#include #include #include #include #include #include #include // for isspace() #include // counts the number of blank lines and // comment lines int main(int argc, char **argv) { int fin; // Take the filename from command line argument if (argc != 2) { fprintf(stderr, "usage: %s filename\n", argv[0]); return EXIT_FAILURE; } // Open the file fin = open(argv[1], O_RDONLY); if (fin < 0 ) { fprintf(stderr, "%s -- ", argv[1]); perror("open failed"); return EXIT_FAILURE; } // set up state machine typedef enum state_t {START, POSSIBLE_COMMENT, COMMENT, OTHER, NUM_STATES} State; typedef enum linetype_t {BLANK_LINE, COMMENT_LINE, OTHER_LINE, NUM_LINE_TYPES} LineType; State fsaState = START; int count[NUM_LINE_TYPES] = { 0, 0, 0}; char c; ssize_t readCnt; while ( 1 ) { readCnt = read(fin, &c, 1); if ( readCnt == 0 ) break; // EOF if ( readCnt == -1 && errno == EINTR ) continue; // try again switch(fsaState) { case START: if ( c == '\n' ) count[BLANK_LINE]++; else if (isspace(c) ); else if (c == '/') fsaState = POSSIBLE_COMMENT; else { fsaState = OTHER; count[OTHER_LINE]++; } break; case POSSIBLE_COMMENT: if ( c == '/' ) { fsaState = COMMENT; count[COMMENT_LINE]++; } else if (c == '\n') { fsaState = START; count[OTHER_LINE]++; } else { fsaState = OTHER; count[OTHER_LINE]++; } break; case COMMENT: if ( c == '\n' ) fsaState = START; break; case OTHER: if ( c == '\n' ) fsaState = START; break; default: fprintf(stderr, "Internal error\n"); return EXIT_FAILURE; } } close(fin); if ( readCnt < 0 ) { perror(NULL); return EXIT_FAILURE; } printf("Blank lines: %d\n", count[BLANK_LINE]); printf("Comment lines: %d\n", count[COMMENT_LINE]); printf("Other lines: %d\n", count[OTHER_LINE]); return EXIT_SUCCESS; }