1

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.

1 Answer 1

2

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;
}
2
  • Both initscr and newterm updates the stdscr global variable. So it's a drop in replacement (newterm on stdin and /dev/tty VS initscr) ! Thank you, that's perfect.
    – Neekobus
    1 hour ago
  • @Neekobus Glad it helped! You're welcome!
    – Ted Lyngmo
    56 mins ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.