HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Size improvements for cat reimplementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
sizereimplementationcatforimprovements

Problem

I have written a reimplementation of cat that will be compliant with most scripts, and that is as small and fast as possible. Can anybody suggest some size improvements for it?

#include               /* we need printf, fprintf, FILE,
                         * fopen, fclose and that sort of
                         * stuff */
#include              /* for exit, EXIT_SUCCESS, and
                         * EXIT_FAILURE */

int main(int argc, char *argv[])
{
    FILE *fp;               /* file to cat */
    short int ch;               /* character to print */
    unsigned short int cp;          /* currently printing argv[?] */
    unsigned short int failed = 0;      /* how many failed to print */

    if (argc < 2) {             /* if not enough args act as pipe */
        for (;;) {          /* infinite loop */
            if ((ch = fgetc(stdin)) == EOF) {
                exit(EXIT_SUCCESS);
            } else {
                printf("%c", ch);
            }
        }
    }

    for (cp = 1; cp <= argc - 1; cp++) {    /* for each file in cli args */
        fp = fopen(argv[cp], "r");  /* open the file */

        if(fp == NULL) {
            fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[cp]);
            failed++;       /* increment the number of failed */
            continue;       /* go back to beginning */
        }

        while ((ch = fgetc(fp)) != EOF) {
            printf("%c", ch);
        }

        fclose(fp);         /* close the file */
    }

    exit(failed);               /* exit with the number of files */
}                       /* that failed */


I'm sorry that the indentation is messed up, I use tabs in my code.

In clang version 3.5.0 on Ubuntu the generated binary size is 5200 bytes with these options:

-Oz -fomit-frame-pointer -s


Improvements

I added some more error checking, added -u and - and also wrote a function that writes out a file to avoid repeating myself. Also changed short int to int, printf to putchar, an

Solution

-
Do not repeat yourself. Copying stdin doesn't differ from copying any other file. There is no need to special case stdin as you do at lines 15-21.

-
Avoid naked loops. Every loop does an important job that deserves a name. This is strong enough reason to factor it out as a function:

-
Expect errors

-
fgetc may fail. Once fgetc returns EOF, call feof or ferror to see what has actually happened.

-
printf may fail. Make sure to detect (printf returns -1) and report (analyze errno) errors.

-
Handle options. At least recognize a standalone - as a fake file name referring to stdin.

Context

StackExchange Code Review Q#90302, answer score: 3

Revisions (0)

No revisions yet.