C++ Logo

std-proposals

Advanced search

[std-proposals] A standard way to redirect all standard output

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Mon, 13 Mar 2023 15:55:44 +0000
I'm currently combining two programs into one program, so that they
both run as one process.

I have to capture all the output from one of the programs, and I've
had to do so in 3 ways:
(1) Create a new 'streambuf' type to assign to cout, cerr, clog
(2) Use the GNU-gcc function fopencookie to change the FILE* for stdout, stderr
(3) Provide my own implementation of the POSIX function "write" which
checks if the file descriptor is 1 or 2

I was thinking it would be nice if the Standard Library allowed us to
redirect all standard output (destined for stdout + stderr), if we
were to define these two functions:

        void stdout_redirect(char const *buf, size_t const len);
        void stderr_redirect(char const *buf, size_t const len);

This would effect all invocations of printf, puts, fprintf(stderr),
fwrite(stdout), cout <<, cerr <<, clog <<.

Finally the Standard would have a paragraph saying that this
redirection should be implemented by the compiler vendor for all
platform-specific functions that write to stdout and stderr (for
example 'write(fd = 1)' on POSIX systems).

Here's the code I had to write in my own program to achieve all of this:

    ssize_t writer(void*, char const *const buffer, size_t const size)
    {
        if ( (0u == size) || (nullptr == buffer) ) return 0;

        // For example send output to text box in GUI

        return size;
    }

    class streambuf_redirect : public std::streambuf {

        using std::streambuf::streambuf;

        virtual std::streamsize xsputn(char const *const s,
std::streamsize const count)
        {
            return writer(nullptr,s,count);
        }
    };

extern "C" ssize_t write(int const fd, void const *const buf, size_t
const count) // This takes the place of the function provided by
glibc
{
    static ssize_t (*const p)(int,void const*,size_t) =
reinterpret_cast<ssize_t(*)(int,void const*,size_t)>(
::dlsym(RTLD_NEXT, "write") );

    if ( (fd < 1) || (fd > 2) ) return p(fd,buf,count); // 1 =
stdout, 2 = stderr

    return writer(nullptr, static_cast<char const*>(buf), count);
}

void RedirectAllOutput(void)
{
    cookie_io_functions_t g_funcptrs = {}; // all nullptr

    g_funcptrs.write = writer;

    FILE *const fp = fopencookie(nullptr, "w", g_funcptrs);

    assert( nullptr != fp );

    setvbuf(fp, nullptr, _IOLBF, 0); // line buffered

    stdout = stderr = fp;

    static streambuf_redirect buf;

    std::cout.rdbuf( &buf );
    std::clog.rdbuf( &buf );
    std::cerr.rdbuf( &buf );
}

Received on 2023-03-13 15:55:56