.
[coreutils.git] / src / cksum.c
blob9253d9b16711f75fe59b792c851dc9714f4349cb
1 /* cksum -- calculate and print POSIX checksums and sizes of files
2 Copyright (C) 92, 1995-2003 Free Software Foundation, Inc.
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.
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.
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. */
18 /* Written by Q. Frank Xia, qx@math.columbia.edu.
19 Cosmetic changes and reorganization by David MacKenzie, djm@gnu.ai.mit.edu.
21 Usage: cksum [file...]
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:
28 cc -DCRCTAB -o crctab cksum.c
29 crctab > crctab.h
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.
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. */
43 #include <config.h>
45 /* The official name of this program (e.g., no `g' prefix). */
46 #define PROGRAM_NAME "cksum"
48 #define AUTHORS "Q. Frank Xia"
50 #include <stdio.h>
51 #include <sys/types.h>
52 #include "system.h"
54 #if !defined UINT_FAST32_MAX && !defined uint_fast32_t
55 # define uint_fast32_t unsigned int
56 #endif
58 #ifdef CRCTAB
60 # define BIT(x) ((uint_fast32_t) 1 << (x))
61 # define SBIT BIT (31)
63 /* The generating polynomial is
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
68 The i bit in GEN is set if X^i is a summand of G(X) except X^32. */
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))
74 static uint_fast32_t r[8];
76 static void
77 fill_r (void)
79 int i;
81 r[0] = GEN;
82 for (i = 1; i < 8; i++)
83 r[i] = (r[i - 1] << 1) ^ ((r[i - 1] & SBIT) ? GEN : 0);
86 static uint_fast32_t
87 remainder (int m)
89 uint_fast32_t rem = 0;
90 int i;
92 for (i = 0; i < 8; i++)
93 if (BIT (i) & m)
94 rem ^= r[i];
96 return rem & 0xFFFFFFFF; /* Make it run on 64-bit machine. */
99 int
100 main (void)
102 int i;
104 fill_r ();
105 printf ("static uint_fast32_t crctab[256] =\n{\n 0x0");
106 for (i = 0; i < 51; i++)
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));
113 printf ("\n};\n");
114 exit (EXIT_SUCCESS);
117 #else /* !CRCTAB */
119 # include <getopt.h>
120 # include "long-options.h"
121 # include "error.h"
122 # include "inttostr.h"
124 /* Number of bytes to read at once. */
125 # define BUFLEN (1 << 16)
127 /* The name this program was run with. */
128 char *program_name;
130 static struct option const long_options[] =
132 {0, 0, 0, 0}
135 static uint_fast32_t crctab[256] =
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
191 /* Nonzero if any of the files read were the standard input. */
192 static int have_read_stdin;
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. */
199 static int
200 cksum (const char *file, int print_name)
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;
210 if (STREQ (file, "-"))
212 fp = stdin;
213 have_read_stdin = 1;
215 else
217 fp = fopen (file, "r");
218 if (fp == NULL)
220 error (0, errno, "%s", file);
221 return -1;
225 /* Read input in BINARY mode, unless it is a console device. */
226 SET_BINARY (fileno (fp));
228 while ((bytes_read = fread (buf, 1, BUFLEN, fp)) > 0)
230 unsigned char *cp = buf;
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;
241 if (ferror (fp))
243 error (0, errno, "%s", file);
244 if (!STREQ (file, "-"))
245 fclose (fp);
246 return -1;
249 if (!STREQ (file, "-") && fclose (fp) == EOF)
251 error (0, errno, "%s", file);
252 return -1;
255 hp = umaxtostr (length, length_buf);
257 for (; length; length >>= 8)
258 crc = (crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
260 crc = ~crc & 0xFFFFFFFF;
262 if (print_name)
263 printf ("%u %s %s\n", (unsigned) crc, hp, file);
264 else
265 printf ("%u %s\n", (unsigned) crc, hp);
267 if (ferror (stdout))
268 error (EXIT_FAILURE, errno, "-: %s", _("write error"));
270 return 0;
273 void
274 usage (int status)
276 if (status != 0)
277 fprintf (stderr, _("Try `%s --help' for more information.\n"),
278 program_name);
279 else
281 printf (_("\
282 Usage: %s [FILE]...\n\
283 or: %s [OPTION]\n\
285 program_name, program_name);
286 fputs (_("\
287 Print CRC checksum and byte counts of each FILE.\n\
289 "), stdout);
290 fputs (HELP_OPTION_DESCRIPTION, stdout);
291 fputs (VERSION_OPTION_DESCRIPTION, stdout);
292 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
294 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
298 main (int argc, char **argv)
300 int i, c;
301 int errors = 0;
303 initialize_main (&argc, &argv);
304 program_name = argv[0];
305 setlocale (LC_ALL, "");
306 bindtextdomain (PACKAGE, LOCALEDIR);
307 textdomain (PACKAGE);
309 atexit (close_stdout);
311 parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, VERSION,
312 usage, AUTHORS, (char const *) NULL);
314 have_read_stdin = 0;
316 while ((c = getopt_long (argc, argv, "", long_options, NULL)) != -1)
318 switch (c)
320 case 0:
321 break;
323 default:
324 usage (EXIT_FAILURE);
328 if (optind == argc)
329 errors |= cksum ("-", 0);
330 else
332 for (i = optind; i < argc; i++)
333 errors |= cksum (argv[i], 1);
336 if (have_read_stdin && fclose (stdin) == EOF)
337 error (EXIT_FAILURE, errno, "-");
338 exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
341 #endif /* !CRCTAB */