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