2

I was wondering if there was a way to "freeze" an input line in order to separate input and output from each other in c. For instance, my console output is currently something like this:

1 OutputLine1
2 OutputLine2

But I'd like it to be something like this:

1 OutputLine1
2 OutputLine2
3 Enter a Command:

and I'd like for it to be able to change as the program receives a stream of data. So as it runs it would be something like this

1 OutputLine1
2 OutputLine2
3 OutputLine3
4 Enter a Command:

To change to this:

1 OutputLine1
2 OutputLine2
3 OutputLine3
4 OutputLine4
5 Enter a Command:

I'm currently using printf() for all my output, but it doesn't seem like that would work in this situation. Are there any other printing/input libraries I can use?

Thanks in advance!!

Colin Fausnaught
  • 323
  • 3
  • 12
  • nothing standard, you have to roll your own. – Sourav Ghosh Jul 06 '16 at 17:13
  • Well getting input from `stdin` *is* blocking so using any standard input function that reads from `stdin` (like scanf` or `fgets` from `stdin) will in fact "freeze" your program. – Some programmer dude Jul 06 '16 at 17:14
  • Or do you mean that your program is continuously outputting text, and you want to detect when the user attempts to input anything? Then that's operating system dependent, and you need to tell us your operating system or we can't answer this question. – Some programmer dude Jul 06 '16 at 17:15
  • What is "freezing" an input line? Does it mean that your program does not run while waiting for input? Does this mean that what a person types is not displayed? Or something else? – user31264 Jul 06 '16 at 17:16
  • @JoachimPileborg The latter. My program is reading a stream from a serial and continuously getting info from that. I want to be able to send it commands to start streams, stop them, set different parameters, etc. – Colin Fausnaught Jul 06 '16 at 17:16
  • @user31264 I want the program to have a line that is at the bottom of the console, and as it prints output data it can accept input from that bottom line. That's what I mean when freezing, like have all the input print above a line that is designated for input only. – Colin Fausnaught Jul 06 '16 at 17:18
  • 5
    If you are on linux/mac, you could use [ncurses](http://invisible-island.net/ncurses/ncurses-intro.html). I think there exists some kind of curses for windows. If you are using some kind of terminal program and your target is generating the output, you will probably just need to emit some VT100 escapes to erase the bottom line and move the cursor to the beginning of the line after each command. I don't think anybody can really help without knowing more about your system. – evaitl Jul 06 '16 at 17:25
  • 1
    @evaitl I am using linux, I'll take a look at `ncurses` thanks! – Colin Fausnaught Jul 06 '16 at 17:27
  • For those readers on Windows, here is a [previous question](http://stackoverflow.com/questions/15770853/how-to-use-setconsolecursorposition-func) – Weather Vane Jul 06 '16 at 17:34
  • 1
    On POSIX systems (like Linux) you can use `select` to poll if reading from `stdin` (or rather `STDIN_FILENO`) will block or not. If `select` says that `STDIN_FILENO` can be read without blocking, then at least one character are ready to be read, and you can halt your output (possibly buffering it in the background) and read input from the user. – Some programmer dude Jul 06 '16 at 17:48

2 Answers2

1

This will work on most terminals (specifically in an xterm) and I think it is easier than setting up curses:

#include <stdio.h>
#include <unistd.h>
#include <termios.h>

int main(){
    int lineno=1;
    int c;
    struct termios old_tio;
    struct termios new_tio;
    tcgetattr(STDIN_FILENO,&old_tio);
    new_tio=old_tio;
    new_tio.c_lflag &= (~ICANON&~ECHO);
    tcsetattr(STDIN_FILENO,TCSANOW,&new_tio);
    setvbuf(stdout,NULL,_IONBF,0);
    while(1){
        printf("%4d Enter a command: ",lineno);
        c=getchar();
        printf("\033[2K\033[50D%4d Command was %c\n",lineno++, c);
        if(c=='q'){
            break;
        }
    }
    tcsetattr(STDIN_FILENO,TCSANOW,&old_tio);
    return 0;
}

Output looks what OP wanted:

evaitl@evbb ~/se $ ./foo 
   1 Command was a
   2 Command was b
   3 Command was c
   4 Command was d
   5 Command was q
   6 Enter a command: 

Refs: unbuffered IO

vt102 escapes

evaitl
  • 1,365
  • 8
  • 16
0

Assuming your terminal allows VT100 escape codes, you can try this:

printf("OutputLine1\n");
printf("OutputLine2\n");
printf("OutputLine3\n");
printf("Enter a command: ");
// wait for input or more output

// if more output is ready, clear prompt
printf("\033[2K"); // VT100 clearline escape code (^[[2K)
printf("\r");      // Carriage return to return cursor to beginning of line
printf("OutputLine4\n");
// print prompt again
printf("Enter a command: ");
// wait for input or more output
Tim
  • 4,790
  • 4
  • 33
  • 41