1 /* wc - print the number of bytes, words, and lines in files
2 Copyright (C) 85, 91, 1995-2002 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. */
25 #include <sys/types.h>
27 /* Get mbstate_t, mbrtowc(), wcwidth(). */
32 /* Get iswprint(), iswspace(). */
36 #if !defined iswprint && !HAVE_ISWPRINT
37 # define iswprint(wc) 1
39 #if !defined iswspace && !HAVE_ISWSPACE
40 # define iswspace(wc) \
41 ((wc) == (unsigned char) (wc) && ISSPACE ((unsigned char) (wc)))
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. */
52 #include "safe-read.h"
54 /* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
55 #if HAVE_MBRTOWC && defined mbstate_t
56 # define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
59 #ifndef HAVE_DECL_WCWIDTH
60 "this configure-time declaration test was not run"
62 #if !HAVE_DECL_WCWIDTH
63 extern int wcwidth ();
66 /* If wcwidth() doesn't exist, assume all printable characters have
68 #if !defined wcwidth && !HAVE_WCWIDTH
69 # define wcwidth(wc) ((wc) == 0 ? 0 : iswprint (wc) ? 1 : -1)
72 /* The official name of this program (e.g., no `g' prefix). */
73 #define PROGRAM_NAME "wc"
75 #define AUTHORS N_ ("Paul Rubin and David MacKenzie")
77 /* Size of atomic reads. */
78 #define BUFFER_SIZE (16 * 1024)
80 /* The name this program was run with. */
83 /* Cumulative number of lines, words, chars and bytes in all files so far.
84 max_line_length is the maximum over all files processed so far. */
85 static uintmax_t total_lines
;
86 static uintmax_t total_words
;
87 static uintmax_t total_chars
;
88 static uintmax_t total_bytes
;
89 static uintmax_t max_line_length
;
91 /* Which counts to print. */
92 static int print_lines
, print_words
, print_chars
, print_bytes
;
93 static int print_linelength
;
95 /* Nonzero if we have ever read the standard input. */
96 static int have_read_stdin
;
98 /* The error code to return to the system. */
99 static int exit_status
;
101 /* If nonzero, do not line up columns but instead separate numbers by
102 a single space as specified in Single Unix Specification and POSIX. */
103 static int posixly_correct
;
105 static struct option
const longopts
[] =
107 {"bytes", no_argument
, NULL
, 'c'},
108 {"chars", no_argument
, NULL
, 'm'},
109 {"lines", no_argument
, NULL
, 'l'},
110 {"words", no_argument
, NULL
, 'w'},
111 {"max-line-length", no_argument
, NULL
, 'L'},
112 {GETOPT_HELP_OPTION_DECL
},
113 {GETOPT_VERSION_OPTION_DECL
},
121 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
126 Usage: %s [OPTION]... [FILE]...\n\
130 Print byte, word, and newline counts for each FILE, and a total line if\n\
131 more than one FILE is specified. With no FILE, or when FILE is -,\n\
132 read standard input.\n\
133 -c, --bytes print the byte counts\n\
134 -m, --chars print the character counts\n\
135 -l, --lines print the newline counts\n\
138 -L, --max-line-length print the length of the longest line\n\
139 -w, --words print the word counts\n\
141 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
142 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
143 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
145 exit (status
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);
149 write_counts (uintmax_t lines
,
153 uintmax_t linelength
,
156 char buf
[INT_BUFSIZE_BOUND (uintmax_t)];
157 char const *space
= "";
158 char const *format_int
= (posixly_correct
? "%s" : "%7s");
159 char const *format_sp_int
= (posixly_correct
? "%s%s" : "%s%7s");
163 printf (format_int
, umaxtostr (lines
, buf
));
168 printf (format_sp_int
, space
, umaxtostr (words
, buf
));
173 printf (format_sp_int
, space
, umaxtostr (chars
, buf
));
178 printf (format_sp_int
, space
, umaxtostr (bytes
, buf
));
181 if (print_linelength
)
183 printf (format_sp_int
, space
, umaxtostr (linelength
, buf
));
186 printf (" %s", file
);
191 wc (int fd
, const char *file
)
193 char buf
[BUFFER_SIZE
+ 1];
195 uintmax_t lines
, words
, chars
, bytes
, linelength
;
196 int count_bytes
, count_chars
, count_complicated
;
198 lines
= words
= chars
= bytes
= linelength
= 0;
200 /* If in the current locale, chars are equivalent to bytes, we prefer
201 counting bytes, because that's easier. */
202 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
205 count_bytes
= print_bytes
;
206 count_chars
= print_chars
;
211 count_bytes
= print_bytes
+ print_chars
;
214 count_complicated
= print_words
+ print_linelength
;
216 /* We need binary input, since `wc' relies on `lseek' and byte counts. */
219 /* When counting only bytes, save some line- and word-counting
220 overhead. If FD is a `regular' Unix file, using lseek is enough
221 to get its `size' in bytes. Otherwise, read blocks of BUFFER_SIZE
222 bytes at a time until EOF. Note that the `size' (number of bytes)
223 that wc reports is smaller than stats.st_size when the file is not
224 positioned at its beginning. That's why the lseek calls below are
225 necessary. For example the command
226 `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
227 should make wc report `0' bytes. */
229 if (count_bytes
&& !count_chars
&& !print_lines
&& !count_complicated
)
231 off_t current_pos
, end_pos
;
234 if (fstat (fd
, &stats
) == 0 && S_ISREG (stats
.st_mode
)
235 && (current_pos
= lseek (fd
, (off_t
) 0, SEEK_CUR
)) != -1
236 && (end_pos
= lseek (fd
, (off_t
) 0, SEEK_END
)) != -1)
239 /* Be careful here. The current position may actually be
240 beyond the end of the file. As in the example above. */
241 bytes
= (diff
= end_pos
- current_pos
) < 0 ? 0 : diff
;
245 while ((bytes_read
= safe_read (fd
, buf
, BUFFER_SIZE
)) > 0)
247 if (bytes_read
== SAFE_READ_ERROR
)
249 error (0, errno
, "%s", file
);
257 else if (!count_chars
&& !count_complicated
)
259 /* Use a separate loop when counting only lines or lines and bytes --
260 but not chars or words. */
261 while ((bytes_read
= safe_read (fd
, buf
, BUFFER_SIZE
)) > 0)
263 register char *p
= buf
;
265 if (bytes_read
== SAFE_READ_ERROR
)
267 error (0, errno
, "%s", file
);
272 while ((p
= memchr (p
, '\n', (buf
+ bytes_read
) - p
)))
280 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
281 # define SUPPORT_OLD_MBRTOWC 1
282 else if (MB_CUR_MAX
> 1)
285 uintmax_t linepos
= 0;
287 uintmax_t last_error_line
= 0;
288 int last_error_errno
= 0;
289 # if SUPPORT_OLD_MBRTOWC
290 /* Back-up the state before each multibyte character conversion and
291 move the last incomplete character of the buffer to the front
292 of the buffer. This is needed because we don't know whether
293 the `mbrtowc' function updates the state when it returns -2, -
294 this is the ISO C 99 and glibc-2.2 behaviour - or not - amended
295 ANSI C, glibc-2.1 and Solaris 2.7 behaviour. We don't have an
296 autoconf test for this, yet. */
297 size_t prev
= 0; /* number of bytes carried over from previous round */
299 const size_t prev
= 0;
302 memset (&state
, 0, sizeof (mbstate_t));
303 while ((bytes_read
= safe_read (fd
, buf
+ prev
, BUFFER_SIZE
- prev
)) > 0)
306 # if SUPPORT_OLD_MBRTOWC
307 mbstate_t backup_state
;
309 if (bytes_read
== SAFE_READ_ERROR
)
311 error (0, errno
, "%s", file
);
324 # if SUPPORT_OLD_MBRTOWC
325 backup_state
= state
;
327 n
= mbrtowc (&wide_char
, p
, bytes_read
, &state
);
328 if (n
== (size_t) -2)
330 # if SUPPORT_OLD_MBRTOWC
331 state
= backup_state
;
335 if (n
== (size_t) -1)
337 /* Signal repeated errors only once per line. */
338 if (!(lines
+ 1 == last_error_line
339 && errno
== last_error_errno
))
341 char line_number_buf
[INT_BUFSIZE_BOUND (uintmax_t)];
342 last_error_line
= lines
+ 1;
343 last_error_errno
= errno
;
344 error (0, errno
, "%s:%s", file
,
345 umaxtostr (last_error_line
, line_number_buf
));
367 if (linepos
> linelength
)
368 linelength
= linepos
;
370 goto mb_word_separator
;
372 linepos
+= 8 - (linepos
% 8);
373 goto mb_word_separator
;
386 if (iswprint (wide_char
))
388 int width
= wcwidth (wide_char
);
391 if (iswspace (wide_char
))
392 goto mb_word_separator
;
399 while (bytes_read
> 0);
401 # if SUPPORT_OLD_MBRTOWC
404 if (bytes_read
== BUFFER_SIZE
)
406 /* Encountered a very long redundant shift sequence. */
410 memmove (buf
, p
, bytes_read
);
415 if (linepos
> linelength
)
416 linelength
= linepos
;
424 uintmax_t linepos
= 0;
426 while ((bytes_read
= safe_read (fd
, buf
, BUFFER_SIZE
)) > 0)
429 if (bytes_read
== SAFE_READ_ERROR
)
431 error (0, errno
, "%s", file
);
446 if (linepos
> linelength
)
447 linelength
= linepos
;
451 linepos
+= 8 - (linepos
% 8);
465 if (ISPRINT ((unsigned char) p
[-1]))
468 if (ISSPACE ((unsigned char) p
[-1]))
475 while (--bytes_read
);
477 if (linepos
> linelength
)
478 linelength
= linepos
;
483 if (count_chars
< print_chars
)
486 write_counts (lines
, words
, chars
, bytes
, linelength
, file
);
487 total_lines
+= lines
;
488 total_words
+= words
;
489 total_chars
+= chars
;
490 total_bytes
+= bytes
;
491 if (linelength
> max_line_length
)
492 max_line_length
= linelength
;
496 wc_file (const char *file
)
498 if (STREQ (file
, "-"))
505 int fd
= open (file
, O_RDONLY
);
508 error (0, errno
, "%s", file
);
515 error (0, errno
, "%s", file
);
522 main (int argc
, char **argv
)
527 program_name
= argv
[0];
528 setlocale (LC_ALL
, "");
529 bindtextdomain (PACKAGE
, LOCALEDIR
);
530 textdomain (PACKAGE
);
532 atexit (close_stdout
);
535 posixly_correct
= (getenv ("POSIXLY_CORRECT") != NULL
);
536 print_lines
= print_words
= print_chars
= print_bytes
= print_linelength
= 0;
537 total_lines
= total_words
= total_chars
= total_bytes
= max_line_length
= 0;
539 while ((optc
= getopt_long (argc
, argv
, "clLmw", longopts
, NULL
)) != -1)
562 print_linelength
= 1;
565 case_GETOPT_HELP_CHAR
;
567 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
570 usage (EXIT_FAILURE
);
573 if (print_lines
+ print_words
+ print_chars
+ print_bytes
+ print_linelength
575 print_lines
= print_words
= print_bytes
= 1;
577 nfiles
= argc
- optind
;
586 for (; optind
< argc
; ++optind
)
587 wc_file (argv
[optind
]);
590 write_counts (total_lines
, total_words
, total_chars
, total_bytes
,
591 max_line_length
, _("total"));
594 if (have_read_stdin
&& close (STDIN_FILENO
) != 0)
595 error (EXIT_FAILURE
, errno
, "-");
597 exit (exit_status
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);