1 /* wc - print the number of bytes, words, and lines in files
2 Copyright (C) 85, 91, 95, 96, 1997 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
16 Foundation, 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>
29 /* Size of atomic reads. */
30 #define BUFFER_SIZE (16 * 1024)
34 /* The name this program was run with. */
37 /* Cumulative number of lines, words, and chars in all files so far. */
38 static unsigned long total_lines, total_words, total_chars;
40 /* Which counts to print. */
41 static int print_lines, print_words, print_chars;
43 /* Nonzero if we have ever read the standard input. */
44 static int have_read_stdin;
46 /* The error code to return to the system. */
47 static int exit_status;
49 /* If nonzero, display usage information and exit. */
52 /* If nonzero, print the version on standard output then exits. */
53 static int show_version;
55 static struct option const longopts[] =
57 {"bytes", no_argument, NULL, 'c'},
58 {"chars", no_argument, NULL, 'c'},
59 {"lines", no_argument, NULL, 'l'},
60 {"words", no_argument, NULL, 'w'},
61 {"help", no_argument, &show_help, 1},
62 {"version", no_argument, &show_version, 1},
70 fprintf (stderr, _("Try `%s --help' for more information.\n"),
75 Usage: %s [OPTION]... [FILE]...\n\
79 Print line, word, and byte counts for each FILE, and a total line if\n\
80 more than one FILE is specified. With no FILE, or when FILE is -,\n\
81 read standard input.\n\
82 -c, --bytes, --chars print the byte counts\n\
83 -l, --lines print the newline counts\n\
84 -w, --words print the word counts\n\
85 --help display this help and exit\n\
86 --version output version information and exit\n\
88 puts (_("\nReport bugs to <textutils-bugs@gnu.org>."));
90 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
94 write_counts (long unsigned int lines, long unsigned int words,
95 long unsigned int chars, const char *file)
98 printf ("%7lu", lines);
103 printf ("%7lu", words);
107 if (print_lines || print_words)
109 printf ("%7lu", chars);
112 printf (" %s", file);
117 wc (int fd, const char *file)
119 char buf[BUFFER_SIZE + 1];
120 register int bytes_read;
121 register int in_word = 0;
122 register unsigned long lines, words, chars;
124 lines = words = chars = 0;
126 /* When counting only bytes, save some line- and word-counting
127 overhead. If FD is a `regular' Unix file, using lseek is enough
128 to get its `size' in bytes. Otherwise, read blocks of BUFFER_SIZE
129 bytes at a time until EOF. Note that the `size' (number of bytes)
130 that wc reports is smaller than stats.st_size when the file is not
131 positioned at its beginning. That's why the lseek calls below are
132 necessary. For example the command
133 `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
134 should make wc report `0' bytes. */
136 if (print_chars && !print_words && !print_lines)
138 off_t current_pos, end_pos;
141 if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
142 && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
143 && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
146 /* Be careful here. The current position may actually be
147 beyond the end of the file. As in the example above. */
148 chars = (diff = end_pos - current_pos) < 0 ? 0 : diff;
152 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
158 error (0, errno, "%s", file);
163 else if (!print_words)
165 /* Use a separate loop when counting only lines or lines and bytes --
167 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
169 register char *p = buf;
171 while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
180 error (0, errno, "%s", file);
186 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
188 register char *p = buf;
214 while (--bytes_read);
218 error (0, errno, "%s", file);
225 write_counts (lines, words, chars, file);
226 total_lines += lines;
227 total_words += words;
228 total_chars += chars;
232 wc_file (const char *file)
234 if (!strcmp (file, "-"))
241 int fd = open (file, O_RDONLY);
244 error (0, errno, "%s", file);
251 error (0, errno, "%s", file);
258 main (int argc, char **argv)
263 program_name = argv[0];
264 setlocale (LC_ALL, "");
265 bindtextdomain (PACKAGE, LOCALEDIR);
266 textdomain (PACKAGE);
269 print_lines = print_words = print_chars = 0;
270 total_lines = total_words = total_chars = 0;
272 while ((optc = getopt_long (argc, argv, "clw", longopts, NULL)) != -1)
296 printf ("wc (%s) %s\n", GNU_PACKAGE, VERSION);
303 if (print_lines + print_words + print_chars == 0)
304 print_lines = print_words = print_chars = 1;
306 nfiles = argc - optind;
315 for (; optind < argc; ++optind)
316 wc_file (argv[optind]);
319 write_counts (total_lines, total_words, total_chars, _("total"));
322 if (have_read_stdin && close (0))
323 error (EXIT_FAILURE, errno, "-");
325 exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);