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