Adjust to today's renaming changes in system.h.
[platform/upstream/coreutils.git] / src / wc.c
1 /* wc - print the number of lines, words, and bytes in files
2    Copyright (C) 85, 91, 1995-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <sys/types.h>
26
27 /* Get mbstate_t, mbrtowc(), wcwidth().  */
28 #if HAVE_WCHAR_H
29 # include <wchar.h>
30 #endif
31
32 /* Get iswprint(), iswspace().  */
33 #if HAVE_WCTYPE_H
34 # include <wctype.h>
35 #endif
36 #if !defined iswprint && !HAVE_ISWPRINT
37 # define iswprint(wc) 1
38 #endif
39 #if !defined iswspace && !HAVE_ISWSPACE
40 # define iswspace(wc) \
41     ((wc) == to_uchar (wc) && isspace (to_uchar (wc)))
42 #endif
43
44 #include "system.h"
45 #include "error.h"
46 #include "inttostr.h"
47 #include "quote.h"
48 #include "readtokens0.h"
49 #include "safe-read.h"
50
51 #ifndef HAVE_DECL_WCWIDTH
52 "this configure-time declaration test was not run"
53 #endif
54 #if !HAVE_DECL_WCWIDTH
55 extern int wcwidth ();
56 #endif
57
58 /* If wcwidth() doesn't exist, assume all printable characters have
59    width 1.  */
60 #if !defined wcwidth && !HAVE_WCWIDTH
61 # define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1)
62 #endif
63
64 /* The official name of this program (e.g., no `g' prefix).  */
65 #define PROGRAM_NAME "wc"
66
67 #define AUTHORS "Paul Rubin", "David MacKenzie"
68
69 /* Size of atomic reads. */
70 #define BUFFER_SIZE (16 * 1024)
71
72 /* The name this program was run with. */
73 char *program_name;
74
75 /* Cumulative number of lines, words, chars and bytes in all files so far.
76    max_line_length is the maximum over all files processed so far.  */
77 static uintmax_t total_lines;
78 static uintmax_t total_words;
79 static uintmax_t total_chars;
80 static uintmax_t total_bytes;
81 static uintmax_t max_line_length;
82
83 /* Which counts to print. */
84 static bool print_lines, print_words, print_chars, print_bytes;
85 static bool print_linelength;
86
87 /* The print width of each count.  */
88 static int number_width;
89
90 /* True if we have ever read the standard input. */
91 static bool have_read_stdin;
92
93 /* The result of calling fstat or stat on a file descriptor or file.  */
94 struct fstatus
95 {
96   /* If positive, fstat or stat has not been called yet.  Otherwise,
97      this is the value returned from fstat or stat.  */
98   int failed;
99
100   /* If FAILED is zero, this is the file's status.  */
101   struct stat st;
102 };
103
104 /* For long options that have no equivalent short option, use a
105    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
106 enum
107 {
108   FILES0_FROM_OPTION = CHAR_MAX + 1
109 };
110
111 static struct option const longopts[] =
112 {
113   {"bytes", no_argument, NULL, 'c'},
114   {"chars", no_argument, NULL, 'm'},
115   {"lines", no_argument, NULL, 'l'},
116   {"words", no_argument, NULL, 'w'},
117   {"files0-from", required_argument, NULL, FILES0_FROM_OPTION},
118   {"max-line-length", no_argument, NULL, 'L'},
119   {GETOPT_HELP_OPTION_DECL},
120   {GETOPT_VERSION_OPTION_DECL},
121   {NULL, 0, NULL, 0}
122 };
123
124 void
125 usage (int status)
126 {
127   if (status != EXIT_SUCCESS)
128     fprintf (stderr, _("Try `%s --help' for more information.\n"),
129              program_name);
130   else
131     {
132       printf (_("\
133 Usage: %s [OPTION]... [FILE]...\n\
134   or:  %s [OPTION]... --files0-from=F\n\
135 "),
136               program_name, program_name);
137       fputs (_("\
138 Print newline, word, and byte counts for each FILE, and a total line if\n\
139 more than one FILE is specified.  With no FILE, or when FILE is -,\n\
140 read standard input.\n\
141   -c, --bytes            print the byte counts\n\
142   -m, --chars            print the character counts\n\
143   -l, --lines            print the newline counts\n\
144 "), stdout);
145       fputs (_("\
146       --files0-from=F    read input from the files specified by\n\
147                            NUL-terminated names in file F\n\
148   -L, --max-line-length  print the length of the longest line\n\
149   -w, --words            print the word counts\n\
150 "), stdout);
151       fputs (HELP_OPTION_DESCRIPTION, stdout);
152       fputs (VERSION_OPTION_DESCRIPTION, stdout);
153       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
154     }
155   exit (status);
156 }
157
158 /* FILE is the name of the file (or NULL for standard input)
159    associated with the specified counters.  */
160 static void
161 write_counts (uintmax_t lines,
162               uintmax_t words,
163               uintmax_t chars,
164               uintmax_t bytes,
165               uintmax_t linelength,
166               const char *file)
167 {
168   static char const format_sp_int[] = " %*s";
169   char const *format_int = format_sp_int + 1;
170   char buf[INT_BUFSIZE_BOUND (uintmax_t)];
171
172   if (print_lines)
173     {
174       printf (format_int, number_width, umaxtostr (lines, buf));
175       format_int = format_sp_int;
176     }
177   if (print_words)
178     {
179       printf (format_int, number_width, umaxtostr (words, buf));
180       format_int = format_sp_int;
181     }
182   if (print_chars)
183     {
184       printf (format_int, number_width, umaxtostr (chars, buf));
185       format_int = format_sp_int;
186     }
187   if (print_bytes)
188     {
189       printf (format_int, number_width, umaxtostr (bytes, buf));
190       format_int = format_sp_int;
191     }
192   if (print_linelength)
193     {
194       printf (format_int, number_width, umaxtostr (linelength, buf));
195     }
196   if (file)
197     printf (" %s", file);
198   putchar ('\n');
199 }
200
201 /* Count words.  FILE_X is the name of the file (or NULL for standard
202    input) that is open on descriptor FD.  *FSTATUS is its status.
203    Return true if successful.  */
204 static bool
205 wc (int fd, char const *file_x, struct fstatus *fstatus)
206 {
207   bool ok = true;
208   char buf[BUFFER_SIZE + 1];
209   size_t bytes_read;
210   uintmax_t lines, words, chars, bytes, linelength;
211   bool count_bytes, count_chars, count_complicated;
212   char const *file = file_x ? file_x : _("standard input");
213
214   lines = words = chars = bytes = linelength = 0;
215
216   /* If in the current locale, chars are equivalent to bytes, we prefer
217      counting bytes, because that's easier.  */
218 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
219   if (MB_CUR_MAX > 1)
220     {
221       count_bytes = print_bytes;
222       count_chars = print_chars;
223     }
224   else
225 #endif
226     {
227       count_bytes = print_bytes | print_chars;
228       count_chars = false;
229     }
230   count_complicated = print_words | print_linelength;
231
232   /* When counting only bytes, save some line- and word-counting
233      overhead.  If FD is a `regular' Unix file, using lseek is enough
234      to get its `size' in bytes.  Otherwise, read blocks of BUFFER_SIZE
235      bytes at a time until EOF.  Note that the `size' (number of bytes)
236      that wc reports is smaller than stats.st_size when the file is not
237      positioned at its beginning.  That's why the lseek calls below are
238      necessary.  For example the command
239      `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
240      should make wc report `0' bytes.  */
241
242   if (count_bytes & !count_chars & !print_lines & !count_complicated)
243     {
244       off_t current_pos, end_pos;
245
246       if (0 < fstatus->failed)
247         fstatus->failed = fstat (fd, &fstatus->st);
248
249       if (! fstatus->failed && S_ISREG (fstatus->st.st_mode)
250           && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
251           && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
252         {
253           /* Be careful here.  The current position may actually be
254              beyond the end of the file.  As in the example above.  */
255           bytes = end_pos < current_pos ? 0 : end_pos - current_pos;
256         }
257       else
258         {
259           while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
260             {
261               if (bytes_read == SAFE_READ_ERROR)
262                 {
263                   error (0, errno, "%s", file);
264                   ok = false;
265                   break;
266                 }
267               bytes += bytes_read;
268             }
269         }
270     }
271   else if (!count_chars & !count_complicated)
272     {
273       /* Use a separate loop when counting only lines or lines and bytes --
274          but not chars or words.  */
275       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
276         {
277           char *p = buf;
278
279           if (bytes_read == SAFE_READ_ERROR)
280             {
281               error (0, errno, "%s", file);
282               ok = false;
283               break;
284             }
285
286           while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
287             {
288               ++p;
289               ++lines;
290             }
291           bytes += bytes_read;
292         }
293     }
294 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
295 # define SUPPORT_OLD_MBRTOWC 1
296   else if (MB_CUR_MAX > 1)
297     {
298       bool in_word = false;
299       uintmax_t linepos = 0;
300       mbstate_t state;
301       uintmax_t last_error_line = 0;
302       int last_error_errno = 0;
303 # if SUPPORT_OLD_MBRTOWC
304       /* Back-up the state before each multibyte character conversion and
305          move the last incomplete character of the buffer to the front
306          of the buffer.  This is needed because we don't know whether
307          the `mbrtowc' function updates the state when it returns -2, -
308          this is the ISO C 99 and glibc-2.2 behaviour - or not - amended
309          ANSI C, glibc-2.1 and Solaris 5.7 behaviour.  We don't have an
310          autoconf test for this, yet.  */
311       size_t prev = 0; /* number of bytes carried over from previous round */
312 # else
313       const size_t prev = 0;
314 # endif
315
316       memset (&state, 0, sizeof (mbstate_t));
317       while ((bytes_read = safe_read (fd, buf + prev, BUFFER_SIZE - prev)) > 0)
318         {
319           const char *p;
320 # if SUPPORT_OLD_MBRTOWC
321           mbstate_t backup_state;
322 # endif
323           if (bytes_read == SAFE_READ_ERROR)
324             {
325               error (0, errno, "%s", file);
326               ok = false;
327               break;
328             }
329
330           bytes += bytes_read;
331           p = buf;
332           bytes_read += prev;
333           do
334             {
335               wchar_t wide_char;
336               size_t n;
337
338 # if SUPPORT_OLD_MBRTOWC
339               backup_state = state;
340 # endif
341               n = mbrtowc (&wide_char, p, bytes_read, &state);
342               if (n == (size_t) -2)
343                 {
344 # if SUPPORT_OLD_MBRTOWC
345                   state = backup_state;
346 # endif
347                   break;
348                 }
349               if (n == (size_t) -1)
350                 {
351                   /* Signal repeated errors only once per line.  */
352                   if (!(lines + 1 == last_error_line
353                         && errno == last_error_errno))
354                     {
355                       char line_number_buf[INT_BUFSIZE_BOUND (uintmax_t)];
356                       last_error_line = lines + 1;
357                       last_error_errno = errno;
358                       error (0, errno, "%s:%s", file,
359                              umaxtostr (last_error_line, line_number_buf));
360                       ok = false;
361                     }
362                   p++;
363                   bytes_read--;
364                 }
365               else
366                 {
367                   if (n == 0)
368                     {
369                       wide_char = 0;
370                       n = 1;
371                     }
372                   p += n;
373                   bytes_read -= n;
374                   chars++;
375                   switch (wide_char)
376                     {
377                     case '\n':
378                       lines++;
379                       /* Fall through. */
380                     case '\r':
381                     case '\f':
382                       if (linepos > linelength)
383                         linelength = linepos;
384                       linepos = 0;
385                       goto mb_word_separator;
386                     case '\t':
387                       linepos += 8 - (linepos % 8);
388                       goto mb_word_separator;
389                     case ' ':
390                       linepos++;
391                       /* Fall through. */
392                     case '\v':
393                     mb_word_separator:
394                       words += in_word;
395                       in_word = false;
396                       break;
397                     default:
398                       if (iswprint (wide_char))
399                         {
400                           int width = wcwidth (wide_char);
401                           if (width > 0)
402                             linepos += width;
403                           if (iswspace (wide_char))
404                             goto mb_word_separator;
405                           in_word = true;
406                         }
407                       break;
408                     }
409                 }
410             }
411           while (bytes_read > 0);
412
413 # if SUPPORT_OLD_MBRTOWC
414           if (bytes_read > 0)
415             {
416               if (bytes_read == BUFFER_SIZE)
417                 {
418                   /* Encountered a very long redundant shift sequence.  */
419                   p++;
420                   bytes_read--;
421                 }
422               memmove (buf, p, bytes_read);
423             }
424           prev = bytes_read;
425 # endif
426         }
427       if (linepos > linelength)
428         linelength = linepos;
429       words += in_word;
430     }
431 #endif
432   else
433     {
434       bool in_word = false;
435       uintmax_t linepos = 0;
436
437       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
438         {
439           const char *p = buf;
440           if (bytes_read == SAFE_READ_ERROR)
441             {
442               error (0, errno, "%s", file);
443               ok = false;
444               break;
445             }
446
447           bytes += bytes_read;
448           do
449             {
450               switch (*p++)
451                 {
452                 case '\n':
453                   lines++;
454                   /* Fall through. */
455                 case '\r':
456                 case '\f':
457                   if (linepos > linelength)
458                     linelength = linepos;
459                   linepos = 0;
460                   goto word_separator;
461                 case '\t':
462                   linepos += 8 - (linepos % 8);
463                   goto word_separator;
464                 case ' ':
465                   linepos++;
466                   /* Fall through. */
467                 case '\v':
468                 word_separator:
469                   words += in_word;
470                   in_word = false;
471                   break;
472                 default:
473                   if (isprint (to_uchar (p[-1])))
474                     {
475                       linepos++;
476                       if (isspace (to_uchar (p[-1])))
477                         goto word_separator;
478                       in_word = true;
479                     }
480                   break;
481                 }
482             }
483           while (--bytes_read);
484         }
485       if (linepos > linelength)
486         linelength = linepos;
487       words += in_word;
488     }
489
490   if (count_chars < print_chars)
491     chars = bytes;
492
493   write_counts (lines, words, chars, bytes, linelength, file_x);
494   total_lines += lines;
495   total_words += words;
496   total_chars += chars;
497   total_bytes += bytes;
498   if (linelength > max_line_length)
499     max_line_length = linelength;
500
501   return ok;
502 }
503
504 static bool
505 wc_file (char const *file, struct fstatus *fstatus)
506 {
507   if (! file || STREQ (file, "-"))
508     {
509       have_read_stdin = true;
510       if (O_BINARY && ! isatty (STDIN_FILENO))
511         freopen (NULL, "rb", stdin);
512       return wc (STDIN_FILENO, file, fstatus);
513     }
514   else
515     {
516       int fd = open (file, O_RDONLY | O_BINARY);
517       if (fd == -1)
518         {
519           error (0, errno, "%s", file);
520           return false;
521         }
522       else
523         {
524           bool ok = wc (fd, file, fstatus);
525           if (close (fd) != 0)
526             {
527               error (0, errno, "%s", file);
528               return false;
529             }
530           return ok;
531         }
532     }
533 }
534
535 /* Return the file status for the NFILES files addressed by FILE.
536    Optimize the case where only one number is printed, for just one
537    file; in that case we can use a print width of 1, so we don't need
538    to stat the file.  */
539
540 static struct fstatus *
541 get_input_fstatus (int nfiles, char * const *file)
542 {
543   struct fstatus *fstatus = xnmalloc (nfiles, sizeof *fstatus);
544
545   if (nfiles == 1
546       && ((print_lines + print_words + print_chars
547            + print_bytes + print_linelength)
548           == 1))
549     fstatus[0].failed = 1;
550   else
551     {
552       int i;
553
554       for (i = 0; i < nfiles; i++)
555         fstatus[i].failed = (! file[i] || STREQ (file[i], "-")
556                              ? fstat (STDIN_FILENO, &fstatus[i].st)
557                              : stat (file[i], &fstatus[i].st));
558     }
559
560   return fstatus;
561 }
562
563 /* Return a print width suitable for the NFILES files whose status is
564    recorded in FSTATUS.  Optimize the same special case that
565    get_input_fstatus optimizes.  */
566
567 static int
568 compute_number_width (int nfiles, struct fstatus const *fstatus)
569 {
570   int width = 1;
571
572   if (0 < nfiles && fstatus[0].failed <= 0)
573     {
574       int minimum_width = 1;
575       uintmax_t regular_total = 0;
576       int i;
577
578       for (i = 0; i < nfiles; i++)
579         if (! fstatus[i].failed)
580           {
581             if (S_ISREG (fstatus[i].st.st_mode))
582               regular_total += fstatus[i].st.st_size;
583             else
584               minimum_width = 7;
585           }
586
587       for (; 10 <= regular_total; regular_total /= 10)
588         width++;
589       if (width < minimum_width)
590         width = minimum_width;
591     }
592
593   return width;
594 }
595
596
597 int
598 main (int argc, char **argv)
599 {
600   int i;
601   bool ok;
602   int optc;
603   int nfiles;
604   char **files;
605   char *files_from = NULL;
606   struct fstatus *fstatus;
607   struct Tokens tok;
608
609   initialize_main (&argc, &argv);
610   program_name = argv[0];
611   setlocale (LC_ALL, "");
612   bindtextdomain (PACKAGE, LOCALEDIR);
613   textdomain (PACKAGE);
614
615   atexit (close_stdout);
616
617   print_lines = print_words = print_chars = print_bytes = false;
618   print_linelength = false;
619   total_lines = total_words = total_chars = total_bytes = max_line_length = 0;
620
621   while ((optc = getopt_long (argc, argv, "clLmw", longopts, NULL)) != -1)
622     switch (optc)
623       {
624       case 'c':
625         print_bytes = true;
626         break;
627
628       case 'm':
629         print_chars = true;
630         break;
631
632       case 'l':
633         print_lines = true;
634         break;
635
636       case 'w':
637         print_words = true;
638         break;
639
640       case 'L':
641         print_linelength = true;
642         break;
643
644       case FILES0_FROM_OPTION:
645         files_from = optarg;
646         break;
647
648       case_GETOPT_HELP_CHAR;
649
650       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
651
652       default:
653         usage (EXIT_FAILURE);
654       }
655
656   if (! (print_lines | print_words | print_chars | print_bytes
657          | print_linelength))
658     print_lines = print_words = print_bytes = true;
659
660   if (files_from)
661     {
662       FILE *stream;
663
664       /* When using --files0-from=F, you may not specify any files
665          on the command-line.  */
666       if (optind < argc)
667         {
668           error (0, 0, _("extra operand %s"), quote (argv[optind]));
669           fprintf (stderr, "%s\n",
670                    _("File operands cannot be combined with --files0-from."));
671           usage (EXIT_FAILURE);
672         }
673
674       if (STREQ (files_from, "-"))
675         stream = stdin;
676       else
677         {
678           stream = fopen (files_from, "r");
679           if (stream == NULL)
680             error (EXIT_FAILURE, errno, _("cannot open %s for reading"),
681                    quote (files_from));
682         }
683
684       readtokens0_init (&tok);
685
686       if (! readtokens0 (stream, &tok) || fclose (stream) != 0)
687         error (EXIT_FAILURE, 0, _("cannot read file names from %s"),
688                quote (files_from));
689
690       files = tok.tok;
691       nfiles = tok.n_tok;
692     }
693   else
694     {
695       static char *stdin_only[2];
696       files = (optind < argc ? argv + optind : stdin_only);
697       nfiles = (optind < argc ? argc - optind : 1);
698       stdin_only[0] = NULL;
699     }
700
701   fstatus = get_input_fstatus (nfiles, files);
702   number_width = compute_number_width (nfiles, fstatus);
703
704   ok = true;
705   for (i = 0; i < nfiles; i++)
706     {
707       if (files_from && STREQ (files_from, "-") && STREQ (files[i], "-"))
708         {
709           ok = false;
710           error (0, 0,
711                  _("when reading file names from stdin, "
712                    "no file name of %s allowed"),
713                  quote ("-"));
714           continue;
715         }
716       ok &= wc_file (files[i], &fstatus[i]);
717     }
718
719   if (1 < nfiles)
720     write_counts (total_lines, total_words, total_chars, total_bytes,
721                   max_line_length, _("total"));
722
723   free (fstatus);
724
725   if (have_read_stdin && close (STDIN_FILENO) != 0)
726     error (EXIT_FAILURE, errno, "-");
727
728   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
729 }