Use PROGRAM_NAME in place of string in parse_long_options call.
[platform/upstream/coreutils.git] / src / sum.c
1 /* sum -- checksum and count the blocks in a file
2    Copyright (C) 86, 89, 91, 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
16    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. */
19
20 /* Written by Kayvan Aghaiepour and David MacKenzie. */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <getopt.h>
27 #include "system.h"
28 #include "error.h"
29 #include "long-options.h"
30 #include "safe-read.h"
31
32 /* The official name of this program (e.g., no `g' prefix).  */
33 #define PROGRAM_NAME "sum"
34
35 /* The name this program was run with. */
36 char *program_name;
37
38 /* Nonzero if any of the files read were the standard input. */
39 static int have_read_stdin;
40
41 /* Right-rotate 32-bit integer variable C. */
42 #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x8000; else (c) >>= 1;
43
44 static struct option const longopts[] =
45 {
46   {"sysv", no_argument, NULL, 's'},
47   {NULL, 0, NULL, 0}
48 };
49
50 void
51 usage (int status)
52 {
53   if (status != 0)
54     fprintf (stderr, _("Try `%s --help' for more information.\n"),
55              program_name);
56   else
57     {
58       printf (_("\
59 Usage: %s [OPTION]... [FILE]...\n\
60 "),
61               program_name);
62       printf (_("\
63 Print checksum and block counts for each FILE.\n\
64 \n\
65   -r              defeat -s, use BSD sum algorithm, use 1K blocks\n\
66   -s, --sysv      use System V sum algorithm, use 512 bytes blocks\n\
67       --help      display this help and exit\n\
68       --version   output version information and exit\n\
69 \n\
70 With no FILE, or when FILE is -, read standard input.\n\
71 "));
72       puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
73     }
74   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
75 }
76
77 /* Calculate and print the rotated checksum and the size in 1K blocks
78    of file FILE, or of the standard input if FILE is "-".
79    If PRINT_NAME is >1, print FILE next to the checksum and size.
80    The checksum varies depending on sizeof(int).
81    Return 0 if successful, -1 if an error occurs. */
82
83 static int
84 bsd_sum_file (const char *file, int print_name)
85 {
86   register FILE *fp;
87   register unsigned long checksum = 0; /* The checksum mod 2^16. */
88   register long total_bytes = 0; /* The number of bytes. */
89   register int ch;              /* Each character read. */
90
91   if (STREQ (file, "-"))
92     {
93       fp = stdin;
94       have_read_stdin = 1;
95     }
96   else
97     {
98       fp = fopen (file, "r");
99       if (fp == NULL)
100         {
101           error (0, errno, "%s", file);
102           return -1;
103         }
104     }
105   /* Need binary I/O, or else byte counts and checksums are incorrect.  */
106   SET_BINARY (fileno(fp));
107
108   while ((ch = getc (fp)) != EOF)
109     {
110       total_bytes++;
111       ROTATE_RIGHT (checksum);
112       checksum += ch;
113       checksum &= 0xffff;       /* Keep it within bounds. */
114     }
115
116   if (ferror (fp))
117     {
118       error (0, errno, "%s", file);
119       if (!STREQ (file, "-"))
120         fclose (fp);
121       return -1;
122     }
123
124   if (!STREQ (file, "-") && fclose (fp) == EOF)
125     {
126       error (0, errno, "%s", file);
127       return -1;
128     }
129
130   printf ("%05lu %5ld", checksum, (total_bytes + 1024 - 1) / 1024);
131   if (print_name > 1)
132     printf (" %s", file);
133   putchar ('\n');
134
135   return 0;
136 }
137
138 /* Calculate and print the checksum and the size in 512-byte blocks
139    of file FILE, or of the standard input if FILE is "-".
140    If PRINT_NAME is >0, print FILE next to the checksum and size.
141    Return 0 if successful, -1 if an error occurs. */
142
143 static int
144 sysv_sum_file (const char *file, int print_name)
145 {
146   int fd;
147   unsigned char buf[8192];
148   register int bytes_read;
149   register unsigned long checksum = 0;
150   long total_bytes = 0;
151
152   if (STREQ (file, "-"))
153     {
154       fd = 0;
155       have_read_stdin = 1;
156     }
157   else
158     {
159       fd = open (file, O_RDONLY);
160       if (fd == -1)
161         {
162           error (0, errno, "%s", file);
163           return -1;
164         }
165     }
166   /* Need binary I/O, or else byte counts and checksums are incorrect.  */
167   SET_BINARY (fd);
168
169   while ((bytes_read = safe_read (fd, buf, sizeof buf)) > 0)
170     {
171       register int i;
172
173       for (i = 0; i < bytes_read; i++)
174         checksum += buf[i];
175       total_bytes += bytes_read;
176     }
177
178   if (bytes_read < 0)
179     {
180       error (0, errno, "%s", file);
181       if (!STREQ (file, "-"))
182         close (fd);
183       return -1;
184     }
185
186   if (!STREQ (file, "-") && close (fd) == -1)
187     {
188       error (0, errno, "%s", file);
189       return -1;
190     }
191
192   printf ("%lu %ld", checksum % 0xffff, (total_bytes + 512 - 1) / 512);
193   if (print_name)
194     printf (" %s", file);
195   putchar ('\n');
196
197   return 0;
198 }
199
200 int
201 main (int argc, char **argv)
202 {
203   int errors = 0;
204   int optc;
205   int files_given;
206   int (*sum_func) () = bsd_sum_file;
207
208   program_name = argv[0];
209   setlocale (LC_ALL, "");
210   bindtextdomain (PACKAGE, LOCALEDIR);
211   textdomain (PACKAGE);
212
213   have_read_stdin = 0;
214
215   parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
216                       "Kayvan Aghaiepour and David MacKenzie", usage);
217
218   while ((optc = getopt_long (argc, argv, "rs", longopts, NULL)) != -1)
219     {
220       switch (optc)
221         {
222         case 0:
223           break;
224
225         case 'r':               /* For SysV compatibility. */
226           sum_func = bsd_sum_file;
227           break;
228
229         case 's':
230           sum_func = sysv_sum_file;
231           break;
232
233         default:
234           usage (1);
235         }
236     }
237
238   files_given = argc - optind;
239   if (files_given == 0)
240     {
241       if ((*sum_func) ("-", files_given) < 0)
242         errors = 1;
243     }
244   else
245     for (; optind < argc; optind++)
246       if ((*sum_func) (argv[optind], files_given) < 0)
247         errors = 1;
248
249   if (have_read_stdin && fclose (stdin) == EOF)
250     error (EXIT_FAILURE, errno, "-");
251   exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
252 }