C++ Logo

sg16

Advanced search

Re: [SG16] [isocpp-lib-ext] Review of P2093R2: Formatted output

From: Tom Honermann <tom_at_[hidden]>
Date: Tue, 5 Jan 2021 13:51:29 -0500
On 12/5/20 5:16 PM, Tom Honermann via SG16 wrote:
> On 12/5/20 4:31 PM, Jens Maurer wrote:
>> On 05/12/2020 22.16, Tom Honermann wrote:
>>> On 11/28/20 11:33 AM, Victor Zverovich wrote:
>>>>> And then there is the facility of converting the C++ literal encoding to the console encoding, if necessary. Again, this should be a separate facility, preferably offering a generic transcoding facility that can be specialized for the console-only use case.
>>>> While I agree that such a transcoding facility would be useful I think it is out of scope of the current paper. The latter requires only minimal transcoding facilities for the Unicode case and only on some platforms where dedicated system APIs exist.
>>> I agree that distinct interfaces should be provided for each of these concerns, but I also think each can be pursued separately and need not hold up the proposed feature. We can always re-specify the proposed behavior in terms of new interfaces via as-if in the future.
>> Let me disagree here. It took years for to_chars (the underlying
>> elementary operation) to arrive after std::to_string was standardized.
>>
>> I have no objection to providing high-level facilities in C++,
>> but I want the option to ignore those high-level facilities
>> if need be. Apparently, there is an appetite to differentiate
>> "writing to the console" vs. "writing to a file", and that
>> appears to be a useful low-level query to have.
>
> I agree that it is useful to have. But it is also functionality that
> has been readily available for most systems for a long time now and
> there hasn't been a push to standardize it in C or C++ thus far. I'm
> not opposed to adding it at all, I just don't want the lack of it to
> hold up Victor's proposal. At any rate, here is a fairly portable
> (untested) implementation (with lax error handling) for C style
> streams (the Windows implementation would be better implemented using
> whatever Win32 features _isatty() uses).
>
> #if defined(_XOPEN_SOURCE)
> #include <stdio.h>
> #include <unistd.h>
> #elif defined(_MSC_VER)
> #include <io.h>
> #endif
>
> bool is_attached_to_terminal(FILE* fp) {
> #if defined(_XOPEN_SOURCE)
> return isatty(fileno(fp));
> #elif defined(_MSC_VER)
> return _isatty(_fileno(fp));
> #endif
> }
>
While playing around with the console encoding, I discovered that the
MSVC provided _isatty() returns true for any character device, not just
a console. From the documentation
<https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/isatty?view=msvc-160>:

> The *_isatty* function determines whether /fd/ is associated with a
character device (a terminal, console, printer, or serial port).

Here is code that does validate whether the standard file streams are
directed to a Windows console:

    #include <windows.h>
    #include <io.h>
    #include <stdio.h>
    #include <iostream>
    #include <string>

    bool is_console(FILE *fp) {
         if (! fp) {
             return false;
         }
         int fd = _fileno(fp);
         if (fd < 0) {
             return false;
         }
         HANDLE h = (HANDLE)_get_osfhandle(fd);
         if (h == INVALID_HANDLE_VALUE) {
             return false;
         }
         DWORD mode;
         BOOL result;
         result = GetConsoleMode(h, &mode);
         if (! result) {
             return false;
         }
         return true;
    }

    struct stream_desc {
         std::string name;
         FILE *fp;
    };

    int main() {
         stream_desc streams[] = {
             { "stdin", stdin },
         { "stdout", stdout },
         { "stderr", stderr }
         };
         for (auto sd : streams) {
             if (is_console(sd.fp)) {
                 std::cout << sd.name << ": console\n";
             } else {
                 std::cout << sd.name << ": not a console\n";
             }
         }
    }

When saved as is-console.cpp and compiled with cl /Feis-console.exe
/EHsc is-console.cpp:

>is-console
    stdin: console
    stdout: console
    stderr: console

>echo. | is-console
    stdin: not a console
    stdout: console
    stderr: console

>is-console | findstr .
    stdin: console
    stdout: not a console
    stderr: console

>is-console 2>nul
    stdin: console
    stdout: console
    stderr: not a console

>is-console 2>&1
    stdin: console
    stdout: console
    stderr: console

>is-console >&2
    stdin: console
    stdout: console
    stderr: console

>echo. | is-console 2>&1 | findstr .
    stdin: not a console
    stdout: not a console
    stderr: not a console

Tom.


Received on 2021-01-05 12:51:32