#include #include #include #include #include #include #define OPTLIST "clLw" // TRACK WHICH THINGS WE SHOULD DISPLAY. bool display_bytes = false; bool display_lines = false; bool display_words = false; bool display_longest = false; // THINGS WE SHOULD COUNT typedef struct { int bytes; int lines; int longest; int words; } COUNTS; // ------------------------------------------------------------------------ void report_counts(COUNTS what, char *filename) { // JUST DISPLAY THE REQUESTED COUNTS if(display_lines) { printf("%8d", what.lines); } if(display_words) { printf("%8d", what.words); } if(display_bytes) { printf("%8d", what.bytes); } if(display_longest) { printf("%8d", what.longest); } // ONLY DISPLAY THE FILENAME IF IT'S NOT NULL if(filename != NULL) { printf("\t\t%s", filename); } printf("\n"); } void counter(FILE *fp, char *filename, COUNTS *totals) { COUNTS this = { 0, 0, 0, 0 }; char line[BUFSIZ]; // FOREACH LINE READ FROM THE FILE-POINTER.... while( fgets(line, sizeof line, fp) != NULL) { int len = 0; bool inside_word = false; char *s = line; ++this.lines; // UNTIL WE HAVE REACHED THE END OF THIS LINE.... while(*s) { ++this.bytes; // FOR THE LONGEST LINE, TABS ARE EXPANDED TO A MULTIPLE OF 8 SPACES if(*s == '\t') { len = (len+8) / 8 * 8; } else if(*s != '\n') { ++len; } // KEP TRACK OF WHETHER WE'RE INSIDE A WORD, OR NOT if(inside_word && isspace(*s)) { inside_word = false; } else if(!inside_word && !isspace(*s)) { ++this.words; inside_word = true; } // 'WALK' ALONG THE LINE ++s; } // SEE IF WE'VE FOUND A NEW LONGEST LINE if(this.longest < len) { this.longest = len; } } report_counts(this, filename); // UPDATE OUR GLOBAL TOTALS AND LONGEST LINE totals->bytes += this.bytes; totals->lines += this.lines; totals->words += this.words; if(totals->longest < this.longest) totals->longest = this.longest; } // ------------------------------------------------------------------------ // PROVIDE A 'USAGE' MESSAGE IF AN INVALID SWITCH PROVIDED void usage(char *argv0) { fprintf(stderr, "Usage: %s [-clLw] [file ...]\n", argv0); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { COUNTS totals = { 0, 0, 0, 0 }; int opt; // DETERMINE WHICH, IF ANY, COMMAND-LINE SWITCHES WERE PROVIDED while( (opt = getopt(argc, argv, OPTLIST)) != -1) { switch (opt) { case 'c' : display_bytes = true; break; case 'l' : display_lines = true; break; case 'L' : display_longest = true; break; case 'w' : display_words = true; break; // PROVIDE A 'USAGE' MESSAGE IF AN INVALID SWITCH PROVIDED default : usage(argv[0]); break; } } // IF NO OPTIONS PROVIDED, USE THESE DEFAULTS: if(display_bytes == false && display_words == false && display_lines == false && display_longest == false) { display_bytes = true; display_lines = true; display_words = true; } // IF NO ARGUMENTS PROVIDED, READ FROM stdin (e.g. KEYBOARD, PIPE, REDIRECTION) if(optind == argc) { counter(stdin, NULL, &totals); } else { // ARGUMENTS PROVIDED, ITERATE OVER EACH TREATING IT AS A FILENAME for(int a=optind ; a optind) report_counts(totals, "total"); } exit(EXIT_SUCCESS); return 0; }