1 /* wc - print the number of bytes, words, and lines in files
2 Copyright (C) 85, 91, 1995-1999 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>
32 #include "long-options.h"
33 #include "safe-read.h"
35 /* The official name of this program (e.g., no `g' prefix). */
36 #define PROGRAM_NAME "wc"
38 /* Size of atomic reads. */
39 #define BUFFER_SIZE (16 * 1024)
41 /* The name this program was run with. */
44 /* Cumulative number of lines, words, and chars in all files so far.
45 max_line_length is the maximum over all files processed so far. */
46 static uintmax_t total_lines;
47 static uintmax_t total_words;
48 static uintmax_t total_chars;
49 static uintmax_t max_line_length;
51 /* Which counts to print. */
52 static int print_lines, print_words, print_chars, print_linelength;
54 /* Nonzero if we have ever read the standard input. */
55 static int have_read_stdin;
57 /* The error code to return to the system. */
58 static int exit_status;
60 static struct option const longopts[] =
62 {"bytes", no_argument, NULL, 'c'},
63 {"chars", no_argument, NULL, 'c'},
64 {"lines", no_argument, NULL, 'l'},
65 {"words", no_argument, NULL, 'w'},
66 {"max-line-length", no_argument, NULL, 'L'},
74 fprintf (stderr, _("Try `%s --help' for more information.\n"),
79 Usage: %s [OPTION]... [FILE]...\n\
83 Print line, word, and byte counts for each FILE, and a total line if\n\
84 more than one FILE is specified. With no FILE, or when FILE is -,\n\
85 read standard input.\n\
86 -c, --bytes, --chars print the byte counts\n\
87 -l, --lines print the newline counts\n\
88 -L, --max-line-length print the length of the longest line\n\
89 -w, --words print the word counts\n\
90 --help display this help and exit\n\
91 --version output version information and exit\n\
93 puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
95 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
99 write_counts (uintmax_t lines,
102 uintmax_t linelength,
105 char buf[LONGEST_HUMAN_READABLE + 1];
106 char const *space = "";
110 printf ("%7s", human_readable (lines, buf, 1, 1));
115 printf ("%s%7s", space, human_readable (words, buf, 1, 1));
120 printf ("%s%7s", space, human_readable (chars, buf, 1, 1));
123 if (print_linelength)
125 printf ("%s%7s", space, human_readable (linelength, buf, 1, 1));
128 printf (" %s", file);
133 wc (int fd, const char *file)
135 char buf[BUFFER_SIZE + 1];
138 uintmax_t lines, words, chars, linelength;
140 lines = words = chars = linelength = 0;
142 /* We need binary input, since `wc' relies on `lseek' and byte counts. */
145 /* When counting only bytes, save some line- and word-counting
146 overhead. If FD is a `regular' Unix file, using lseek is enough
147 to get its `size' in bytes. Otherwise, read blocks of BUFFER_SIZE
148 bytes at a time until EOF. Note that the `size' (number of bytes)
149 that wc reports is smaller than stats.st_size when the file is not
150 positioned at its beginning. That's why the lseek calls below are
151 necessary. For example the command
152 `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
153 should make wc report `0' bytes. */
155 if (print_chars && !print_words && !print_lines && !print_linelength)
157 off_t current_pos, end_pos;
160 if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
161 && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
162 && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
165 /* Be careful here. The current position may actually be
166 beyond the end of the file. As in the example above. */
167 chars = (diff = end_pos - current_pos) < 0 ? 0 : diff;
171 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
177 error (0, errno, "%s", file);
182 else if (!print_words && !print_linelength)
184 /* Use a separate loop when counting only lines or lines and bytes --
186 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
188 register char *p = buf;
190 while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
199 error (0, errno, "%s", file);
205 uintmax_t linepos = 0;
207 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
221 if (linepos > linelength)
222 linelength = linepos;
226 linepos += 8 - (linepos % 8);
245 while (--bytes_read);
249 error (0, errno, "%s", file);
252 if (linepos > linelength)
253 linelength = linepos;
258 write_counts (lines, words, chars, linelength, file);
259 total_lines += lines;
260 total_words += words;
261 total_chars += chars;
262 if (linelength > max_line_length)
263 max_line_length = linelength;
267 wc_file (const char *file)
269 if (STREQ (file, "-"))
276 int fd = open (file, O_RDONLY);
279 error (0, errno, "%s", file);
286 error (0, errno, "%s", file);
293 main (int argc, char **argv)
298 program_name = argv[0];
299 setlocale (LC_ALL, "");
300 bindtextdomain (PACKAGE, LOCALEDIR);
301 textdomain (PACKAGE);
303 parse_long_options (argc, argv, "wc", GNU_PACKAGE, VERSION,
304 "Paul Rubin and David MacKenzie", usage);
307 print_lines = print_words = print_chars = print_linelength = 0;
308 total_lines = total_words = total_chars = max_line_length = 0;
310 while ((optc = getopt_long (argc, argv, "clLw", longopts, NULL)) != -1)
329 print_linelength = 1;
336 if (print_lines + print_words + print_chars + print_linelength == 0)
337 print_lines = print_words = print_chars = 1;
339 nfiles = argc - optind;
348 for (; optind < argc; ++optind)
349 wc_file (argv[optind]);
352 write_counts (total_lines, total_words, total_chars, max_line_length,
356 if (have_read_stdin && close (0))
357 error (EXIT_FAILURE, errno, "-");
359 exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);