4

I'd like to write a simple program using ncurses for displaying some data. I would then like for the program to write to stdout in such a way that I can then use a pipe (|) on the command line to pipe some data out.

My current attempt doesn't work. I can see the "GOT HERE"'s in a file using '>', but there's a whole bunch of other stuff. The program also exits immediately.

#include <stdio.h>
#include <ncurses.h>


int main(int _argc, char ** _argv)
{
    initscr();          /* Start curses mode          */

    printw("Hello World !!!");  /* Print Hello World          */

    refresh();          /* Print it on to the real screen */

    getch();            /* Wait for user input */

    printf("GOT HERE");

    endwin();           /* End curses mode        */

    printf("GOT HERE");

    return 0;
}

This is the final output using >

^[[?1049h^[[1;29r^[(B^[[m^[[4l^[[?7h^[[H^[[2JHello World !!!^MGOT HERE^[[29;1H^[[?1049l^M^[[?1l^[>GOT HERE

Is it possible to use stdout through a pipeline and ncurses at the same time?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
lowq
  • 628
  • 6
  • 18
  • It is not so easy, because ncurses uses stdout by default. All pseudo-graphics is done using special symbols (`^[`). You can try stderr for text output: `fprintf(stderr,....)` in program and `./a.out 2>file` for redirects. – osgx Dec 03 '11 at 23:29
  • What are you really trying to do? Having an interactive program in a pipeline is unusual to begin with. It's a whole lot easier to write to a file or FIFO and make some minor command line changes. – Duck Dec 03 '11 at 23:50
  • Yeah. What osgx said. Might want to combine his approach with piping through the 'tee' command, so that stdout goes to the screen as well as to a specified file... that could be useful for debugging purposes. If you use `a.out 2> named_pipe` (where named_pipe is a named pipe, naturally), then `cat named_pipe` from a different terminal, you'll be able to see both stdout and stderr show up at the same time. – Barton Chittenden Dec 03 '11 at 23:58

2 Answers2

11

This is 5 years old now and you've probably moved on, but this was the top of my search results so I thought I'd add the solution I found. After a lot of messing about with trying to get pipes to work in code like bash example above, I finally found someone that hinted in the right direction with the newterm command. The only trick is to open a new tty and to use newterm instead of initscr:

#include  <stdio.h>
#include <ncurses.h>

int main(int argc, char ** argv) {

  FILE *f = fopen("/dev/tty", "r+");
  SCREEN *screen = newterm(NULL, f, f);
  set_term(screen);

  //this goes to stdout
  fprintf(stdout, "hello\n");
  //this goes to the console
  fprintf(stderr, "some error\n");
  //this goes to display
  mvprintw(0, 0, "hello ncurses");
  refresh();
  getch();
  endwin();

  return 0;
}

With this you can pipe stdout and stderr wherever you want but have an ncurses session. I'm not sure how portable it is or if there are any other catches, just glad to find a solution that worked.

flukus
  • 996
  • 8
  • 18
  • 3
    Nice work. It has been five years (and a college education). I had quite a bit of learning to do. – lowq Jul 06 '17 at 17:51
6

By default, curses writes to the standard output, which is where your pipe goes. But there are two different initialization functions for curses: initscr and newterm. The latter lets you do what was asked, like this:

#include <stdio.h>
#include <ncurses.h>


int main(int _argc, char ** _argv)
{
    newterm(NULL, stderr, stdin);          /* Start curses mode          */    
    printw("Hello World !!!");  /* Print Hello World          */    
    refresh();          /* Print it on to the real screen */    
    getch();            /* Wait for user input */    
    printf("GOT HERE");    
    endwin();           /* End curses mode        */    
    printf("GOT HERE");    
    return 0;
}

Further reading: manual page for newterm and initscr.

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105