I have a command that displays Ncurses stuffs (initscr
, printw
, addch
, ...). That's okay.
At the end (endwin
), I want to "output" (std::cout << "some string"
) a string to be processed by other command (or maybe redirected to a stream).
I want to do something like this :
my-ncurse-command | any-other-command
my-ncurse-command > some-stream
Problem is : my ncurses display is captured by the pipe or the redirect, not only the final string.
Is there a way to allow that ? Thanks.
CodePudding user response:
Instead of initscr()
, use newterm()
. If you are already using newterm
it's just a matter of supplying a different output stream than stdout
.
initscr()
is equivalent to:
#include <cstdlib>
WINDOW* myinitscr() {
newterm(getenv("TERM"), stdout, stdin);
return stdscr;
}
so
#include <cstdio>
#include <cstdlib>
std::FILE* cursesout{};
WINDOW* myinitscr() {
cursesout = std::fopen("/dev/tty", "w"); // open new stream to your terminal
if(cursesout) newterm(std::getenv("TERM"), cursesout, stdin);
return stdscr;
}
and after endwin()
:
std::fclose(cursesout);
Alternatively, use a smart pointer to not have to std::fclose
the new output stream manually:
#include <cstdio>
#include <cstdlib>
#include <memory>
using FILE_ptr = std::unique_ptr<FILE, decltype(&std::fclose)>;
FILE_ptr cursesout{nullptr, nullptr};
WINDOW* myinitscr() {
cursesout = FILE_ptr(std::fopen("/dev/tty", "w"), &std::fclose);
if(cursesout) newterm(std::getenv("TERM"), cursesout.get(), stdin);
return stdscr;
}
A version not taking the address of a standard library function (which is strictly prohibited) could look like this:
#include <cstdio>
#include <cstdlib>
#include <memory>
using FILE_ptr = std::unique_ptr<FILE, void (*)(FILE*)>;
FILE_ptr cursesout{nullptr, nullptr};
WINDOW* myinitscr() {
cursesout = FILE_ptr(std::fopen("/dev/tty", "w"), [](FILE* fp) {
std::fclose(fp);
});
if(cursesout) newterm(std::getenv("TERM"), cursesout.get(), stdin);
return stdscr;
}