wc.cc


      //  $Id$
      /*
       *  Does the same thing as the Unix wc command.
       *
       *  Functions
       *
       *    processFile()   Count characters, lines, etc. from one file.
       *    printResults()  Print one line of results.
       *    main()          Process command line options and file names.
       *
       *  Author: C. Vickery
       *
       *  Revision History
       *
       *    $Log$
       */
      #include <getopt.h>
      #include <stdio.h>
      #include <string.h>
      #include <unistd.h>
      
      //  Global Constants
      //  ------------------------------------------------------------------
      const struct option long_options[] =
      {
        { "chars",            0, 0, 'c' },
        { "lines",            0, 0, 'l' },
        { "words",            0, 0, 'w' },
        { "max-line-length",  0, 0, 'L' },
        { "help",             0, 0, '?' },
        { 0,                  0, 0, 0   },
        
      };
      const char * const short_options = "clwL?";
      
      #define COUNT_CHARS 1
      #define COUNT_WORDS 2
      #define COUNT_LINES 4
      #define COUNT_MAX   8
      
      //  Global Variables
      //  ------------------------------------------------------------------
      
      //  Counters for totals across input files.
      int totalChars = 0, totalWords = 0, totalLines = 0;
      int totalMaxLine = 0;
      
      //  Counters for individual files.
      int numChars = 0, numWords = 0, numLines = 0, maxLine = 0;
      
      //  processFile()
      //  ------------------------------------------------------------------
      /*
       *    Counts chars, words, lines, and max line length for a single
       *    file.
       *
       *    Arguments
       *
       *      file - an input stream open for reading
       *
       *    Global Variables
       *
       *      Initializes and updates counters for an individual file
       *      (numChars, numWords, numLines, maxLine).
       */
      void
      processFile( FILE * file )
      {
        char  buf[ 8192 ];
      
        numChars = numWords = numLines = maxLine = 0;
        while ( 0 != fgets( buf, sizeof( buf ), file ) )
        {
          numLines++;
          int s = strlen( buf );
          numChars += s;
          if ( --s > maxLine )
          {
            maxLine = s;
          }
          if ( 0 != strtok( buf, " \t\n\r" ) )
          {
            numWords++;
          }
          while ( 0 != strtok( 0, " \t\n\r" ) )
          {
            numWords++;
          }
        }
      }
      
      
      //  printResult()
      //  ------------------------------------------------------------------
      /*
       *    Prints one line, the counts for either one file, or for the
       *    totals across files.
       *
       *    Arguments
       *
       *      options         - which counter(s) to print
       *      cl, cw, cc, cm  - count of lines, words, chars, max
       *      name            - string identifying the file or "total"
       */
      void
      printResult(  int options, 
                    int cl, int cw, int cc, int cm, 
                    const char *name )
      {
        if ( options & COUNT_LINES )
        {
          printf( "%7d ", cl );
        }
        if ( options & COUNT_WORDS )
        {
          printf( "%7d ", cw );
        }
        if ( options & COUNT_CHARS )
        {
          printf( "%7d ", cc );
        }
        if ( options & COUNT_MAX )
        {
          printf( "%7d ", cm );
        }
        printf( "%s\n", name );
      }
      
      
      //  main()
      //  ------------------------------------------------------------------
      /*
       *    Processes command line arguments and all files named on the
       *    command line, counting bytes, words, and lines for each input
       *    file.
       *
       *    Arguments:
       *
       *      argc, argv  - command line options and file names.
       *      envp        - environment (not used).
       */
      int
      main( int argc, char *argv[], char *envp[] )
      {
        //  Process command line options
        int         options = 0x00;
        extern int  optind;
        int         c;
      
        while ( -1 != ( c = getopt_long(  argc, argv, short_options,
                                          long_options, 0 ) ) )
        {
          switch ( c )
          {
            case 'c' :
              options |= COUNT_CHARS;
              break;
            case 'w' :
              options |= COUNT_WORDS;
              break;
            case 'l' :
              options |= COUNT_LINES;
              break;
            case 'L' :
              options |= COUNT_MAX;
              break;
            default:
              fprintf( stderr, "Usage: wc [-cwlL] [file ...]\n" );
              exit( 1 );
          }
        }
        if ( 0 == options )
        {
          options = COUNT_CHARS | COUNT_WORDS | COUNT_LINES;
        }
      
        //  Process stdin if no file names
      
        if ( optind >= argc )
        {
          processFile( stdin );
          printResult( options, numLines, numWords, numChars, maxLine, "" );
          exit( 0 );
        }
      
        //  Process each file named on the command line
        int numFiles = 0;
        for (int i = optind; i < argc; i++ )
        {
          FILE *file = fopen( argv[i], "r" );
          if ( 0 == file )
          {
            perror( argv[i] );
            continue;
          }
          numFiles++;
          processFile( file );
          printResult(  options, 
                        numLines, numWords, numChars, maxLine,
                        argv[ i ] );
      
          //  Accumulate overall sums
          totalLines += numLines;
          totalChars += numChars;
          totalWords += numWords;
          if ( maxLine > totalMaxLine )
          {
            totalMaxLine = maxLine;
          }
        }
      
        //  Print summary line if more than one file processed.
        if ( numFiles > 1 )
        {
          printResult(  options,
                        totalLines, totalWords, totalChars, totalMaxLine,
                        "total" );
        }
      }