There are typically three ways to make a commandline program read a file. The most common is probably to just append the filename as an argument to your program.
programname filename.ext
But there are two other ways to do it:
First a pipe into the program:
cat filename.ext | programname
and second a redirected stdin:
programname < filename.ext
But have you ever wondered how you make your c program work with all three input possibilities? I know I did. Turns out it is not that difficult.
The hard part is actually just knowing wether your program got a input from the outside, or if it should open the file itself. Apart from that, it is just plain old fopen/fgets. This means you can write a (dumbed down) version of cat in about 30 lines of code.
First the includes:
#include <unistd.h>
#include <stdio.h>
unistd is allows us to use isatty (more and that in a while) and stdio allows to work with files. That is all we use.
The program is then split into two parts:
FILE *read_this;
if (isatty(fileno(stdin))) {
if(argc > 1) {
printf("filename: %s\n", argv[1]);
read_this = fopen(argv[1], "r");
} else {
puts("give me a file! Either stdin, a pipe or a filename after programname");
return 1;
}
}
else {
read_this = stdin;
}
which is responsible for giving us the correct file to read. The function isatty returns a bool to indicate wether a given filenumber represents a tty. If it does, we know it is not a file - and can thus proceed to try to read a filename from the program arguments. If it is not a tty, it can still be either a redirected stdin (the < version) or a pipe from another program/process (the | version) - but thankfully these work in exactly the same way (for our purposes anyway). After this block of code the read_this variable will be a file pointer (or null).
We then check to see if we got a valid file pointer:
if (read_this == NULL) {
fprintf(stderr, "Can't open input file\n");
return 1;
}
This will only happen if we try to open a file ourselves - since stdin will always be a valid file pointer.
Finally we can read the content of the file, and print it to the screen (or rather stdout - it could be piped ;-) ... )
char buf[BUFSIZ];
while(NULL != fgets(buf, sizeof buf, read_this)) {
printf("%s", buf);
}
return 0;
That's about it. Go see the complete source code at this gist