I've written this small program in C, which intends to read stdin line-by-line and finally echo each line back to stdout. It is designed to stop reading input when either EOF is detected or a blank line is found. It appears to work alright when reading input from the keyboard, but when I pipe the output of a Windows console command (DIR, SORT and TYPE were all tried), it fails with a "Broken pipe". Why?
Here's the code:
#include <stdio.h> #include <stdlib.h> #define BUFLEN 80 int main(int argc, char *argv[]) { char *s; FILE *fp; fp = fopen("tmpstdin.txt", "w+"); if (fp == NULL) { fputs("File I/O error: Cannot create file.\n", stderr); exit(-1); } s = calloc(BUFLEN, sizeof (*s)); if (s == NULL) { fputs("Memory allocation error.\n", stderr); exit(-1); } while (fgets(s, BUFLEN, stdin) != NULL && *s != '\n') if (fputs(s, fp) == EOF) break; if (ferror(stdin) != 0) { fputs("I/O error on stdin.\n", stderr); exit(-1); } if (ferror(fp) != 0) { fputs("File I/O error: Cannot write to file.\n", stderr); exit(-1); } rewind(fp); while (fgets(s, BUFLEN, fp) != NULL) fputs(s, stdout); if (ferror(fp)) { fputs("File I/O error: Cannot read from file.\n", stderr); exit(-1); } fclose("tmpstdin.txt"); return 0; } Here's the command line used under Windows cmd.exe (assume the above code was compiled to foo.exe):
dir /B | foo.exe
ferror()only when the return value of a function call suggests that there might be something to find, and it's important to distinguish between errors and end-of-file. Although it's not wrong to check at other points, it does needlessly complicate your code.fgets()should not only return a null pointer, but also seterrnoappropriately. It would be appropriate and possibly revealing to useperror()to get a more meaningful diagnostic out of that than the generic ones you are now outputting.