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