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)
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. */
23 # include <inttypes.h>
28 #include <sys/types.h>
30 /* Get mbstate_t, mbrtowc(), wcwidth(). */
39 #if !defined iswprint && !HAVE_ISWPRINT
40 # define iswprint(wc) 1
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. */
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)
58 #ifndef HAVE_DECL_WCWIDTH
59 "this configure-time declaration test was not run"
61 #if !HAVE_DECL_WCWIDTH
62 extern int wcwidth ();
65 /* If wcwidth() doesn't exist, assume all printable characters have
67 #if !defined wcwidth && !HAVE_WCWIDTH
68 # define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1)
71 /* The official name of this program (e.g., no `g' prefix). */
72 #define PROGRAM_NAME "wc"
74 #define AUTHORS N_ ("Paul Rubin and David MacKenzie")
76 /* Size of atomic reads. */
77 #define BUFFER_SIZE (16 * 1024)
79 /* The name this program was run with. */
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},
120 fprintf (stderr, _("Try `%s --help' for more information.\n"),
125 Usage: %s [OPTION]... [FILE]...\n\
129 Print newline, 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\
137 -L, --max-line-length print the length of the longest line\n\
138 -w, --words print the word counts\n\
139 --help display this help and exit\n\
140 --version output version information and exit\n\
142 puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
144 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
148 write_counts (uintmax_t lines,
152 uintmax_t linelength,
155 char buf[LONGEST_HUMAN_READABLE + 1];
156 char const *space = "";
157 char const *format_int = (posixly_correct ? "%s" : "%7s");
158 char const *format_sp_int = (posixly_correct ? "%s%s" : "%s%7s");
162 printf (format_int, human_readable (lines, buf, 1, 1));
167 printf (format_sp_int, space, human_readable (words, buf, 1, 1));
172 printf (format_sp_int, space, human_readable (chars, buf, 1, 1));
177 printf (format_sp_int, space, human_readable (bytes, buf, 1, 1));
180 if (print_linelength)
182 printf (format_sp_int, space, human_readable (linelength, buf, 1, 1));
185 printf (" %s", file);
190 wc (int fd, const char *file)
192 char buf[BUFFER_SIZE + 1];
194 uintmax_t lines, words, chars, bytes, linelength;
195 int count_bytes, count_chars, count_complicated;
197 lines = words = chars = bytes = linelength = 0;
199 /* If in the current locale, chars are equivalent to bytes, we prefer
200 counting bytes, because that's easier. */
201 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
204 count_bytes = print_bytes;
205 count_chars = print_chars;
210 count_bytes = print_bytes + print_chars;
213 count_complicated = print_words + print_linelength;
215 /* We need binary input, since `wc' relies on `lseek' and byte counts. */
218 /* When counting only bytes, save some line- and word-counting
219 overhead. If FD is a `regular' Unix file, using lseek is enough
220 to get its `size' in bytes. Otherwise, read blocks of BUFFER_SIZE
221 bytes at a time until EOF. Note that the `size' (number of bytes)
222 that wc reports is smaller than stats.st_size when the file is not
223 positioned at its beginning. That's why the lseek calls below are
224 necessary. For example the command
225 `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
226 should make wc report `0' bytes. */
228 if (count_bytes && !count_chars && !print_lines && !count_complicated)
230 off_t current_pos, end_pos;
233 if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
234 && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
235 && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
238 /* Be careful here. The current position may actually be
239 beyond the end of the file. As in the example above. */
240 bytes = (diff = end_pos - current_pos) < 0 ? 0 : diff;
244 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
250 error (0, errno, "%s", file);
255 else if (!count_chars && !count_complicated)
257 /* Use a separate loop when counting only lines or lines and bytes --
258 but not chars or words. */
259 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
261 register char *p = buf;
263 while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
272 error (0, errno, "%s", file);
276 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
277 # define SUPPORT_OLD_MBRTOWC 1
278 else if (MB_CUR_MAX > 1)
281 uintmax_t linepos = 0;
283 uintmax_t last_error_line = 0;
284 int last_error_errno = 0;
285 # if SUPPORT_OLD_MBRTOWC
286 /* Back-up the state before each multibyte character conversion and
287 move the last incomplete character of the buffer to the front
288 of the buffer. This is needed because we don't know whether
289 the `mbrtowc' function updates the state when it returns -2, -
290 this is the ISO C 99 and glibc-2.2 behaviour - or not - amended
291 ANSI C, glibc-2.1 and Solaris 2.7 behaviour. We don't have an
292 autoconf test for this, yet. */
293 int prev = 0; /* number of bytes carried over from previous round */
298 memset (&state, 0, sizeof (mbstate_t));
299 while ((bytes_read = safe_read (fd, buf + prev, BUFFER_SIZE - prev)) > 0)
302 # if SUPPORT_OLD_MBRTOWC
303 mbstate_t backup_state;
314 # if SUPPORT_OLD_MBRTOWC
315 backup_state = state;
317 n = mbrtowc (&wide_char, p, bytes_read, &state);
318 if (n == (size_t) -2)
320 # if SUPPORT_OLD_MBRTOWC
321 state = backup_state;
325 if (n == (size_t) -1)
327 /* Signal repeated errors only once per line. */
328 if (!(lines + 1 == last_error_line
329 && errno == last_error_errno))
331 char hr_buf[LONGEST_HUMAN_READABLE + 1];
332 last_error_line = lines + 1;
333 last_error_errno = errno;
334 error (0, errno, "%s:%s", file,
335 human_readable (lines + 1, hr_buf, 1, 1));
357 if (linepos > linelength)
358 linelength = linepos;
360 goto mb_word_separator;
362 linepos += 8 - (linepos % 8);
363 goto mb_word_separator;
376 if (iswprint (wide_char))
378 int width = wcwidth (wide_char);
387 while (bytes_read > 0);
389 # if SUPPORT_OLD_MBRTOWC
392 if (bytes_read == BUFFER_SIZE)
394 /* Encountered a very long redundant shift sequence. */
398 memmove (buf, p, bytes_read);
405 error (0, errno, "%s", file);
408 if (linepos > linelength)
409 linelength = linepos;
417 uintmax_t linepos = 0;
419 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
433 if (linepos > linelength)
434 linelength = linepos;
438 linepos += 8 - (linepos % 8);
452 if (ISPRINT ((unsigned char) p[-1]))
460 while (--bytes_read);
464 error (0, errno, "%s", file);
467 if (linepos > linelength)
468 linelength = linepos;
473 if (count_chars < print_chars)
476 write_counts (lines, words, chars, bytes, linelength, file);
477 total_lines += lines;
478 total_words += words;
479 total_chars += chars;
480 total_bytes += bytes;
481 if (linelength > max_line_length)
482 max_line_length = linelength;
486 wc_file (const char *file)
488 if (STREQ (file, "-"))
495 int fd = open (file, O_RDONLY);
498 error (0, errno, "%s", file);
505 error (0, errno, "%s", file);
512 main (int argc, char **argv)
517 program_name = argv[0];
518 setlocale (LC_ALL, "");
519 bindtextdomain (PACKAGE, LOCALEDIR);
520 textdomain (PACKAGE);
522 atexit (close_stdout);
525 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
526 print_lines = print_words = print_chars = print_bytes = print_linelength = 0;
527 total_lines = total_words = total_chars = total_bytes = max_line_length = 0;
529 while ((optc = getopt_long (argc, argv, "clLmw", longopts, NULL)) != -1)
552 print_linelength = 1;
555 case_GETOPT_HELP_CHAR;
557 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
563 if (print_lines + print_words + print_chars + print_bytes + print_linelength
565 print_lines = print_words = print_bytes = 1;
567 nfiles = argc - optind;
576 for (; optind < argc; ++optind)
577 wc_file (argv[optind]);
580 write_counts (total_lines, total_words, total_chars, total_bytes,
581 max_line_length, _("total"));
584 if (have_read_stdin && close (0))
585 error (EXIT_FAILURE, errno, "-");
587 exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);