home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / a / txtutils / textutil.9 / textutil / textutils-1.9 / src / sum.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-23  |  6.2 KB  |  275 lines

  1. /* sum -- checksum and count the blocks in a file
  2.    Copyright (C) 1986, 1989, 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. /* Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. */
  19.  
  20. /* Written by Kayvan Aghaiepour and David MacKenzie. */
  21.  
  22. #ifdef HAVE_CONFIG_H
  23. #if defined (CONFIG_BROKETS)
  24. /* We use <config.h> instead of "config.h" so that a compilation
  25.    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
  26.    (which it would do because it found this file in $srcdir).  */
  27. #include <config.h>
  28. #else
  29. #include "config.h"
  30. #endif
  31. #endif
  32.  
  33. #include <stdio.h>
  34. #include <sys/types.h>
  35. #include <getopt.h>
  36. #include "system.h"
  37. #include "version.h"
  38.  
  39. static int bsd_sum_file ();
  40. static int sysv_sum_file ();
  41.  
  42. void error ();
  43.  
  44. /* The name this program was run with. */
  45. char *program_name;
  46.  
  47. /* Nonzero if any of the files read were the standard input. */
  48. static int have_read_stdin;
  49.  
  50. /* Right-rotate 32-bit integer variable C. */
  51. #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x8000; else (c) >>= 1;
  52.  
  53. /* If non-zero, display usage information and exit.  */
  54. static int show_help;
  55.  
  56. /* If non-zero, print the version on standard output then exit.  */
  57. static int show_version;
  58.  
  59. static struct option const longopts[] =
  60. {
  61.   {"sysv", no_argument, NULL, 's'},
  62.   {"help", no_argument, &show_help, 1},
  63.   {"version", no_argument, &show_version, 1},
  64.   {NULL, 0, NULL, 0}
  65. };
  66.  
  67. static void
  68. usage (status)
  69.      int status;
  70. {
  71.   if (status != 0)
  72.     fprintf (stderr, "Try `%s --help' for more information.\n",
  73.          program_name);
  74.   else
  75.     {
  76.       printf ("\
  77. Usage: %s [OPTION]... [FILE]...\n\
  78. ",
  79.           program_name);
  80.       printf ("\
  81. \n\
  82.   -r              defeat -s, use BSD sum algorithm, use 1K blocks\n\
  83.   -s, --sysv      use System V sum algorithm, use 512 bytes blocks\n\
  84.       --help      display this help and exit\n\
  85.       --version   output version information and exit\n\
  86. \n\
  87. With no FILE, or when FILE is -, read standard input.\n\
  88. ");
  89.     }
  90.   exit (status);
  91. }
  92.  
  93. void
  94. main (argc, argv)
  95.      int argc;
  96.      char **argv;
  97. {
  98.   int errors = 0;
  99.   int optc;
  100.   int files_given;
  101.   int (*sum_func) () = bsd_sum_file;
  102.  
  103.   program_name = argv[0];
  104.   have_read_stdin = 0;
  105.  
  106.   while ((optc = getopt_long (argc, argv, "rs", longopts, (int *) 0)) != -1)
  107.     {
  108.       switch (optc)
  109.     {
  110.     case 0:
  111.       break;
  112.  
  113.     case 'r':        /* For SysV compatibility. */
  114.       sum_func = bsd_sum_file;
  115.       break;
  116.  
  117.     case 's':
  118.       sum_func = sysv_sum_file;
  119.       break;
  120.  
  121.     default:
  122.       usage (1);
  123.     }
  124.     }
  125.  
  126.   if (show_version)
  127.     {
  128.       printf ("%s\n", version_string);
  129.       exit (0);
  130.     }
  131.  
  132.   if (show_help)
  133.     usage (0);
  134.  
  135.   files_given = argc - optind;
  136.   if (files_given == 0)
  137.     {
  138.       if ((*sum_func) ("-", files_given) < 0)
  139.     errors = 1;
  140.     }
  141.   else
  142.     for (; optind < argc; optind++)
  143.       if ((*sum_func) (argv[optind], files_given) < 0)
  144.     errors = 1;
  145.  
  146.   if (have_read_stdin && fclose (stdin) == EOF)
  147.     error (1, errno, "-");
  148.   exit (errors);
  149. }
  150.  
  151. /* Calculate and print the rotated checksum and the size in 1K blocks
  152.    of file FILE, or of the standard input if FILE is "-".
  153.    If PRINT_NAME is >1, print FILE next to the checksum and size.
  154.    The checksum varies depending on sizeof(int).
  155.    Return 0 if successful, -1 if an error occurs. */
  156.  
  157. static int
  158. bsd_sum_file (file, print_name)
  159.      char *file;
  160.      int print_name;
  161. {
  162.   register FILE *fp;
  163.   register unsigned long checksum = 0; /* The checksum mod 2^16. */
  164.   register long total_bytes = 0; /* The number of bytes. */
  165.   register int ch;        /* Each character read. */
  166.  
  167.   if (!strcmp (file, "-"))
  168.     {
  169.       fp = stdin;
  170.       have_read_stdin = 1;
  171.     }
  172.   else
  173.     {
  174.       fp = fopen (file, "r");
  175.       if (fp == NULL)
  176.     {
  177.       error (0, errno, "%s", file);
  178.       return -1;
  179.     }
  180.     }
  181.  
  182.   /* This algorithm seems to depend on sign extension in `ch' in order to
  183.      give the right results.  Ick.  */
  184.   while ((ch = getc (fp)) != EOF)
  185.     {
  186.       total_bytes++;
  187.       ROTATE_RIGHT (checksum);
  188.       checksum += ch;
  189.       checksum &= 0xffff;    /* Keep it within bounds. */
  190.     }
  191.  
  192.   if (ferror (fp))
  193.     {
  194.       error (0, errno, "%s", file);
  195.       if (strcmp (file, "-"))
  196.     fclose (fp);
  197.       return -1;
  198.     }
  199.  
  200.   if (strcmp (file, "-") && fclose (fp) == EOF)
  201.     {
  202.       error (0, errno, "%s", file);
  203.       return -1;
  204.     }
  205.  
  206.   printf ("%05lu %5ld", checksum, (total_bytes + 1024 - 1) / 1024);
  207.   if (print_name > 1)
  208.     printf (" %s", file);
  209.   putchar ('\n');
  210.  
  211.   return 0;
  212. }
  213.  
  214. /* Calculate and print the checksum and the size in 512-byte blocks
  215.    of file FILE, or of the standard input if FILE is "-".
  216.    If PRINT_NAME is >0, print FILE next to the checksum and size.
  217.    Return 0 if successful, -1 if an error occurs. */
  218.  
  219. static int
  220. sysv_sum_file (file, print_name)
  221.      char *file;
  222.      int print_name;
  223. {
  224.   int fd;
  225.   unsigned char buf[8192];
  226.   register int bytes_read;
  227.   register unsigned long checksum = 0;
  228.   long total_bytes = 0;
  229.  
  230.   if (!strcmp (file, "-"))
  231.     {
  232.       fd = 0;
  233.       have_read_stdin = 1;
  234.     }
  235.   else
  236.     {
  237.       fd = open (file, O_RDONLY);
  238.       if (fd == -1)
  239.     {
  240.       error (0, errno, "%s", file);
  241.       return -1;
  242.     }
  243.     }
  244.  
  245.   while ((bytes_read = read (fd, buf, sizeof buf)) > 0)
  246.     {
  247.       register int i;
  248.  
  249.       for (i = 0; i < bytes_read; i++)
  250.     checksum += buf[i];
  251.       total_bytes += bytes_read;
  252.     }
  253.  
  254.   if (bytes_read < 0)
  255.     {
  256.       error (0, errno, "%s", file);
  257.       if (strcmp (file, "-"))
  258.     close (fd);
  259.       return -1;
  260.     }
  261.  
  262.   if (strcmp (file, "-") && close (fd) == -1)
  263.     {
  264.       error (0, errno, "%s", file);
  265.       return -1;
  266.     }
  267.  
  268.   printf ("%lu %ld", checksum % 0xffff, (total_bytes + 512 - 1) / 512);
  269.   if (print_name)
  270.     printf (" %s", file);
  271.   putchar ('\n');
  272.  
  273.   return 0;
  274. }
  275.