home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / textutils-1.19-src.tgz / tar.out / fsf / textutils / src / sum.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  6KB  |  260 lines

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