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 "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. */
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
},
81 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
86 Usage: %s [OPTION]... [FILE]...\n\
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\
100 puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
102 exit (status
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);
106 write_counts (uintmax_t lines
,
109 uintmax_t linelength
,
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");
119 printf (format_int
, human_readable (lines
, buf
, 1, 1));
124 printf (format_sp_int
, space
, human_readable (words
, buf
, 1, 1));
129 printf (format_sp_int
, space
, human_readable (chars
, buf
, 1, 1));
132 if (print_linelength
)
134 printf (format_sp_int
, space
, human_readable (linelength
, buf
, 1, 1));
137 printf (" %s", file
);
142 wc (int fd
, const char *file
)
144 char buf
[BUFFER_SIZE
+ 1];
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. */
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
;
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)
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
;
180 while ((bytes_read
= safe_read (fd
, buf
, BUFFER_SIZE
)) > 0)
186 error (0, errno
, "%s", file
);
191 else if (!print_words
&& !print_linelength
)
193 /* Use a separate loop when counting only lines or lines and bytes --
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
)))
208 error (0, errno
, "%s", file
);
214 uintmax_t linepos
= 0;
216 while ((bytes_read
= safe_read (fd
, buf
, BUFFER_SIZE
)) > 0)
230 if (linepos
> linelength
)
231 linelength
= linepos
;
235 linepos
+= 8 - (linepos
% 8);
254 while (--bytes_read
);
258 error (0, errno
, "%s", file
);
261 if (linepos
> linelength
)
262 linelength
= linepos
;
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
;
276 wc_file (const char *file
)
278 if (STREQ (file
, "-"))
285 int fd
= open (file
, O_RDONLY
);
288 error (0, errno
, "%s", file
);
295 error (0, errno
, "%s", file
);
302 main (int argc
, char **argv
)
307 program_name
= argv
[0];
308 setlocale (LC_ALL
, "");
309 bindtextdomain (PACKAGE
, LOCALEDIR
);
310 textdomain (PACKAGE
);
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)
336 print_linelength
= 1;
339 case_GETOPT_HELP_CHAR
;
341 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
347 if (print_lines
+ print_words
+ print_chars
+ print_linelength
== 0)
348 print_lines
= print_words
= print_chars
= 1;
350 nfiles
= argc
- optind
;
359 for (; optind
< argc
; ++optind
)
360 wc_file (argv
[optind
]);
363 write_counts (total_lines
, total_words
, total_chars
, max_line_length
,
367 if (have_read_stdin
&& close (0))
368 error (EXIT_FAILURE
, errno
, "-");
370 exit (exit_status
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
);