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