Skip to content

Instantly share code, notes, and snippets.

@jeremyheiler
Created September 4, 2013 05:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyheiler/6432956 to your computer and use it in GitHub Desktop.
Save jeremyheiler/6432956 to your computer and use it in GitHub Desktop.
Print the contents of a file to stdout.
#include <stdio.h>
#include <errno.h>
int main(int argc, char **argv)
{
if (argc == 1) return 0;
if (argc == 2) {
char *filename = argv[1];
FILE *fp = fopen(filename, "r");
if (!fp) {
perror(NULL);
return errno;
}
char buf[11];
int read;
while ((read = fread(buf, sizeof(char), 10, fp)) != 0) {
buf[read] = '\0';
printf(buf);
}
if (fp && fclose(fp) == EOF) {
perror(NULL);
return errno;
}
}
return 0;
}
@jeremy-w
Copy link

jeremy-w commented Sep 4, 2013

Rather than nesting the entire body, you could test != 2 and bail early.

You probably want a non-zero exit code if there are no arguments. I'm used to sysexits.h defining EX_USAGE, but I don't know if anyone actually uses that but me.

fread actually seems to return a size_t; that's unsigned and could be (and likely is) larger than int, though I suppose that's not so much a worry with fixing the read size at 10 bytes. Still good practice to keep types and integer widths and signedness in mind.

You're repeating the size of buf in a fragile way. Use sizeof(buf) - 1 instead of 10. sizeof(char) is also guaranteed to be 1, but it'd be clearer to just do sizeof(*buf), since that's really what you're reading: "fill up buf less 1 with the stuff that buf holds". Doing this completely independently of the size of *buf would require you to read (sizeof(buf)/sizeof(*buf) - 1) * sizeof(*buf) items, which admittedly is a bit involved. :)

You're not testing whether that 0 return from fread is due to EOF or an actual error. Manpage advises feof and ferror to distinguish the cause.

<stdlib.h> actually declares EXIT_SUCCESS and EXIT_FAILURE, which I think could theoretically be defined to values other than 0 and 1.

@jeremy-w
Copy link

jeremy-w commented Sep 4, 2013

Oh, and printf interprets that first arg as a format string, so if the file contains something like %d, you are in funland. Either use fputs or printf("%s", buf).

(Note that puts appends a newline after each call, unlike fputs, just to throw you. So puts(str) is actually basically fputs(str, stdout); putchar('\n');.)

@jeremy-w
Copy link

jeremy-w commented Sep 4, 2013

Also: Once you have file reading, you can actually copy stdin to stdout by telling it to read from /dev/fd/0 or /dev/stdin. Fake device files are fun! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment