*** empty log message ***
[coreutils.git] / src / wc.c
blobced5300dd9018e6e146954e53e821e0d02dbaaec
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)
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>
29 #include "system.h"
30 #include "error.h"
31 #include "human.h"
32 #include "safe-read.h"
34 /* The official name of this program (e.g., no `g' prefix). */
35 #define PROGRAM_NAME "wc"
37 #define AUTHORS "Paul Rubin and David MacKenzie"
39 /* Size of atomic reads. */
40 #define BUFFER_SIZE (16 * 1024)
42 /* The name this program was run with. */
43 char *program_name;
45 /* Cumulative number of lines, words, and chars in all files so far.
46 max_line_length is the maximum over all files processed so far. */
47 static uintmax_t total_lines;
48 static uintmax_t total_words;
49 static uintmax_t total_chars;
50 static uintmax_t max_line_length;
52 /* Which counts to print. */
53 static int print_lines, print_words, print_chars, print_linelength;
55 /* Nonzero if we have ever read the standard input. */
56 static int have_read_stdin;
58 /* The error code to return to the system. */
59 static int exit_status;
61 /* If nonzero, do not line up columns but instead separate numbers by
62 a single space as specified in Single Unix Specification and POSIX. */
63 static int posixly_correct;
65 static struct option const longopts[] =
67 {"bytes", no_argument, NULL, 'c'},
68 {"chars", no_argument, NULL, 'c'},
69 {"lines", no_argument, NULL, 'l'},
70 {"words", no_argument, NULL, 'w'},
71 {"max-line-length", no_argument, NULL, 'L'},
72 {GETOPT_HELP_OPTION_DECL},
73 {GETOPT_VERSION_OPTION_DECL},
74 {NULL, 0, NULL, 0}
77 void
78 usage (int status)
80 if (status != 0)
81 fprintf (stderr, _("Try `%s --help' for more information.\n"),
82 program_name);
83 else
85 printf (_("\
86 Usage: %s [OPTION]... [FILE]...\n\
87 "),
88 program_name);
89 printf (_("\
90 Print line, word, and byte counts for each FILE, and a total line if\n\
91 more than one FILE is specified. With no FILE, or when FILE is -,\n\
92 read standard input.\n\
93 -c, --bytes, --chars print the byte counts\n\
94 -l, --lines print the newline counts\n\
95 -L, --max-line-length print the length of the longest line\n\
96 -w, --words print the word counts\n\
97 --help display this help and exit\n\
98 --version output version information and exit\n\
99 "));
100 puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
102 exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
105 static void
106 write_counts (uintmax_t lines,
107 uintmax_t words,
108 uintmax_t chars,
109 uintmax_t linelength,
110 const char *file)
112 char buf[LONGEST_HUMAN_READABLE + 1];
113 char const *space = "";
114 char const *format_int = (posixly_correct ? "%s" : "%7s");
115 char const *format_sp_int = (posixly_correct ? "%s%s" : "%s%7s");
117 if (print_lines)
119 printf (format_int, human_readable (lines, buf, 1, 1));
120 space = " ";
122 if (print_words)
124 printf (format_sp_int, space, human_readable (words, buf, 1, 1));
125 space = " ";
127 if (print_chars)
129 printf (format_sp_int, space, human_readable (chars, buf, 1, 1));
130 space = " ";
132 if (print_linelength)
134 printf (format_sp_int, space, human_readable (linelength, buf, 1, 1));
136 if (*file)
137 printf (" %s", file);
138 putchar ('\n');
141 static void
142 wc (int fd, const char *file)
144 char buf[BUFFER_SIZE + 1];
145 ssize_t bytes_read;
146 int in_word = 0;
147 uintmax_t lines, words, chars, linelength;
149 lines = words = chars = linelength = 0;
151 /* We need binary input, since `wc' relies on `lseek' and byte counts. */
152 SET_BINARY (fd);
154 /* When counting only bytes, save some line- and word-counting
155 overhead. If FD is a `regular' Unix file, using lseek is enough
156 to get its `size' in bytes. Otherwise, read blocks of BUFFER_SIZE
157 bytes at a time until EOF. Note that the `size' (number of bytes)
158 that wc reports is smaller than stats.st_size when the file is not
159 positioned at its beginning. That's why the lseek calls below are
160 necessary. For example the command
161 `(dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group'
162 should make wc report `0' bytes. */
164 if (print_chars && !print_words && !print_lines && !print_linelength)
166 off_t current_pos, end_pos;
167 struct stat stats;
169 if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
170 && (current_pos = lseek (fd, (off_t) 0, SEEK_CUR)) != -1
171 && (end_pos = lseek (fd, (off_t) 0, SEEK_END)) != -1)
173 off_t diff;
174 /* Be careful here. The current position may actually be
175 beyond the end of the file. As in the example above. */
176 chars = (diff = end_pos - current_pos) < 0 ? 0 : diff;
178 else
180 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
182 chars += bytes_read;
184 if (bytes_read < 0)
186 error (0, errno, "%s", file);
187 exit_status = 1;
191 else if (!print_words && !print_linelength)
193 /* Use a separate loop when counting only lines or lines and bytes --
194 but not words. */
195 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
197 register char *p = buf;
199 while ((p = memchr (p, '\n', (buf + bytes_read) - p)))
201 ++p;
202 ++lines;
204 chars += bytes_read;
206 if (bytes_read < 0)
208 error (0, errno, "%s", file);
209 exit_status = 1;
212 else
214 uintmax_t linepos = 0;
216 while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)
218 const char *p = buf;
220 chars += bytes_read;
223 switch (*p++)
225 case '\n':
226 lines++;
227 /* Fall through. */
228 case '\r':
229 case '\f':
230 if (linepos > linelength)
231 linelength = linepos;
232 linepos = 0;
233 goto word_separator;
234 case '\t':
235 linepos += 8 - (linepos % 8);
236 goto word_separator;
237 case ' ':
238 linepos++;
239 /* Fall through. */
240 case '\v':
241 word_separator:
242 if (in_word)
244 in_word = 0;
245 words++;
247 break;
248 default:
249 linepos++;
250 in_word = 1;
251 break;
254 while (--bytes_read);
256 if (bytes_read < 0)
258 error (0, errno, "%s", file);
259 exit_status = 1;
261 if (linepos > linelength)
262 linelength = linepos;
263 if (in_word)
264 words++;
267 write_counts (lines, words, chars, linelength, file);
268 total_lines += lines;
269 total_words += words;
270 total_chars += chars;
271 if (linelength > max_line_length)
272 max_line_length = linelength;
275 static void
276 wc_file (const char *file)
278 if (STREQ (file, "-"))
280 have_read_stdin = 1;
281 wc (0, file);
283 else
285 int fd = open (file, O_RDONLY);
286 if (fd == -1)
288 error (0, errno, "%s", file);
289 exit_status = 1;
290 return;
292 wc (fd, file);
293 if (close (fd))
295 error (0, errno, "%s", file);
296 exit_status = 1;
302 main (int argc, char **argv)
304 int optc;
305 int nfiles;
307 program_name = argv[0];
308 setlocale (LC_ALL, "");
309 bindtextdomain (PACKAGE, LOCALEDIR);
310 textdomain (PACKAGE);
312 exit_status = 0;
313 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
314 print_lines = print_words = print_chars = print_linelength = 0;
315 total_lines = total_words = total_chars = max_line_length = 0;
317 while ((optc = getopt_long (argc, argv, "clLw", longopts, NULL)) != -1)
318 switch (optc)
320 case 0:
321 break;
323 case 'c':
324 print_chars = 1;
325 break;
327 case 'l':
328 print_lines = 1;
329 break;
331 case 'w':
332 print_words = 1;
333 break;
335 case 'L':
336 print_linelength = 1;
337 break;
339 case_GETOPT_HELP_CHAR;
341 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
343 default:
344 usage (1);
347 if (print_lines + print_words + print_chars + print_linelength == 0)
348 print_lines = print_words = print_chars = 1;
350 nfiles = argc - optind;
352 if (nfiles == 0)
354 have_read_stdin = 1;
355 wc (0, "");
357 else
359 for (; optind < argc; ++optind)
360 wc_file (argv[optind]);
362 if (nfiles > 1)
363 write_counts (total_lines, total_words, total_chars, max_line_length,
364 _("total"));
367 if (have_read_stdin && close (0))
368 error (EXIT_FAILURE, errno, "-");
370 exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);