I have read previous questions regarding this problem too. fflush(stdin) does not work in this scenario for me. I want my program to read from a piped stdin and continue from keyboard input in the middle.
int main()
{
int userin = 3;
read_input();
userin = print_menu();
userin = parse_input(userin);
return 0;
}
I want to read data from a file which is passed to the program as a pipied stding like
int read_input(){
char line[200];
char word[MAX_STRING+1];
int line_number = 0;
while(fgets(line, sizeof(line), stdin) != NULL ){
//do something
printf("%s",line);
line_number++;
}
}
Now read_input must finish reading from the piped input. 'print_menu' must continue reading from the keyboard.
int print_menu()
{
int userinput;
char c;
char num[4];
while((c=getchar()) != '\n' && c != EOF && c != '\r');
printf("\n1. Choice 1 \n");
printf("2. Choice 2\n");
printf("3. Exit\n");
printf("Enter your choice (1-3): ");
/* scanf("%d", &userinput); */
/* fgets(num,80,stdin); */
scanf("%s", num);
userinput = atoi(num);
return userinput;
}
int parse_input(int userinput)
{
char num[4];
while( userinput > 3 || userinput < 1 ){
printf("Sorry, that is not a valid option\n");
printf("Enter your choice (1-3): ");
scanf("%s", num);
userinput = atoi(num);
/* scanf("%d", &userinput); */
/* while( (c = getchar()) == '\n'); */
}
return userinput;
}
My output is a infinite loop of
Enter your choice (1-3): Sorry, that is not a valid option
When I remove read_input method and piped stdin program works fine. I cannot figure out a get around for this, does someone has a idea..
Pipes come (controlled by the shell) normally on file-descriptor 0
, which is the standard input. You can use dup2()
to "move" that to a different file descriptor, and use freopen()
to continue reading from that. You can also open the /dev/tty
device (or whatever the tty
program knows about) and make that your standard input.
The dialog program does this for the --gauge
(progress bar) option. The reason why it does this is because dialog is a curses application (which by default uses the standard input and output). The actual pipe file-descriptor is as well optional, so quoting from its manual page gives some hints:
--input-fd fd
Read keyboard input from the given file descriptor. Most dialog scripts read from the standard input, but the gauge widget reads a pipe (which is always standard input). Some configurations do not work properly when dialog tries to reopen the terminal. Use this option (with appropriate juggling of file-descriptors) if your script must work in that type of environment.
The logic which implements this is in the util.c
, from the init_dialog
function. Here is the main part of that, to give an idea how the functions are used:
dialog_state.pipe_input = stdin;
if (fileno(input) != fileno(stdin)) {
if ((fd1 = dup(fileno(input))) >= 0
&& (fd2 = dup(fileno(stdin))) >= 0) {
(void) dup2(fileno(input), fileno(stdin));
dialog_state.pipe_input = fdopen(fd2, "r");
if (fileno(stdin) != 0) /* some functions may read fd #0 */
(void) dup2(fileno(stdin), 0);
} else {
dlg_exiterr("cannot open tty-input");
}
close(fd1);
} else if (!isatty(fileno(stdin))) {
if ((fd1 = open_terminal(&device, O_RDONLY)) >= 0) {
if ((fd2 = dup(fileno(stdin))) >= 0) {
dialog_state.pipe_input = fdopen(fd2, "r");
if (freopen(device, "r", stdin) == 0)
dlg_exiterr("cannot open tty-input");
if (fileno(stdin) != 0) /* some functions may read fd #0 */
(void) dup2(fileno(stdin), 0);
}
close(fd1);
}
free(device);
}
I had a nearly-identical situation with a program I wrote to read binary data from stdin
(piped in from some other program's stdout
), but I wanted to add keyboard commands (via raw terminal support). Obviously reading piped data and the keyboard simultaneously led to some weird results.
Here's my code, working and tested:
FILE * fp; int fd; fd = dup(fileno(stdin)); fp = fdopen(fd, "r"); (void) freopen("/dev/tty", "r", stdin);
Now, my program reads from fp (a FILE*
object) for its binary data while reading stdin
(now associated with "/dev/tty"
) for keystrokes.
Note that I discard the return value from freopen
(a FILE*
object) since I can refer to it via stdin
if needed. My experience is that there is no need to close()
or fclose()
a standard text stream. I fclose(fp)
at the end of reading the binary data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With