*** empty log message ***
[coreutils.git] / src / wc.c
blob00bb10c77783e8b228b459a97655b0d9755ae752
1 /* wc - print the number of bytes, words, and lines in files
2 Copyright (C) 85, 91, 1995-2001 Free Software Foundation, Inc.
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.
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.
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. */
18 /* Written by Paul Rubin, phr@ocf.berkeley.edu
19 and David MacKenzie, djm@gnu.ai.mit.edu. */
21 #include <config.h>
22 #if HAVE_INTTYPES_H
23 # include <inttypes.h>
24 #endif
26 #include <stdio.h>
27 #include <getopt.h>
28 #include <sys/types.h>
30 /* Get mbstate_t, mbrtowc(), wcwidth(). */
31 #if HAVE_WCHAR_H
32 # include <wchar.h>
33 #endif
35 /* Get iswprint(). */
36 #if HAVE_WCTYPE_H
37 # include <wctype.h>
38 #endif
39 #if !defined iswprint && !HAVE_ISWPRINT
40 # define iswprint(wc) 1
41 #endif
43 /* Include this after wctype.h so that we `#undef' ISPRINT
44 (from Solaris's euc.h, from widec.h, from wctype.h) before
45 redefining and using it. */
46 #include "system.h"
48 #include "closeout.h"
49 #include "error.h"
50 #include "human.h"
51 #include "safe-read.h"
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
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
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
71 /* The official name of this program (e.g., no `g' prefix). */
72 #define PROGRAM_NAME "wc"
74 #define AUTHORS "Paul Rubin and David MacKenzie"
76 /* Size of atomic reads. */
77 #define BUFFER_SIZE (16 * 1024)
79 /* The name this program was run with. */
80 char *program_name;
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;
90 /* Which counts to print. */
91 static int print_lines, print_words, print_chars, print_bytes;
92 static int print_linelength;
94 /* Nonzero if we have ever read the standard input. */
95 static int have_read_stdin;
97 /* The error code to return to the system. */
98 static int exit_status;
100 /* If nonzero, do not line up columns but instead separate numbers by
101 a single space as specified in Single Unix Specification and POSIX. */
102 static int posixly_correct;
104 static struct option const longopts[] =
106 {"bytes", no_argument, NULL, 'c'},
107 {"chars", no_argument, NULL, 'm'},
108 {"lines", no_argument, NULL, 'l'},
109 {"words", no_argument, NULL, 'w'},
110 {"max-line-length", no_argument, NULL, 'L'},
111 {GETOPT_HELP_OPTION_DECL},
112 {GETOPT_VERSION_OPTION_DECL},
113 {NULL, 0, NULL, 0}
116 void
117 usage (int status)
119 if (status != 0)
120 fprintf (stderr, _("Try `%s --help' for more information.\n"),
121 program_name);
122 else
124 printf (_("\
125 Usage: %s [OPTION]... [FILE]...\n\
127 program_name);
128 printf (_("\
129 Print line, word, and byte counts for each FILE, and a total line if\n\
130 more than one FILE is specified. With no FILE, or when FILE is -,\n\
131 read standard input.\n\
132 -c, --bytes print the byte counts\n\
133 -m, --chars print the character counts\n\
134 -l, --lines print the newline counts\n\
135 -L, --max-line-length print the length of the longest line\n\
136 -w, --words print the word counts\n\
137 --help display this help and exit\n\
138 --version output version information and exit\n\
139 "));
140 puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
142 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
145 static void
146 write_counts (uintmax_t lines,
147 uintmax_t words,
148 uintmax_t chars,
149 uintmax_t bytes,
150 uintmax_t linelength,
151 const char *file)
153 char buf[LONGEST_HUMAN_READABLE + 1];
154 char const *space = "";
155 char const *format_int = (posixly_correct ? "%s" : "%7s");
156 char const *format_sp_int = (posixly_correct ? "%s%s" : "%s%7s");
158 if (print_lines)
160 printf (format_int, human_readable (lines, buf, 1, 1));
161 space = " ";
163 if (print_words)
165 printf (format_sp_int, space, human_readable (words, buf, 1, 1));
166 space = " ";
168 if (print_chars)
170 printf (format_sp_int, space, human_readable (chars, buf, 1, 1));
171 space = " ";
173 if (print_bytes)
175 printf (format_sp_int, space, human_readable (bytes, buf, 1, 1));
176 space = " ";
178 if (print_linelength)
180 printf (format_sp_int, space, human_readable (linelength, buf, 1, 1));
182 if (*file)
183 printf (" %s", file);
184 putchar ('\n');
187 static void
188 wc (int fd, const char *file)
190 char buf[BUFFER_SIZE + 1];
191 ssize_t bytes_read;
192 uintmax_t lines, words, chars, bytes, linelength;
193 int count_bytes, count_chars, count_complicated;
195 lines = words = chars = bytes = linelength = 0;
197 /* If in the current locale, chars are equivalent to bytes, we prefer
198 counting bytes, because that's easier. */
199 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
200 if (MB_CUR_MAX > 1)
202 count_bytes = print_bytes;
203 count_chars = print_chars;
205 else
206 #endif
208 count_bytes = print_bytes + print_chars;
209 count_chars = 0;
211 count_complicated = print_words + print_linelength;
213 /* We need binary input, since `wc' relies on `lseek' and byte counts. */
214 SET_BINARY (fd);
216 /* When counting only bytes, save some line- and word-counting
217 overhead. If FD is a `regular' Unix file, using lseek is enough
218 to get its `size' in bytes. Otherwise, read blocks of BUFFER_SIZE
219 bytes at a time until EOF. Note that the `size' (number of bytes)
220 that wc reports is smaller than stats.st_size when the file is not
221 positioned at its beginning. That's why the lseek calls below are
222 necessary. For example the command
223 `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
224 should make wc report `0' bytes. */
226 if (count_bytes && !count_chars && !print_lines && !count_complicated)
228 off_t current_pos, end_pos;
229 struct stat stats;
231 if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
232 && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
233 && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
235 off_t diff;
236 /* Be careful here. The current position may actually be
237 beyond the end of the file. As in the example above. */
238 bytes = (diff = end_pos - current_pos) < 0 ? 0 : diff;
240 else
242 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
244 bytes += bytes_read;
246 if (bytes_read < 0)
248 error (0, errno, "%s", file);
249 exit_status = 1;
253 else if (!count_chars && !count_complicated)
255 /* Use a separate loop when counting only lines or lines and bytes --
256 but not chars or words. */
257 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
259 register char *p = buf;
261 while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
263 ++p;
264 ++lines;
266 bytes += bytes_read;
268 if (bytes_read < 0)
270 error (0, errno, "%s", file);
271 exit_status = 1;
274 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
275 # define SUPPORT_OLD_MBRTOWC 1
276 else if (MB_CUR_MAX > 1)
278 int in_word = 0;
279 uintmax_t linepos = 0;
280 mbstate_t state;
281 uintmax_t last_error_line = 0;
282 int last_error_errno = 0;
283 # if SUPPORT_OLD_MBRTOWC
284 /* Back-up the state before each multibyte character conversion and
285 move the last incomplete character of the buffer to the front
286 of the buffer. This is needed because we don't know whether
287 the `mbrtowc' function updates the state when it returns -2, -
288 this is the ISO C 99 and glibc-2.2 behaviour - or not - amended
289 ANSI C, glibc-2.1 and Solaris 2.7 behaviour. We don't have an
290 autoconf test for this, yet. */
291 int prev = 0; /* number of bytes carried over from previous round */
292 # else
293 const int prev = 0;
294 # endif
296 memset (&state, 0, sizeof (mbstate_t));
297 while ((bytes_read = safe_read (fd, buf + prev, BUFFER_SIZE - prev)) > 0)
299 const char *p;
300 # if SUPPORT_OLD_MBRTOWC
301 mbstate_t backup_state;
302 # endif
304 bytes += bytes_read;
305 p = buf;
306 bytes_read += prev;
309 wchar_t wide_char;
310 size_t n;
312 # if SUPPORT_OLD_MBRTOWC
313 backup_state = state;
314 # endif
315 n = mbrtowc (&wide_char, p, bytes_read, &state);
316 if (n == (size_t) -2)
318 # if SUPPORT_OLD_MBRTOWC
319 state = backup_state;
320 # endif
321 break;
323 if (n == (size_t) -1)
325 /* Signal repeated errors only once per line. */
326 if (!(lines + 1 == last_error_line
327 && errno == last_error_errno))
329 char hr_buf[LONGEST_HUMAN_READABLE + 1];
330 last_error_line = lines + 1;
331 last_error_errno = errno;
332 error (0, errno, "%s:%s", file,
333 human_readable (lines + 1, hr_buf, 1, 1));
335 p++;
336 bytes_read--;
338 else
340 if (n == 0)
342 wide_char = 0;
343 n = 1;
345 p += n;
346 bytes_read -= n;
347 chars++;
348 switch (wide_char)
350 case '\n':
351 lines++;
352 /* Fall through. */
353 case '\r':
354 case '\f':
355 if (linepos > linelength)
356 linelength = linepos;
357 linepos = 0;
358 goto mb_word_separator;
359 case '\t':
360 linepos += 8 - (linepos % 8);
361 goto mb_word_separator;
362 case ' ':
363 linepos++;
364 /* Fall through. */
365 case '\v':
366 mb_word_separator:
367 if (in_word)
369 in_word = 0;
370 words++;
372 break;
373 default:
374 if (iswprint (wide_char))
376 int width = wcwidth (wide_char);
377 if (width > 0)
378 linepos += width;
379 in_word = 1;
381 break;
385 while (bytes_read > 0);
387 # if SUPPORT_OLD_MBRTOWC
388 if (bytes_read > 0)
390 if (bytes_read == BUFFER_SIZE)
392 /* Encountered a very long redundant shift sequence. */
393 p++;
394 bytes_read--;
396 memmove (buf, p, bytes_read);
398 prev = bytes_read;
399 # endif
401 if (bytes_read < 0)
403 error (0, errno, "%s", file);
404 exit_status = 1;
406 if (linepos > linelength)
407 linelength = linepos;
408 if (in_word)
409 words++;
411 #endif
412 else
414 int in_word = 0;
415 uintmax_t linepos = 0;
417 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
419 const char *p = buf;
421 bytes += bytes_read;
424 switch (*p++)
426 case '\n':
427 lines++;
428 /* Fall through. */
429 case '\r':
430 case '\f':
431 if (linepos > linelength)
432 linelength = linepos;
433 linepos = 0;
434 goto word_separator;
435 case '\t':
436 linepos += 8 - (linepos % 8);
437 goto word_separator;
438 case ' ':
439 linepos++;
440 /* Fall through. */
441 case '\v':
442 word_separator:
443 if (in_word)
445 in_word = 0;
446 words++;
448 break;
449 default:
450 if (ISPRINT ((unsigned char) p[-1]))
452 linepos++;
453 in_word = 1;
455 break;
458 while (--bytes_read);
460 if (bytes_read < 0)
462 error (0, errno, "%s", file);
463 exit_status = 1;
465 if (linepos > linelength)
466 linelength = linepos;
467 if (in_word)
468 words++;
471 if (count_chars < print_chars)
472 chars = bytes;
474 write_counts (lines, words, chars, bytes, linelength, file);
475 total_lines += lines;
476 total_words += words;
477 total_chars += chars;
478 total_bytes += bytes;
479 if (linelength > max_line_length)
480 max_line_length = linelength;
483 static void
484 wc_file (const char *file)
486 if (STREQ (file, "-"))
488 have_read_stdin = 1;
489 wc (0, file);
491 else
493 int fd = open (file, O_RDONLY);
494 if (fd == -1)
496 error (0, errno, "%s", file);
497 exit_status = 1;
498 return;
500 wc (fd, file);
501 if (close (fd))
503 error (0, errno, "%s", file);
504 exit_status = 1;
510 main (int argc, char **argv)
512 int optc;
513 int nfiles;
515 program_name = argv[0];
516 setlocale (LC_ALL, "");
517 bindtextdomain (PACKAGE, LOCALEDIR);
518 textdomain (PACKAGE);
520 atexit (close_stdout);
522 exit_status = 0;
523 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
524 print_lines = print_words = print_chars = print_bytes = print_linelength = 0;
525 total_lines = total_words = total_chars = total_bytes = max_line_length = 0;
527 while ((optc = getopt_long (argc, argv, "clLmw", longopts, NULL)) != -1)
528 switch (optc)
530 case 0:
531 break;
533 case 'c':
534 print_bytes = 1;
535 break;
537 case 'm':
538 print_chars = 1;
539 break;
541 case 'l':
542 print_lines = 1;
543 break;
545 case 'w':
546 print_words = 1;
547 break;
549 case 'L':
550 print_linelength = 1;
551 break;
553 case_GETOPT_HELP_CHAR;
555 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
557 default:
558 usage (1);
561 if (print_lines + print_words + print_chars + print_bytes + print_linelength
562 == 0)
563 print_lines = print_words = print_bytes = 1;
565 nfiles = argc - optind;
567 if (nfiles == 0)
569 have_read_stdin = 1;
570 wc (0, "");
572 else
574 for (; optind < argc; ++optind)
575 wc_file (argv[optind]);
577 if (nfiles > 1)
578 write_counts (total_lines, total_words, total_chars, total_bytes,
579 max_line_length, _("total"));
582 if (have_read_stdin && close (0))
583 error (EXIT_FAILURE, errno, "-");
585 exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);