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