4bdffc4d813868a18545ba4447d27235987904cc
[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-2003 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
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) == (unsigned char) (wc) && ISSPACE ((unsigned char) (wc)))
42 #endif
43
44 /* Include this after wctype.h so that we `#undef' ISPRINT
45    (from Solaris's euc.h, from widec.h, from wctype.h) before
46    redefining and using it. */
47 #include "system.h"
48
49 #include "error.h"
50 #include "inttostr.h"
51 #include "safe-read.h"
52
53 /* Some systems, like BeOS, have multibyte encodings but lack mbstate_t.  */
54 #if HAVE_MBRTOWC && defined mbstate_t
55 # define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
56 #endif
57
58 #ifndef HAVE_DECL_WCWIDTH
59 "this configure-time declaration test was not run"
60 #endif
61 #if !HAVE_DECL_WCWIDTH
62 extern int wcwidth ();
63 #endif
64
65 /* If wcwidth() doesn't exist, assume all printable characters have
66    width 1.  */
67 #if !defined wcwidth && !HAVE_WCWIDTH
68 # define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1)
69 #endif
70
71 /* The official name of this program (e.g., no `g' prefix).  */
72 #define PROGRAM_NAME "wc"
73
74 #define WRITTEN_BY _("Written by Paul Rubin and David MacKenzie.")
75
76 /* Size of atomic reads. */
77 #define BUFFER_SIZE (16 * 1024)
78
79 /* The name this program was run with. */
80 char *program_name;
81
82 /* Cumulative number of lines, words, chars and bytes in all files so far.
83    max_line_length is the maximum over all files processed so far.  */
84 static uintmax_t total_lines;
85 static uintmax_t total_words;
86 static uintmax_t total_chars;
87 static uintmax_t total_bytes;
88 static uintmax_t max_line_length;
89
90 /* Which counts to print. */
91 static int print_lines, print_words, print_chars, print_bytes;
92 static int print_linelength;
93
94 /* The print width of each count.  */
95 static int number_width;
96
97 /* Nonzero if we have ever read the standard input. */
98 static int have_read_stdin;
99
100 /* The error code to return to the system. */
101 static int exit_status;
102
103 /* The result of calling fstat or stat on a file descriptor or file.  */
104 struct fstatus
105 {
106   /* If positive, fstat or stat has not been called yet.  Otherwise,
107      this is the value returned from fstat or stat.  */
108   int failed;
109
110   /* If FAILED is zero, this is the file's status.  */
111   struct stat st;
112 };
113
114
115 static struct option const longopts[] =
116 {
117   {"bytes", no_argument, NULL, 'c'},
118   {"chars", no_argument, NULL, 'm'},
119   {"lines", no_argument, NULL, 'l'},
120   {"words", no_argument, NULL, 'w'},
121   {"max-line-length", no_argument, NULL, 'L'},
122   {GETOPT_HELP_OPTION_DECL},
123   {GETOPT_VERSION_OPTION_DECL},
124   {NULL, 0, NULL, 0}
125 };
126
127 void
128 usage (int status)
129 {
130   if (status != 0)
131     fprintf (stderr, _("Try `%s --help' for more information.\n"),
132              program_name);
133   else
134     {
135       printf (_("\
136 Usage: %s [OPTION]... [FILE]...\n\
137 "),
138               program_name);
139       fputs (_("\
140 Print newline, word, and byte counts for each FILE, and a total line if\n\
141 more than one FILE is specified.  With no FILE, or when FILE is -,\n\
142 read standard input.\n\
143   -c, --bytes            print the byte counts\n\
144   -m, --chars            print the character counts\n\
145   -l, --lines            print the newline counts\n\
146 "), stdout);
147       fputs (_("\
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 == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
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 /* FILE_X is the name of the file (or NULL for standard input) that is
202    open on descriptor FD.  */
203 static void
204 wc (int fd, char const *file_x, struct fstatus *fstatus)
205 {
206   char buf[BUFFER_SIZE + 1];
207   size_t bytes_read;
208   uintmax_t lines, words, chars, bytes, linelength;
209   int count_bytes, count_chars, count_complicated;
210   char const *file = file_x ? file_x : _("standard input");
211
212   lines = words = chars = bytes = linelength = 0;
213
214   /* If in the current locale, chars are equivalent to bytes, we prefer
215      counting bytes, because that's easier.  */
216 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
217   if (MB_CUR_MAX > 1)
218     {
219       count_bytes = print_bytes;
220       count_chars = print_chars;
221     }
222   else
223 #endif
224     {
225       count_bytes = print_bytes + print_chars;
226       count_chars = 0;
227     }
228   count_complicated = print_words + print_linelength;
229
230   /* We need binary input, since `wc' relies on `lseek' and byte counts.  */
231   SET_BINARY (fd);
232
233   /* When counting only bytes, save some line- and word-counting
234      overhead.  If FD is a `regular' Unix file, using lseek is enough
235      to get its `size' in bytes.  Otherwise, read blocks of BUFFER_SIZE
236      bytes at a time until EOF.  Note that the `size' (number of bytes)
237      that wc reports is smaller than stats.st_size when the file is not
238      positioned at its beginning.  That's why the lseek calls below are
239      necessary.  For example the command
240      `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
241      should make wc report `0' bytes.  */
242
243   if (count_bytes && !count_chars && !print_lines && !count_complicated)
244     {
245       off_t current_pos, end_pos;
246
247       if (0 < fstatus->failed)
248         fstatus->failed = fstat (fd, &fstatus->st);
249
250       if (! fstatus->failed && S_ISREG (fstatus->st.st_mode)
251           && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
252           && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
253         {
254           /* Be careful here.  The current position may actually be
255              beyond the end of the file.  As in the example above.  */
256           bytes = end_pos < current_pos ? 0 : end_pos - current_pos;
257         }
258       else
259         {
260           while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
261             {
262               if (bytes_read == SAFE_READ_ERROR)
263                 {
264                   error (0, errno, "%s", file);
265                   exit_status = 1;
266                   break;
267                 }
268               bytes += bytes_read;
269             }
270         }
271     }
272   else if (!count_chars && !count_complicated)
273     {
274       /* Use a separate loop when counting only lines or lines and bytes --
275          but not chars or words.  */
276       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
277         {
278           register char *p = buf;
279
280           if (bytes_read == SAFE_READ_ERROR)
281             {
282               error (0, errno, "%s", file);
283               exit_status = 1;
284               break;
285             }
286
287           while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
288             {
289               ++p;
290               ++lines;
291             }
292           bytes += bytes_read;
293         }
294     }
295 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
296 # define SUPPORT_OLD_MBRTOWC 1
297   else if (MB_CUR_MAX > 1)
298     {
299       int in_word = 0;
300       uintmax_t linepos = 0;
301       mbstate_t state;
302       uintmax_t last_error_line = 0;
303       int last_error_errno = 0;
304 # if SUPPORT_OLD_MBRTOWC
305       /* Back-up the state before each multibyte character conversion and
306          move the last incomplete character of the buffer to the front
307          of the buffer.  This is needed because we don't know whether
308          the `mbrtowc' function updates the state when it returns -2, -
309          this is the ISO C 99 and glibc-2.2 behaviour - or not - amended
310          ANSI C, glibc-2.1 and Solaris 5.7 behaviour.  We don't have an
311          autoconf test for this, yet.  */
312       size_t prev = 0; /* number of bytes carried over from previous round */
313 # else
314       const size_t prev = 0;
315 # endif
316
317       memset (&state, 0, sizeof (mbstate_t));
318       while ((bytes_read = safe_read (fd, buf + prev, BUFFER_SIZE - prev)) > 0)
319         {
320           const char *p;
321 # if SUPPORT_OLD_MBRTOWC
322           mbstate_t backup_state;
323 # endif
324           if (bytes_read == SAFE_READ_ERROR)
325             {
326               error (0, errno, "%s", file);
327               exit_status = 1;
328               break;
329             }
330
331           bytes += bytes_read;
332           p = buf;
333           bytes_read += prev;
334           do
335             {
336               wchar_t wide_char;
337               size_t n;
338
339 # if SUPPORT_OLD_MBRTOWC
340               backup_state = state;
341 # endif
342               n = mbrtowc (&wide_char, p, bytes_read, &state);
343               if (n == (size_t) -2)
344                 {
345 # if SUPPORT_OLD_MBRTOWC
346                   state = backup_state;
347 # endif
348                   break;
349                 }
350               if (n == (size_t) -1)
351                 {
352                   /* Signal repeated errors only once per line.  */
353                   if (!(lines + 1 == last_error_line
354                         && errno == last_error_errno))
355                     {
356                       char line_number_buf[INT_BUFSIZE_BOUND (uintmax_t)];
357                       last_error_line = lines + 1;
358                       last_error_errno = errno;
359                       error (0, errno, "%s:%s", file,
360                              umaxtostr (last_error_line, line_number_buf));
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                       if (in_word)
395                         {
396                           in_word = 0;
397                           words++;
398                         }
399                       break;
400                     default:
401                       if (iswprint (wide_char))
402                         {
403                           int width = wcwidth (wide_char);
404                           if (width > 0)
405                             linepos += width;
406                           if (iswspace (wide_char))
407                             goto mb_word_separator;
408                           in_word = 1;
409                         }
410                       break;
411                     }
412                 }
413             }
414           while (bytes_read > 0);
415
416 # if SUPPORT_OLD_MBRTOWC
417           if (bytes_read > 0)
418             {
419               if (bytes_read == BUFFER_SIZE)
420                 {
421                   /* Encountered a very long redundant shift sequence.  */
422                   p++;
423                   bytes_read--;
424                 }
425               memmove (buf, p, bytes_read);
426             }
427           prev = bytes_read;
428 # endif
429         }
430       if (linepos > linelength)
431         linelength = linepos;
432       if (in_word)
433         words++;
434     }
435 #endif
436   else
437     {
438       int in_word = 0;
439       uintmax_t linepos = 0;
440
441       while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
442         {
443           const char *p = buf;
444           if (bytes_read == SAFE_READ_ERROR)
445             {
446               error (0, errno, "%s", file);
447               exit_status = 1;
448               break;
449             }
450
451           bytes += bytes_read;
452           do
453             {
454               switch (*p++)
455                 {
456                 case '\n':
457                   lines++;
458                   /* Fall through. */
459                 case '\r':
460                 case '\f':
461                   if (linepos > linelength)
462                     linelength = linepos;
463                   linepos = 0;
464                   goto word_separator;
465                 case '\t':
466                   linepos += 8 - (linepos % 8);
467                   goto word_separator;
468                 case ' ':
469                   linepos++;
470                   /* Fall through. */
471                 case '\v':
472                 word_separator:
473                   if (in_word)
474                     {
475                       in_word = 0;
476                       words++;
477                     }
478                   break;
479                 default:
480                   if (ISPRINT ((unsigned char) p[-1]))
481                     {
482                       linepos++;
483                       if (ISSPACE ((unsigned char) p[-1]))
484                         goto word_separator;
485                       in_word = 1;
486                     }
487                   break;
488                 }
489             }
490           while (--bytes_read);
491         }
492       if (linepos > linelength)
493         linelength = linepos;
494       if (in_word)
495         words++;
496     }
497
498   if (count_chars < print_chars)
499     chars = bytes;
500
501   write_counts (lines, words, chars, bytes, linelength, file_x);
502   total_lines += lines;
503   total_words += words;
504   total_chars += chars;
505   total_bytes += bytes;
506   if (linelength > max_line_length)
507     max_line_length = linelength;
508 }
509
510 static void
511 wc_file (char const *file, struct fstatus *fstatus)
512 {
513   if (STREQ (file, "-"))
514     {
515       have_read_stdin = 1;
516       wc (STDIN_FILENO, file, fstatus);
517     }
518   else
519     {
520       int fd = open (file, O_RDONLY);
521       if (fd == -1)
522         {
523           error (0, errno, "%s", file);
524           exit_status = 1;
525           return;
526         }
527       wc (fd, file, fstatus);
528       if (close (fd))
529         {
530           error (0, errno, "%s", file);
531           exit_status = 1;
532         }
533     }
534 }
535
536 /* Return the file status for the NFILES files addressed by FILE.
537    Optimize the case where only one number is printed, for just one
538    file; in that case we can use a print width of 1, so we don't need
539    to stat the file.  */
540
541 static struct fstatus *
542 get_input_fstatus (int nfiles, char * const *file)
543 {
544   struct fstatus *fstatus = xmalloc (nfiles * sizeof *fstatus);
545
546   if (nfiles == 1
547       && ((print_lines + print_words + print_chars
548            + print_bytes + print_linelength)
549           == 1))
550     fstatus[0].failed = 1;
551   else
552     {
553       int i;
554
555       for (i = 0; i < nfiles; i++)
556         fstatus[i].failed = (! file[i] || STREQ (file[i], "-")
557                              ? fstat (STDIN_FILENO, &fstatus[i].st)
558                              : stat (file[i], &fstatus[i].st));
559     }
560
561   return fstatus;
562 }
563
564 /* Return a print width suitable for the NFILES files whose status is
565    recorded in FSTATUS.  Optimize the same special case that
566    get_input_fstatus optimizes.  */
567
568 static int
569 compute_number_width (int nfiles, struct fstatus const *fstatus)
570 {
571   int width = 1;
572
573   if (fstatus[0].failed <= 0)
574     {
575       int minimum_width = 1;
576       uintmax_t regular_total = 0;
577       int i;
578
579       for (i = 0; i < nfiles; i++)
580         if (! fstatus[i].failed)
581           {
582             if (S_ISREG (fstatus[i].st.st_mode))
583               regular_total += fstatus[i].st.st_size;
584             else
585               minimum_width = 7;
586           }
587
588       for (; 10 <= regular_total; regular_total /= 10)
589         width++;
590       if (width < minimum_width)
591         width = minimum_width;
592     }
593
594   return width;
595 }
596
597
598 int
599 main (int argc, char **argv)
600 {
601   int optc;
602   int nfiles;
603   struct fstatus *fstatus;
604
605   initialize_main (&argc, &argv);
606   program_name = argv[0];
607   setlocale (LC_ALL, "");
608   bindtextdomain (PACKAGE, LOCALEDIR);
609   textdomain (PACKAGE);
610
611   atexit (close_stdout);
612
613   exit_status = 0;
614   print_lines = print_words = print_chars = print_bytes = print_linelength = 0;
615   total_lines = total_words = total_chars = total_bytes = max_line_length = 0;
616
617   while ((optc = getopt_long (argc, argv, "clLmw", longopts, NULL)) != -1)
618     switch (optc)
619       {
620       case 0:
621         break;
622
623       case 'c':
624         print_bytes = 1;
625         break;
626
627       case 'm':
628         print_chars = 1;
629         break;
630
631       case 'l':
632         print_lines = 1;
633         break;
634
635       case 'w':
636         print_words = 1;
637         break;
638
639       case 'L':
640         print_linelength = 1;
641         break;
642
643       case_GETOPT_HELP_CHAR;
644
645       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY);
646
647       default:
648         usage (EXIT_FAILURE);
649       }
650
651   if (print_lines + print_words + print_chars + print_bytes + print_linelength
652       == 0)
653     print_lines = print_words = print_bytes = 1;
654
655   nfiles = argc - optind;
656   nfiles += (nfiles == 0);
657
658   fstatus = get_input_fstatus (nfiles, argv + optind);
659   number_width = compute_number_width (nfiles, fstatus);
660
661   if (! argv[optind])
662     {
663       have_read_stdin = 1;
664       wc (STDIN_FILENO, NULL, &fstatus[0]);
665     }
666   else
667     {
668       int i;
669       for (i = 0; i < nfiles; i++)
670         wc_file (argv[optind + i], &fstatus[i]);
671
672       if (nfiles > 1)
673         write_counts (total_lines, total_words, total_chars, total_bytes,
674                       max_line_length, _("total"));
675     }
676
677   if (have_read_stdin && close (STDIN_FILENO) != 0)
678     error (EXIT_FAILURE, errno, "-");
679
680   exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
681 }