Use PROGRAM_NAME in place of string in parse_long_options call.
[platform/upstream/coreutils.git] / src / wc.c
1 /* wc - print the number of bytes, words, and lines in files
2    Copyright (C) 85, 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 Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by Paul Rubin, phr@ocf.berkeley.edu
19    and David MacKenzie, djm@gnu.ai.mit.edu. */
20 \f
21 #include <config.h>
22 #if HAVE_INTTYPES_H
23 # include <inttypes.h>
24 #endif
25
26 #include <stdio.h>
27 #include <getopt.h>
28 #include <sys/types.h>
29 #include "system.h"
30 #include "error.h"
31 #include "human.h"
32 #include "long-options.h"
33 #include "safe-read.h"
34
35 /* The official name of this program (e.g., no `g' prefix).  */
36 #define PROGRAM_NAME "wc"
37
38 /* Size of atomic reads. */
39 #define BUFFER_SIZE (16 * 1024)
40
41 /* The name this program was run with. */
42 char *program_name;
43
44 /* Cumulative number of lines, words, and chars in all files so far.
45    max_line_length is the maximum over all files processed so far.  */
46 static uintmax_t total_lines;
47 static uintmax_t total_words;
48 static uintmax_t total_chars;
49 static uintmax_t max_line_length;
50
51 /* Which counts to print. */
52 static int print_lines, print_words, print_chars, print_linelength;
53
54 /* Nonzero if we have ever read the standard input. */
55 static int have_read_stdin;
56
57 /* The error code to return to the system. */
58 static int exit_status;
59
60 static struct option const longopts[] =
61 {
62   {"bytes", no_argument, NULL, 'c'},
63   {"chars", no_argument, NULL, 'c'},
64   {"lines", no_argument, NULL, 'l'},
65   {"words", no_argument, NULL, 'w'},
66   {"max-line-length", no_argument, NULL, 'L'},
67   {NULL, 0, NULL, 0}
68 };
69
70 void
71 usage (int status)
72 {
73   if (status != 0)
74     fprintf (stderr, _("Try `%s --help' for more information.\n"),
75              program_name);
76   else
77     {
78       printf (_("\
79 Usage: %s [OPTION]... [FILE]...\n\
80 "),
81               program_name);
82       printf (_("\
83 Print line, word, and byte counts for each FILE, and a total line if\n\
84 more than one FILE is specified.  With no FILE, or when FILE is -,\n\
85 read standard input.\n\
86   -c, --bytes, --chars   print the byte counts\n\
87   -l, --lines            print the newline counts\n\
88   -L, --max-line-length  print the length of the longest line\n\
89   -w, --words            print the word counts\n\
90       --help             display this help and exit\n\
91       --version          output version information and exit\n\
92 "));
93       puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
94     }
95   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
96 }
97
98 static void
99 write_counts (uintmax_t lines,
100               uintmax_t words,
101               uintmax_t chars,
102               uintmax_t linelength,
103               const char *file)
104 {
105   char buf[LONGEST_HUMAN_READABLE + 1];
106   char const *space = "";
107
108   if (print_lines)
109     {
110       printf ("%7s", human_readable (lines, buf, 1, 1));
111       space = " ";
112     }
113   if (print_words)
114     {
115       printf ("%s%7s", space, human_readable (words, buf, 1, 1));
116       space = " ";
117     }
118   if (print_chars)
119     {
120       printf ("%s%7s", space, human_readable (chars, buf, 1, 1));
121       space = " ";
122     }
123   if (print_linelength)
124     {
125       printf ("%s%7s", space, human_readable (linelength, buf, 1, 1));
126     }
127   if (*file)
128     printf (" %s", file);
129   putchar ('\n');
130 }
131
132 static void
133 wc (int fd, const char *file)
134 {
135   char buf[BUFFER_SIZE + 1];
136   ssize_t bytes_read;
137   int in_word = 0;
138   uintmax_t lines, words, chars, linelength;
139
140   lines = words = chars = linelength = 0;
141
142   /* We need binary input, since `wc' relies on `lseek' and byte counts.  */
143   SET_BINARY (fd);
144
145   /* When counting only bytes, save some line- and word-counting
146      overhead.  If FD is a `regular' Unix file, using lseek is enough
147      to get its `size' in bytes.  Otherwise, read blocks of BUFFER_SIZE
148      bytes at a time until EOF.  Note that the `size' (number of bytes)
149      that wc reports is smaller than stats.st_size when the file is not
150      positioned at its beginning.  That's why the lseek calls below are
151      necessary.  For example the command
152      `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
153      should make wc report `0' bytes.  */
154
155   if (print_chars && !print_words && !print_lines && !print_linelength)
156     {
157       off_t current_pos, end_pos;
158       struct stat stats;
159
160       if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
161           && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
162           && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
163         {
164           off_t diff;
165           /* Be careful here.  The current position may actually be
166              beyond the end of the file.  As in the example above.  */
167           chars = (diff = end_pos - current_pos) < 0 ? 0 : diff;
168         }
169       else
170         {
171           while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
172             {
173               chars += bytes_read;
174             }
175           if (bytes_read < 0)
176             {
177               error (0, errno, "%s", file);
178               exit_status = 1;
179             }
180         }
181     }
182   else if (!print_words && !print_linelength)
183     {
184       /* Use a separate loop when counting only lines or lines and bytes --
185          but not words.  */
186       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
187         {
188           register char *p = buf;
189
190           while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
191             {
192               ++p;
193               ++lines;
194             }
195           chars += bytes_read;
196         }
197       if (bytes_read < 0)
198         {
199           error (0, errno, "%s", file);
200           exit_status = 1;
201         }
202     }
203   else
204     {
205       uintmax_t linepos = 0;
206
207       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
208         {
209           const char *p = buf;
210
211           chars += bytes_read;
212           do
213             {
214               switch (*p++)
215                 {
216                 case '\n':
217                   lines++;
218                   /* Fall through. */
219                 case '\r':
220                 case '\f':
221                   if (linepos > linelength)
222                     linelength = linepos;
223                   linepos = 0;
224                   goto word_separator;
225                 case '\t':
226                   linepos += 8 - (linepos % 8);
227                   goto word_separator;
228                 case ' ':
229                   linepos++;
230                   /* Fall through. */
231                 case '\v':
232                 word_separator:
233                   if (in_word)
234                     {
235                       in_word = 0;
236                       words++;
237                     }
238                   break;
239                 default:
240                   linepos++;
241                   in_word = 1;
242                   break;
243                 }
244             }
245           while (--bytes_read);
246         }
247       if (bytes_read < 0)
248         {
249           error (0, errno, "%s", file);
250           exit_status = 1;
251         }
252       if (linepos > linelength)
253         linelength = linepos;
254       if (in_word)
255         words++;
256     }
257
258   write_counts (lines, words, chars, linelength, file);
259   total_lines += lines;
260   total_words += words;
261   total_chars += chars;
262   if (linelength > max_line_length)
263     max_line_length = linelength;
264 }
265
266 static void
267 wc_file (const char *file)
268 {
269   if (STREQ (file, "-"))
270     {
271       have_read_stdin = 1;
272       wc (0, file);
273     }
274   else
275     {
276       int fd = open (file, O_RDONLY);
277       if (fd == -1)
278         {
279           error (0, errno, "%s", file);
280           exit_status = 1;
281           return;
282         }
283       wc (fd, file);
284       if (close (fd))
285         {
286           error (0, errno, "%s", file);
287           exit_status = 1;
288         }
289     }
290 }
291
292 int
293 main (int argc, char **argv)
294 {
295   int optc;
296   int nfiles;
297
298   program_name = argv[0];
299   setlocale (LC_ALL, "");
300   bindtextdomain (PACKAGE, LOCALEDIR);
301   textdomain (PACKAGE);
302
303   parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
304                       "Paul Rubin and David MacKenzie", usage);
305
306   exit_status = 0;
307   print_lines = print_words = print_chars = print_linelength = 0;
308   total_lines = total_words = total_chars = max_line_length = 0;
309
310   while ((optc = getopt_long (argc, argv, "clLw", longopts, NULL)) != -1)
311     switch (optc)
312       {
313       case 0:
314         break;
315
316       case 'c':
317         print_chars = 1;
318         break;
319
320       case 'l':
321         print_lines = 1;
322         break;
323
324       case 'w':
325         print_words = 1;
326         break;
327
328       case 'L':
329         print_linelength = 1;
330         break;
331
332       default:
333         usage (1);
334       }
335
336   if (print_lines + print_words + print_chars + print_linelength == 0)
337     print_lines = print_words = print_chars = 1;
338
339   nfiles = argc - optind;
340
341   if (nfiles == 0)
342     {
343       have_read_stdin = 1;
344       wc (0, "");
345     }
346   else
347     {
348       for (; optind < argc; ++optind)
349         wc_file (argv[optind]);
350
351       if (nfiles > 1)
352         write_counts (total_lines, total_words, total_chars, max_line_length,
353                       _("total"));
354     }
355
356   if (have_read_stdin && close (0))
357     error (EXIT_FAILURE, errno, "-");
358
359   exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
360 }