LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 680|回复: 0

看看你能不能写出像样的wc

[复制链接]
发表于 2005-12-29 21:30:26 | 显示全部楼层 |阅读模式
wc在我看来是最简单的程序了

不过不知你看了源程序是不是和我的感觉一样

好像一点也不简单

  1. /* wc - print the number of bytes, words, and lines in files
  2.    Copyright (C) 85, 91, 95, 1996 Free Software Foundation, Inc.

  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2, or (at your option)
  6.    any later version.

  7.    This program is distributed in the hope that it will be useful,
  8.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.    GNU General Public License for more details.

  11.    You should have received a copy of the GNU General Public License
  12.    along with this program; if not, write to the Free Software
  13.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

  14. /* Written by Paul Rubin, [email]phr@ocf.berkeley.edu[/email]
  15.    and David MacKenzie, [email]djm@gnu.ai.mit.edu[/email]. */

  16. #include <config.h>

  17. #include <stdio.h>
  18. #include <getopt.h>
  19. #include <sys/types.h>
  20. #include "system.h"
  21. #include "error.h"

  22. /* Size of atomic reads. */
  23. #define BUFFER_SIZE (16 * 1024)

  24. int safe_read ();

  25. /* The name this program was run with. */
  26. char *program_name;

  27. /* Cumulative number of lines, words, and chars in all files so far. */
  28. static unsigned long total_lines, total_words, total_chars;

  29. /* Which counts to print. */
  30. static int print_lines, print_words, print_chars;

  31. /* Nonzero if we have ever read the standard input. */
  32. static int have_read_stdin;

  33. /* The error code to return to the system. */
  34. static int exit_status;

  35. /* If nonzero, display usage information and exit.  */
  36. static int show_help;

  37. /* If nonzero, print the version on standard output then exits.  */
  38. static int show_version;

  39. static struct option const longopts[] =
  40. {
  41.   {"bytes", no_argument, NULL, 'c'},
  42.   {"chars", no_argument, NULL, 'c'},
  43.   {"lines", no_argument, NULL, 'l'},
  44.   {"words", no_argument, NULL, 'w'},
  45.   {"help", no_argument, &show_help, 1},
  46.   {"version", no_argument, &show_version, 1},
  47.   {NULL, 0, NULL, 0}
  48. };

  49. static void
  50. usage (int status)
  51. {
  52.   if (status != 0)
  53.     fprintf (stderr, _("Try `%s --help' for more information.\n"),
  54.              program_name);
  55.   else
  56.     {
  57.       printf (_("\
  58. Usage: %s [OPTION]... [FILE]...\n\
  59. "),
  60.               program_name);
  61.       printf (_("\
  62. Print line, word, and byte counts for each FILE, and a total line if\n\
  63. more than one FILE is specified.  With no FILE, or when FILE is -,\n\
  64. read standard input.\n\
  65.   -c, --bytes, --chars   print the byte counts\n\
  66.   -l, --lines            print the newline counts\n\
  67.   -w, --words            print the word counts\n\
  68.       --help             display this help and exit\n\
  69.       --version          output version information and exit\n\
  70. "));
  71.       puts (_("\nReport bugs to [email]textutils-bugs@gnu.ai.mit.edu[/email]"));
  72.     }
  73.   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
  74. }

  75. static void
  76. write_counts (long unsigned int lines, long unsigned int words,
  77.               long unsigned int chars, const char *file)
  78. {
  79.   if (print_lines)
  80.     printf ("%7lu", lines);
  81.   if (print_words)
  82.     {
  83.       if (print_lines)
  84.         putchar (' ');
  85.       printf ("%7lu", words);
  86.     }
  87.   if (print_chars)
  88.     {
  89.       if (print_lines || print_words)
  90.         putchar (' ');
  91.       printf ("%7lu", chars);
  92.     }
  93.   if (*file)
  94.     printf (" %s", file);
  95.   putchar ('\n');
  96. }

  97. static void
  98. wc (int fd, const char *file)
  99. {
  100.   char buf[BUFFER_SIZE + 1];
  101.   register int bytes_read;
  102.   register int in_word = 0;
  103.   register unsigned long lines, words, chars;

  104.   lines = words = chars = 0;

  105.   /* When counting only bytes, save some line- and word-counting
  106.      overhead.  If FD is a `regular' Unix file, using lseek is enough
  107.      to get its `size' in bytes.  Otherwise, read blocks of BUFFER_SIZE
  108.      bytes at a time until EOF.  Note that the `size' (number of bytes)
  109.      that wc reports is smaller than stats.st_size when the file is not
  110.      positioned at its beginning.  That's why the lseek calls below are
  111.      necessary.  For example the command
  112.      `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
  113.      should make wc report `0' bytes.  */

  114.   if (print_chars && !print_words && !print_lines)
  115.     {
  116.       off_t current_pos, end_pos;
  117.       struct stat stats;

  118.       if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
  119.           && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
  120.           && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
  121.         {
  122.           off_t diff;
  123.           /* Be careful here.  The current position may actually be
  124.              beyond the end of the file.  As in the example above.  */
  125.           chars = (diff = end_pos - current_pos) < 0 ? 0 : diff;
  126.         }
  127.       else
  128.         {
  129.           while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
  130.             {
  131.               chars += bytes_read;
  132.             }
  133.           if (bytes_read < 0)
  134.             {
  135.               error (0, errno, "%s", file);
  136.               exit_status = 1;
  137.             }
  138.         }
  139.     }
  140.   else if (!print_words)
  141.     {
  142.       /* Use a separate loop when counting only lines or lines and bytes --
  143.          but not words.  */
  144.       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
  145.         {
  146.           register char *p = buf;

  147.           while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
  148.             {
  149.               ++p;
  150.               ++lines;
  151.             }
  152.           chars += bytes_read;
  153.         }
  154.       if (bytes_read < 0)
  155.         {
  156.           error (0, errno, "%s", file);
  157.           exit_status = 1;
  158.         }
  159.     }
  160.   else
  161.     {
  162.       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
  163.         {
  164.           register char *p = buf;

  165.           chars += bytes_read;
  166.           do
  167.             {
  168.               switch (*p++)
  169.                 {
  170.                 case '\n':
  171.                   lines++;
  172.                   /* Fall through. */
  173.                 case '\r':
  174.                 case '\f':
  175.                 case '\t':
  176.                 case '\v':
  177.                 case ' ':
  178.                   if (in_word)
  179.                     {
  180.                       in_word = 0;
  181.                       words++;
  182.                     }
  183.                   break;
  184.                 default:
  185.                   in_word = 1;
  186.                   break;
  187.                 }
  188.             }
  189.           while (--bytes_read);
  190.         }
  191.       if (bytes_read < 0)
  192.         {
  193.           error (0, errno, "%s", file);
  194.           exit_status = 1;
  195.         }
  196.       if (in_word)
  197.         words++;
  198.     }

  199.   write_counts (lines, words, chars, file);
  200.   total_lines += lines;
  201.   total_words += words;
  202.   total_chars += chars;
  203. }

  204. static void
  205. wc_file (const char *file)
  206. {
  207.   if (!strcmp (file, "-"))
  208.     {
  209.       have_read_stdin = 1;
  210.       wc (0, file);
  211.     }
  212.   else
  213.     {
  214.       int fd = open (file, O_RDONLY);
  215.       if (fd == -1)
  216.         {
  217.           error (0, errno, "%s", file);
  218.           exit_status = 1;
  219.           return;
  220.         }
  221.       wc (fd, file);
  222.       if (close (fd))
  223.         {
  224.           error (0, errno, "%s", file);
  225.           exit_status = 1;
  226.         }
  227.     }
  228. }

  229. int
  230. main (int argc, char **argv)
  231. {
  232.   int optc;
  233.   int nfiles;

  234.   program_name = argv[0];
  235.   setlocale (LC_ALL, "");
  236.   bindtextdomain (PACKAGE, LOCALEDIR);
  237.   textdomain (PACKAGE);

  238.   exit_status = 0;
  239.   print_lines = print_words = print_chars = 0;
  240.   total_lines = total_words = total_chars = 0;

  241.   while ((optc = getopt_long (argc, argv, "clw", longopts, (int *) 0)) != EOF)
  242.     switch (optc)
  243.       {
  244.       case 0:
  245.         break;

  246.       case 'c':
  247.         print_chars = 1;
  248.         break;

  249.       case 'l':
  250.         print_lines = 1;
  251.         break;

  252.       case 'w':
  253.         print_words = 1;
  254.         break;

  255.       default:
  256.         usage (1);
  257.       }

  258.   if (show_version)
  259.     {
  260.       printf ("wc (%s) %s\n", GNU_PACKAGE, VERSION);
  261.       exit (EXIT_SUCCESS);
  262.     }

  263.   if (show_help)
  264.     usage (0);

  265.   if (print_lines + print_words + print_chars == 0)
  266.     print_lines = print_words = print_chars = 1;

  267.   nfiles = argc - optind;

  268.   if (nfiles == 0)
  269.     {
  270.       have_read_stdin = 1;
  271.       wc (0, "");
  272.     }
  273.   else
  274.     {
  275.       for (; optind < argc; ++optind)
  276.         wc_file (argv[optind]);

  277.       if (nfiles > 1)
  278.         write_counts (total_lines, total_words, total_chars, _("total"));
  279.     }

  280.   if (have_read_stdin && close (0))
  281.     error (EXIT_FAILURE, errno, "-");

  282.   exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
  283. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表