0

I am writing an application which first receives data from a unix pipeline, and then prompting the user for input. What I cannot seem to figure out is why the input from the pipeline does not seem to close properly before prompting the user for input. It feels like I'm missing something very elementary here.

I have tried all examples for flushing stdin presented here without success. This also seems potentially relevant, but I have not managed to extract any relevant answers.

#include <stdio.h>
#include <stdlib.h>

#define BUFSZ 1024

int main(void) {

    char *buf = calloc(BUFSZ, sizeof(char));

    while(fgets(buf, BUFSZ, stdin)) { printf("Pipe input: %s", buf); }

    printf("Enter input: ");
    fgets(buf, BUFSZ, stdin);
    printf("User input: %s", buf);

    free(buf);
    return 0;
}

Example usage and output:

$ cat testdata2 | ./a.out
Pipe input: testdata testdata
Pipe input: testdata testdata2
Pipe input: testdata testdata3
Pipe input: testdata testdata4
Pipe input: testdata testdata5
Pipe input: testdata testdata6
Pipe input: testdata testdata7
Enter input: User input: testdata testdata7
$

How can it be that the second fgets() (intended for keyboard input) never touches the buffer?

This MCVE has been compiled tested on OSX and Linux with identical results.

Community
  • 1
  • 1
B Nauclér
  • 37
  • 2
  • 9

1 Answers1

6

If stdin is a pipe, then stdin is not the terminal. When you get to the end of the pipe, that's it! That's the end of stdin. You're expecting some kind of magical transformation where stdin stops being the pipe and starts being something else. Don't expect that. It's still the pipe. And EOF has occurred. For pipes, EOF is a permanent condition. Once you've hit EOF, you won't ever get anything more.

Do check the return value of fgets every time. You'll see that the last one returns null, because it's at EOF.

Programs that want to read piped stdin and also get keyboard input must open the terminal separately, as in FILE *tty = fopen("/dev/tty", "r");