Convert static declarations of struct option to use new macros from
[platform/upstream/coreutils.git] / src / sum.c
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
27 static int bsd_sum_file ();
28 static int sysv_sum_file ();
29
30 void error ();
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 static struct option const longopts[] =
42 {
43   {"sysv", no_argument, NULL, 's'},
44   {NULL, 0, NULL, 0}
45 };
46
47 void
48 main (argc, argv)
49      int argc;
50      char **argv;
51 {
52   int errors = 0;
53   int optc;
54   int files_given;
55   int (*sum_func) () = bsd_sum_file;
56
57   program_name = argv[0];
58   have_read_stdin = 0;
59
60   while ((optc = getopt_long (argc, argv, "rs", longopts, (int *) 0)) != -1)
61     {
62       switch (optc)
63         {
64         case 'r':               /* For SysV compatibility. */
65           sum_func = bsd_sum_file;
66           break;
67
68         case 's':
69           sum_func = sysv_sum_file;
70           break;
71
72         case '?':
73           fprintf (stderr, "\
74 Usage: %s [-rs] [--sysv] [file...]\n", argv[0]);
75           exit (1);
76         }
77     }
78
79   files_given = argc - optind;
80   if (files_given == 0)
81     {
82       if ((*sum_func) ("-", files_given) < 0)
83         errors = 1;
84     }
85   else
86     for (; optind < argc; optind++)
87       if ((*sum_func) (argv[optind], files_given) < 0)
88         errors = 1;
89
90   if (have_read_stdin && fclose (stdin) == EOF)
91     error (1, errno, "-");
92   exit (errors);
93 }
94
95 /* Calculate and print the rotated checksum and the size in 1K blocks
96    of file FILE, or of the standard input if FILE is "-".
97    If PRINT_NAME is >1, print FILE next to the checksum and size.
98    The checksum varies depending on sizeof(int).
99    Return 0 if successful, -1 if an error occurs. */
100
101 static int
102 bsd_sum_file (file, print_name)
103      char *file;
104      int print_name;
105 {
106   register FILE *fp;
107   register unsigned long checksum = 0; /* The checksum mod 2^16. */
108   register long total_bytes = 0; /* The number of bytes. */
109   register int ch;              /* Each character read. */
110
111   if (!strcmp (file, "-"))
112     {
113       fp = stdin;
114       have_read_stdin = 1;
115     }
116   else
117     {
118       fp = fopen (file, "r");
119       if (fp == NULL)
120         {
121           error (0, errno, "%s", file);
122           return -1;
123         }
124     }
125  
126   /* This algorithm seems to depend on sign extension in `ch' in order to
127      give the right results.  Ick.  */
128   while ((ch = getc (fp)) != EOF)
129     {
130       total_bytes++;
131       ROTATE_RIGHT (checksum);
132       checksum += ch;
133       checksum &= 0xffff;       /* Keep it within bounds. */
134     }
135
136   if (ferror (fp))
137     {
138       error (0, errno, "%s", file);
139       if (strcmp (file, "-"))
140         fclose (fp);
141       return -1;
142     }
143
144   if (strcmp (file, "-") && fclose (fp) == EOF)
145     {
146       error (0, errno, "%s", file);
147       return -1;
148     }
149
150   printf ("%05lu %5ld", checksum, (total_bytes + 1024 - 1) / 1024);
151   if (print_name > 1)
152     printf (" %s", file);
153   putchar ('\n');
154
155   return 0;
156 }
157
158 /* Calculate and print the checksum and the size in 512-byte blocks
159    of file FILE, or of the standard input if FILE is "-".
160    If PRINT_NAME is >0, print FILE next to the checksum and size.
161    Return 0 if successful, -1 if an error occurs. */
162
163 static int
164 sysv_sum_file (file, print_name)
165      char *file;
166      int print_name;
167 {
168   int fd;
169   unsigned char buf[8192];
170   register int bytes_read;
171   register unsigned long checksum = 0;
172   long total_bytes = 0;
173
174   if (!strcmp (file, "-"))
175     {
176       fd = 0;
177       have_read_stdin = 1;
178     }
179   else
180     {
181       fd = open (file, O_RDONLY);
182       if (fd == -1)
183         {
184           error (0, errno, "%s", file);
185           return -1;
186         }
187     }
188
189   while ((bytes_read = read (fd, buf, sizeof buf)) > 0)
190     {
191       register int i;
192
193       for (i = 0; i < bytes_read; i++)
194         checksum += buf[i];
195       total_bytes += bytes_read;
196     }
197
198   if (bytes_read < 0)
199     {
200       error (0, errno, "%s", file);
201       if (strcmp (file, "-"))
202         close (fd);
203       return -1;
204     }
205
206   if (strcmp (file, "-") && close (fd) == -1)
207     {
208       error (0, errno, "%s", file);
209       return -1;
210     }
211
212   printf ("%lu %ld", checksum % 0xffff, (total_bytes + 512 - 1) / 512);
213   if (print_name)
214     printf (" %s", file);
215   putchar ('\n');
216
217   return 0;
218 }