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