cpp-terminal
cpp-terminal copied to clipboard
`std::cin` doesn't read pipe redirection
Hello,
I'd like to present a use case that I'm currently working on.
I'm trying to create a program that changes the color of some words based on a defined pattern. I'd like to use this program with pipe redirection. Something similar to the following bash script below:
#!/usr/bin/env bash
RED=$(echo -e '\033[1;31m')
CLEAR=$(echo -e '\033[0m')
sed -E "s/\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/${RED}&${CLEAR}/g"
The direct use of this script is using unamed pipe redirection, like (manually edited to illustrate the months written in red color):
$ cat /tmp/test.txt | ./hlight.bash
\33[0;31mJanJan\33[0m 31st
\33[0;31mFebFeb\33[0m 01st
\33[0;31mMayMay\33[0m 15th
I tried making a C++20 program in Linux (Ubuntu 22.04, xterm) with that same behavior and also using pipe redirection, but it seems that program never reads the pipe input because the cpp-terminal library modifies the std::cin.rdbuf
in iostream.cpp and discards the initial stdin
content during the program initialization.
void Term::StreamInitializer::init()
{
if(m_counter++ == 0)
{
std::ios_base::Init();
new(&Term::cout) TOstream(Term::Buffer::Type::FullBuffered, BUFSIZ);
new(&Term::clog) TOstream(Term::Buffer::Type::LineBuffered, BUFSIZ);
new(&Term::cerr) TOstream(Term::Buffer::Type::Unbuffered, 0);
new(&Term::cin) TIstream(Term::Buffer::Type::FullBuffered, BUFSIZ);
std::cin.rdbuf(Term::cin.rdbuf());
}
}
void Term::Private::FileInitializer::init()
{
// ...
#if defined(_WIN32)
// ...
#else
new(&Term::Private::in) InputFileHandler(io_mutex, "/dev/tty");
new(&Term::Private::out) OutputFileHandler(io_mutex, "/dev/tty");
#endif
// ...
}
I believe this is a project decision, but instead of always opening a new /dev/tty
in file.cpp::Term::Private::FileInitializer::init
, it might be useful to reuse the already opened fd = 0
(stdin
) when the program uses pipe redirection. A possible solution could be addind a new ctor Term::Private::FileHandler::FileHandler
that reuses stdin
instead.
To ensure that the program correctly opens a pipe redirection for stdin
, you can verify it by using the isatty
function. So the Term::Private::FileInitializer::init
can be modified to something like:
void Term::Private::FileInitializer::init()
{
// ...
#if defined(_WIN32)
// ...
#else
if (isatty(STDIN_FILENO)) {
new(&Term::Private::in) InputFileHandler(io_mutex, stdin);
} else {
new(&Term::Private::in) InputFileHandler(io_mutex, "/dev/tty");
}
new(&Term::Private::out) OutputFileHandler(io_mutex, "/dev/tty");
#endif
// ...
}
I aim to enable cpp-terminal to maintain the same expected behavior for std::cin
in all scenarios.
Thank you!