Compare getopt_long return value against -1, not EOF. Use NULL, not '(int *) 0'...
[platform/upstream/coreutils.git] / src / cksum.c
1 /* cksum -- calculate and print POSIX.2 checksums and sizes of files
2    Copyright (C) 92, 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 \f
18 /* Written by Q. Frank Xia, qx@math.columbia.edu.
19    Cosmetic changes and reorganization by David MacKenzie, djm@gnu.ai.mit.edu.
20
21   Usage: cksum [file...]
22
23   The code segment between "#ifdef CRCTAB" and "#else" is the code
24   which calculates the "crctab". It is included for those who want
25   verify the correctness of the "crctab". To recreate the "crctab",
26   do following:
27
28       cc -DCRCTAB -o crctab cksum.c
29       crctab > crctab.h
30
31   As Bruce Evans pointed out to me, the crctab in the sample C code
32   in 4.9.10 Rationale of P1003.2/D11.2 is represented in reversed order.
33   Namely, 0x01 is represented as 0x80, 0x02 is represented as 0x40, etc.
34   The generating polynomial is crctab[0x80]=0xedb88320 instead of
35   crctab[1]=0x04C11DB7.  But the code works only for a non-reverse order
36   crctab.  Therefore, the sample implementation is wrong.
37
38   This software is compatible with neither the System V nor the BSD
39   `sum' program.  It is supposed to conform to P1003.2/D11.2,
40   except foreign language interface (4.9.5.3 of P1003.2/D11.2) support.
41   Any inconsistency with the standard except 4.9.5.3 is a bug.  */
42
43 #include <config.h>
44
45 #ifdef CRCTAB
46
47 #include <stdio.h>
48
49 #define BIT(x)  ( (unsigned long)1 << (x) )
50 #define SBIT    BIT(31)
51
52 /* The generating polynomial is
53
54           32   26   23   22   16   12   11   10   8   7   5   4   2   1
55     G(X)=X  + X  + X  + X  + X  + X  + X  + X  + X + X + X + X + X + X + 1
56
57   The i bit in GEN is set if X^i is a summand of G(X) except X^32.  */
58
59 #define GEN     (BIT(26)|BIT(23)|BIT(22)|BIT(16)|BIT(12)|BIT(11)|BIT(10)\
60                 |BIT(8) |BIT(7) |BIT(5) |BIT(4) |BIT(2) |BIT(1) |BIT(0));
61
62 static unsigned long r[8];
63
64 static void
65 fill_r ()
66 {
67   int i;
68
69   r[0] = GEN;
70   for (i = 1; i < 8; i++)
71     r[i] = (r[i - 1] & SBIT) ? (r[i - 1] << 1) ^ r[0] : r[i - 1] << 1;
72 }
73
74 static unsigned long
75 remainder (m)
76      int m;
77 {
78   unsigned long rem = 0;
79   int i;
80
81   for (i = 0; i < 8; i++)
82     if (BIT (i) & m)
83       rem = rem ^ r[i];
84
85   return rem & 0xFFFFFFFF;      /* Make it run on 64-bit machine.  */
86 }
87
88 int
89 main ()
90 {
91   int i;
92
93   fill_r ();
94   printf ("unsigned long crctab[256] = {\n  0x0");
95   for (i = 0; i < 51; i++)
96     {
97       printf (",\n  0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X",
98         remainder (i * 5 + 1), remainder (i * 5 + 2), remainder (i * 5 + 3),
99               remainder (i * 5 + 4), remainder (i * 5 + 5));
100     }
101   printf ("\n};\n");
102   exit (EXIT_SUCCESS);
103 }
104
105 #else /* !CRCTAB */
106
107 #include <stdio.h>
108 #include <getopt.h>
109 #include <sys/types.h>
110 #include "system.h"
111 #include "error.h"
112
113 /* Number of bytes to read at once.  */
114 #define BUFLEN (1 << 16)
115
116 /* The name this program was run with.  */
117 char *program_name;
118
119 /* If nonzero, display usage information and exit.  */
120 static int show_help;
121
122 /* If nonzero, print the version on standard output then exit.  */
123 static int show_version;
124
125 static struct option const long_options[] =
126 {
127   {"help", no_argument, &show_help, 1},
128   {"version", no_argument, &show_version, 1},
129   {0, 0, 0, 0}
130 };
131
132 static unsigned long const crctab[256] =
133 {
134   0x0,
135   0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
136   0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
137   0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
138   0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
139   0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
140   0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
141   0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
142   0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
143   0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
144   0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
145   0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
146   0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
147   0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
148   0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
149   0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
150   0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
151   0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
152   0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
153   0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
154   0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
155   0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
156   0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
157   0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
158   0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
159   0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
160   0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
161   0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
162   0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
163   0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
164   0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
165   0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
166   0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
167   0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
168   0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
169   0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
170   0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
171   0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
172   0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
173   0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
174   0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
175   0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
176   0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
177   0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
178   0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
179   0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
180   0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
181   0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
182   0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
183   0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
184   0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
185   0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
186 };
187
188 /* Nonzero if any of the files read were the standard input. */
189 static int have_read_stdin;
190
191 /* Calculate and print the checksum and length in bytes
192    of file FILE, or of the standard input if FILE is "-".
193    If PRINT_NAME is nonzero, print FILE next to the checksum and size.
194    Return 0 if successful, -1 if an error occurs. */
195
196 static int
197 cksum (char *file, int print_name)
198 {
199   unsigned char buf[BUFLEN];
200   unsigned long crc = 0;
201   long length = 0;
202   long bytes_read;
203   register FILE *fp;
204
205   if (!strcmp (file, "-"))
206     {
207       fp = stdin;
208       have_read_stdin = 1;
209     }
210   else
211     {
212       fp = fopen (file, "r");
213       if (fp == NULL)
214         {
215           error (0, errno, "%s", file);
216           return -1;
217         }
218     }
219
220   while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0)
221     {
222       unsigned char *cp = buf;
223
224       length += bytes_read;
225       while (bytes_read--)
226         crc = (crc << 8) ^ crctab[((crc >> 24) ^ *(cp++)) & 0xFF];
227     }
228
229   if (ferror (fp))
230     {
231       error (0, errno, "%s", file);
232       if (strcmp (file, "-"))
233         fclose (fp);
234       return -1;
235     }
236
237   if (strcmp (file, "-") && fclose (fp) == EOF)
238     {
239       error (0, errno, "%s", file);
240       return -1;
241     }
242
243   bytes_read = length;
244   while (bytes_read > 0)
245     {
246       crc = (crc << 8) ^ crctab[((crc >> 24) ^ bytes_read) & 0xFF];
247       bytes_read >>= 8;
248     }
249
250   crc = ~crc & 0xFFFFFFFF;
251
252   printf ("%lu %ld", crc, length);
253   if (print_name)
254     printf (" %s", file);
255   putchar ('\n');
256
257   return 0;
258 }
259
260 static void
261 usage (int status)
262 {
263   if (status != 0)
264     fprintf (stderr, _("Try `%s --help' for more information.\n"),
265              program_name);
266   else
267     {
268       printf (_("\
269 Usage: %s [OPTION]... [FILE]...\n\
270 "),
271               program_name);
272       printf (_("\
273 Print CRC checksum and byte counts of each FILE.\n\
274 \n\
275   --help      display this help and exit\n\
276   --version   output version information and exit\n\
277 "));
278       puts (_("\nReport bugs to textutils-bugs@gnu.ai.mit.edu"));
279     }
280   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
281 }
282
283 int
284 main (int argc, char **argv)
285 {
286   int i, c;
287   int errors = 0;
288
289   program_name = argv[0];
290   setlocale (LC_ALL, "");
291   bindtextdomain (PACKAGE, LOCALEDIR);
292   textdomain (PACKAGE);
293
294   have_read_stdin = 0;
295
296   while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1)
297     {
298       switch (c)
299         {
300         case 0:
301           break;
302
303         default:
304           usage (1);
305         }
306     }
307
308   if (show_version)
309     {
310       printf ("cksum (%s) %s\n", GNU_PACKAGE, VERSION);
311       exit (EXIT_SUCCESS);
312     }
313
314   if (show_help)
315     usage (0);
316
317   if (optind >= argc)
318     {
319       if (cksum ("-", 0) < 0)
320         errors = 1;
321     }
322   else
323     {
324       for (i = optind; i < argc; i++)
325         if (cksum (argv[i], 1) < 0)
326           errors = 1;
327     }
328
329   if (have_read_stdin && fclose (stdin) == EOF)
330     error (EXIT_FAILURE, errno, "-");
331   exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
332 }
333
334 #endif /* !CRCTAB */