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 );
}
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