home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / gnu / textutils-1.11-src.lha / textutils-1.11 / src / wc.c < prev   
Encoding:
C/C++ Source or Header  |  1994-11-13  |  6.2 KB  |  301 lines

  1. /* wc - print the number of bytes, words, and lines in files
  2.    Copyright (C) 1985, 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by Paul Rubin, phr@ocf.berkeley.edu
  19.    and David MacKenzie, djm@gnu.ai.mit.edu. */
  20.  
  21. #include <config.h>
  22.  
  23. #include <stdio.h>
  24. #include <getopt.h>
  25. #include <sys/types.h>
  26. #include "system.h"
  27. #include "version.h"
  28.  
  29. /* Size of atomic reads. */
  30. #define BUFFER_SIZE (16 * 1024)
  31.  
  32. void error ();
  33. int safe_read ();
  34.  
  35. static void wc ();
  36. static void wc_file ();
  37. static void write_counts ();
  38.  
  39. /* The name this program was run with. */
  40. char *program_name;
  41.  
  42. /* Cumulative number of lines, words, and chars in all files so far. */
  43. static unsigned long total_lines, total_words, total_chars;
  44.  
  45. /* Which counts to print. */
  46. static int print_lines, print_words, print_chars;
  47.  
  48. /* Nonzero if we have ever read the standard input. */
  49. static int have_read_stdin;
  50.  
  51. /* The error code to return to the system. */
  52. static int exit_status;
  53.  
  54. /* If non-zero, display usage information and exit.  */
  55. static int show_help;
  56.  
  57. /* If non-zero, print the version on standard output then exits.  */
  58. static int show_version;
  59.  
  60. static struct option const longopts[] =
  61. {
  62.   {"bytes", no_argument, NULL, 'c'},
  63.   {"chars", no_argument, NULL, 'c'},
  64.   {"lines", no_argument, NULL, 'l'},
  65.   {"words", no_argument, NULL, 'w'},
  66.   {"help", no_argument, &show_help, 1},
  67.   {"version", no_argument, &show_version, 1},
  68.   {NULL, 0, NULL, 0}
  69. };
  70.  
  71. static void
  72. usage (status)
  73.      int status;
  74. {
  75.   if (status != 0)
  76.     fprintf (stderr, "Try `%s --help' for more information.\n",
  77.          program_name);
  78.   else
  79.     {
  80.       printf ("\
  81. Usage: %s [OPTION]... [FILE]...\n\
  82. ",
  83.           program_name);
  84.       printf ("\
  85. \n\
  86.   -c, --bytes, --chars   print the byte counts\n\
  87.   -l, --lines            print the newline counts\n\
  88.   -w, --words            print the word counts\n\
  89.       --help             display this help and exit\n\
  90.       --version          output version information and exit\n\
  91. \n\
  92. Print lines, words and bytes in that order.  If none of -clw, select\n\
  93. them all.  With no FILE, or when FILE is -, read standard input.\n\
  94. ");
  95.     }
  96.   exit (status);
  97. }
  98.  
  99. main (argc, argv)
  100.      int argc;
  101.      char **argv;
  102. {
  103.   int optc;
  104.   int nfiles;
  105.  
  106.   program_name = argv[0];
  107.   exit_status = 0;
  108.   print_lines = print_words = print_chars = 0;
  109.   total_lines = total_words = total_chars = 0;
  110.  
  111.   while ((optc = getopt_long (argc, argv, "clw", longopts, (int *) 0)) != EOF)
  112.     switch (optc)
  113.       {
  114.       case 0:
  115.     break;
  116.  
  117.       case 'c':
  118.     print_chars = 1;
  119.     break;
  120.  
  121.       case 'l':
  122.     print_lines = 1;
  123.     break;
  124.  
  125.       case 'w':
  126.     print_words = 1;
  127.     break;
  128.  
  129.       default:
  130.     usage (1);
  131.       }
  132.  
  133.   if (show_version)
  134.     {
  135.       printf ("wc - %s\n", version_string);
  136.       exit (0);
  137.     }
  138.  
  139.   if (show_help)
  140.     usage (0);
  141.  
  142.   if (print_lines + print_words + print_chars == 0)
  143.     print_lines = print_words = print_chars = 1;
  144.  
  145.   nfiles = argc - optind;
  146.  
  147.   if (nfiles == 0)
  148.     {
  149.       have_read_stdin = 1;
  150.       wc (0, "");
  151.     }
  152.   else
  153.     {
  154.       for (; optind < argc; ++optind)
  155.     wc_file (argv[optind]);
  156.  
  157.       if (nfiles > 1)
  158.     write_counts (total_lines, total_words, total_chars, "total");
  159.     }
  160.  
  161.   if (have_read_stdin && close (0))
  162.     error (1, errno, "-");
  163.  
  164.   exit (exit_status);
  165. }
  166.  
  167. static void
  168. wc_file (file)
  169.      char *file;
  170. {
  171.   if (!strcmp (file, "-"))
  172.     {
  173.       have_read_stdin = 1;
  174.       wc (0, file);
  175.     }
  176.   else
  177.     {
  178.       int fd = open (file, O_RDONLY);
  179.       if (fd == -1)
  180.     {
  181.       error (0, errno, "%s", file);
  182.       exit_status = 1;
  183.       return;
  184.     }
  185.       wc (fd, file);
  186.       if (close (fd))
  187.     {
  188.       error (0, errno, "%s", file);
  189.       exit_status = 1;
  190.     }
  191.     }
  192. }
  193.  
  194. char buf[BUFFER_SIZE];        /* Move buffer off stack; David Gay */
  195.  
  196. static void
  197. wc (fd, file)
  198.      int fd;
  199.      char *file;
  200. {
  201.   register int bytes_read;
  202.   register int in_word = 0;
  203.   register unsigned long lines, words, chars;
  204.   struct stat stats;
  205.  
  206.   lines = words = chars = 0;
  207.  
  208.   /* When counting only bytes, save some line- and word-counting
  209.      overhead.  If FD is a `regular' Unix file, using fstat is enough
  210.      to get its size in bytes.  Otherwise, read blocks of BUFFER_SIZE
  211.      bytes at a time until EOF.  */
  212.   if (print_chars && !print_words && !print_lines)
  213.     {
  214.       if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode))
  215.     {
  216.       chars = stats.st_size;
  217.     }
  218.       else
  219.     {
  220.       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
  221.         {
  222.           chars += bytes_read;
  223.         }
  224.       if (bytes_read < 0)
  225.         {
  226.           error (0, errno, "%s", file);
  227.           exit_status = 1;
  228.         }
  229.     }
  230.     }
  231.   else
  232.     {
  233.       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
  234.     {
  235.       register char *p = buf;
  236.  
  237.       chars += bytes_read;
  238.       do
  239.         {
  240.           switch (*p++)
  241.         {
  242.         case '\n':
  243.           lines++;
  244.           /* Fall through. */
  245.         case '\r':
  246.         case '\f':
  247.         case '\t':
  248.         case '\v':
  249.         case ' ':
  250.           if (in_word)
  251.             {
  252.               in_word = 0;
  253.               words++;
  254.             }
  255.           break;
  256.         default:
  257.           in_word = 1;
  258.           break;
  259.         }
  260.         }
  261.       while (--bytes_read);
  262.     }
  263.       if (bytes_read < 0)
  264.     {
  265.       error (0, errno, "%s", file);
  266.       exit_status = 1;
  267.     }
  268.       if (in_word)
  269.     words++;
  270.     }
  271.  
  272.   write_counts (lines, words, chars, file);
  273.   total_lines += lines;
  274.   total_words += words;
  275.   total_chars += chars;
  276. }
  277.  
  278. static void
  279. write_counts (lines, words, chars, file)
  280.      unsigned long lines, words, chars;
  281.      char *file;
  282. {
  283.   if (print_lines)
  284.     printf ("%7lu", lines);
  285.   if (print_words)
  286.     {
  287.       if (print_lines)
  288.     putchar (' ');
  289.       printf ("%7lu", words);
  290.     }
  291.   if (print_chars)
  292.     {
  293.       if (print_lines || print_words)
  294.     putchar (' ');
  295.       printf ("%7lu", chars);
  296.     }
  297.   if (*file)
  298.     printf (" %s", file);
  299.   putchar ('\n');
  300. }
  301.