## Appendix A Source of the `wc` command ¶

The source file `wc.c`, used to produce sample ASCII tree graph (see ascii tree).

    /* Sample implementation of wc utility. */

    #include <stdlib.h>
    #include <stdio.h>
    #include <stdarg.h>

    typedef unsigned long count_t;  /* Counter type */

    /* Current file counters: chars, words, lines */
    count_t ccount;
    count_t wcount;
    count_t lcount;

    /* Totals counters: chars, words, lines */
    count_t total_ccount = 0;
    count_t total_wcount = 0;
    count_t total_lcount = 0;

    /* Print error message and exit with error status. If PERR is not 0,
       display current errno status. */
    static void
    error_print (int perr, char *fmt, va_list ap)
    {
      vfprintf (stderr, fmt, ap);
      if (perr)
        perror (" ");
      else
        fprintf (stderr, "\n");
      exit (1);
    }

    /* Print error message and exit with error status. */
    static void
    errf (char *fmt, ...)
    {
      va_list ap;

      va_start (ap, fmt);
      error_print (0, fmt, ap);
      va_end (ap);
    }

    /* Print error message followed by errno status and exit
       with error code. */
    static void
    perrf (char *fmt, ...)
    {
      va_list ap;

      va_start (ap, fmt);
      error_print (1, fmt, ap);
      va_end (ap);
    }

    /* Output counters for given file */
    void
    report (char *file, count_t ccount, count_t wcount, count_t lcount)
    {
      printf ("%6lu %6lu %6lu %s\n", lcount, wcount, ccount, file);
    }

    /* Return true if C is a valid word constituent */
    static int
    isword (unsigned char c)
    {
      return isalpha (c);
    }

    /* Increase character and, if necessary, line counters */
    #define COUNT(c)       \
          ccount++;        \
          if ((c) == '\n') \
            lcount++;

    /* Get next word from the input stream. Return 0 on end
       of file or error condition. Return 1 otherwise. */
    int
    getword (FILE *fp)
    {
      int c;
      int word = 0;

      if (feof (fp))
        return 0;

      while ((c = getc (fp)) != EOF)
        {
          if (isword (c))
            {
              wcount++;
              break;
            }
          COUNT (c);
        }

      for (; c != EOF; c = getc (fp))
        {
          COUNT (c);
          if (!isword (c))
            break;
        }

      return c != EOF;
    }

    /* Process file FILE. */
    void
    counter (char *file)
    {
      FILE *fp = fopen (file, "r");

      if (!fp)
        perrf ("cannot open file `%s'", file);

      ccount = wcount = lcount = 0;
      while (getword (fp))
        ;
      fclose (fp);

      report (file, ccount, wcount, lcount);
      total_ccount += ccount;
      total_wcount += wcount;
      total_lcount += lcount;
    }

    int
    main (int argc, char **argv)
    {
      int i;

      if (argc < 2)
        errf ("usage: wc FILE [FILE...]");

      for (i = 1; i < argc; i++)
        counter (argv[i]);

      if (argc > 2)
        report ("total", total_ccount, total_wcount, total_lcount);
      return 0;
    }