/* Programmer: Greg Perkins Program: cw.c Class: CS 73 C/UNIX Due: TBA This program emulates the functionality of the 'wc' UNIX command. For a more complete description, type 'man wc' from the system shell. The programs results are undefined when attempting to count the words in an executable/binary file. */ #include #include /* FUNCTION PROTOTYPES */ int arg_parser (int arg_total, char new_argv[], char *old_argv[]); /* PRE: arg_total - is the number of command-line arguments new_argv[] - vector to contain valid switches in order given by user old_arv[] - vector of command-line arguments passed to main() POST: fctval - number of switches contained on command-line new_argv[] - contains switches in the order given by user */ int file_locator (int arg_total, char *old_argv[]); /* PRE: arg_total - is the number of command-line arguments old_argv[] - vector to command-line arguments passed to main() POST: fctval - index/location of first filename in argv[] fctval = 0 if there were no filenames specified on the command line */ void std_count (int num_args, char arg_order[]); /* PRE: num_args - the number of command-line switches {default is 3} arg_order[] - vector containing command-line switches is user given order POST: function counts the chars, bytes, lines, words provided in standard input stream then passes these values to count_display() */ void file_count (int start, int stop, int num_args, char cmd_argv[], char *old_argv[]); /* PRE: start - position of first filename in old_argv[]{0,if no files given} stop - total number of arguments in old_argv[] num_args - number of switches in cmd_argv[] cmd_argv[] - vector containing switches in proper order old_argv[] - vector of command-line arguments passed to main() POST: function counts the chars, bytes, lines, words in specified files then passes these values to count_display() */ void count_display (int lines, int words, int bytes, int arg_num, char switch_argv[], char filename[]); /* PRE: lines - number of lines counted in file or stdin words - number of words counted in file or stdin bytes - number of bytes/chars counted in file or stdin arg_num - number of switches in switch_argv[] switch_argv[] - vector containing switches in proper order filename[] - filename currently being counted POST: function displays chars, bytes, lines, words in the order specified in switch_argv[], then displays filename */ /* FUNCTION DEFINITIONS */ int main(int argc, char *argv[]) { int i, j; /* loop variables */ int num_cmds = 0; /* number of valid switches on cmd-line */ int start_file = 0; /* array position of first filenames on cmd-line */ char cmd_order[4]; /* array holding cmd-line switches in order given */ num_cmds = arg_parser (argc, cmd_order, argv); if (num_cmds == 0) /* if NO switches were specified */ { num_cmds = 3; /* set the 3 default switches */ cmd_order[0] = 'l'; cmd_order[1] = 'w'; cmd_order[2] = 'c'; } start_file = file_locator (argc, argv); if (start_file == 0) std_count (num_cmds, cmd_order); else file_count (start_file, argc, num_cmds, cmd_order, argv); return (0); } /********************** arg_parser ************************/ int arg_parser (int arg_total, char new_argv[], char *old_argv[]) { int i, j, k; /* loop variables */ int num_args = 0; /* new_argv[] position holder */ int arg_used; /* boolean var to control repeating args */ char *arg; /* controlling arg pointer */ /* Check each command-line argument */ for (i = 1, arg = old_argv[1]; i < arg_total; arg = old_argv[++i]) { if (arg[0] != '-') /* arg[] is not a command line switch */ break; for (k = 1; arg[k] != '\0'; k++) { arg_used = 0; /* assume that switch has not been used */ for (j = 0; j < num_args; j++) /* check new_arg for repeats */ if (new_argv[j] == arg[k]) arg_used = 1; if (arg_used) continue; /* skip repeated args */ switch (arg[k]) /* put args in order called in new_argv */ { case 'l': case 'c': case 'w': case 'm': new_argv[num_args++] = arg[k]; break; default : printf("cw: illegal option -- %c\n", arg[k]); printf("usage: cw [-clmw] [file ...]\n"); exit (1); /* user entered invalid switch */ break; } /* end switch */ } /* end inside 'for' */ } /* end outside 'for' */ return (num_args); } /* end function */ /********************** file_locator ************************/ int file_locator (int arg_total, char *old_argv[]) { int i; char *file_arg; for (i = 1, file_arg = old_argv[1];i < arg_total;file_arg = old_argv[++i]) { if (file_arg[0] != '-') /* if a filename is found */ return (i); /* return its position in argv[] */ } return (0); /* if no filenames are specified */ } /********************** std_count ************************/ void std_count (int num_args, char arg_order[]) { int i; int byte = 0, line = 0, word = 0; /* counters */ int curr_char, prev_char = -1; while ((curr_char = getchar()) != EOF) { byte++; if (curr_char == '\n') line++; if (prev_char != -1) if ((isspace(curr_char)) && (!isspace(prev_char))) word++; prev_char = curr_char; } count_display (line, word, byte, num_args, arg_order, ""); } /********************** file_count ************************/ void file_count(int start, int stop, int num_args, char cmd_argv[], char *old_argv[]) { int i, j, k; /* loop variables */ int curr_char, prev_char; int byte, line, word; int byte_total = 0, line_total = 0, word_total = 0; FILE *input; for (i = start; i < stop; i++) { input = fopen (old_argv[i], "r"); if (input != NULL) { byte = line = word = 0; /* init counters for each file */ prev_char = -1; /* init first char for each file */ while ((curr_char = fgetc(input)) != EOF) { byte++; byte_total++; if (curr_char == '\n') { line++; line_total++; } if (prev_char != -1) if ((isspace(curr_char)) && (!isspace(prev_char))) { word++; word_total++; } prev_char = curr_char; } /* end while */ if (fclose(input) != 0) printf("cw: %s : Error closing file.\n", old_argv[i]); count_display (line, word, byte, num_args, cmd_argv, old_argv[i]); } /* end if - begin else */ else printf("cw: %s : No such file or directory\n", old_argv[i]); } /* end for loop */ if ((stop - 1) > start) /* If more than one file, print totals */ count_display (line_total, word_total, byte_total, num_args, cmd_argv, "total"); } /* end function */ /********************** count_display ************************/ void count_display (int lines, int words, int bytes, int arg_num, char switch_argv[], char filename[]) { int i; for (i = 0; i < arg_num; i++) switch (switch_argv[i]) { case 'l': printf(" %9d", lines); break; case 'w': printf(" %9d", words); break; case 'c': case 'm': printf(" %9d", bytes); break; } printf(" %s\n", filename); }