wc.c revision 1.15 1 /* $NetBSD: wc.c,v 1.15 1999/02/13 15:53:17 explorer Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1987, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)wc.c 8.2 (Berkeley) 5/2/95";
45 #else
46 __RCSID("$NetBSD: wc.c,v 1.15 1999/02/13 15:53:17 explorer Exp $");
47 #endif
48 #endif /* not lint */
49
50 /* wc line, word and char count */
51
52 #include <sys/param.h>
53 #include <sys/stat.h>
54 #include <sys/types.h>
55
56 #include <fcntl.h>
57 #include <unistd.h>
58 #include <errno.h>
59 #include <stdio.h>
60
61 #include <stdlib.h>
62 #include <string.h>
63 #include <locale.h>
64 #include <ctype.h>
65 #include <errno.h>
66 #include <sys/param.h>
67 #include <sys/stat.h>
68 #include <sys/file.h>
69 #include <unistd.h>
70 #include <err.h>
71
72 static u_int64_t tlinect, twordct, tcharct;
73 static int doline, doword, dochar;
74 static int rval = 0;
75
76 static void cnt __P((char *));
77 static void print_counts __P((u_int64_t, u_int64_t, u_int64_t, char *));
78 static void usage __P((void));
79 int main __P((int, char *[]));
80
81 int
82 main(argc, argv)
83 int argc;
84 char *argv[];
85 {
86 int ch;
87
88 setlocale(LC_ALL, "");
89
90 while ((ch = getopt(argc, argv, "lwcm")) != -1)
91 switch((char)ch) {
92 case 'l':
93 doline = 1;
94 break;
95 case 'w':
96 doword = 1;
97 break;
98 case 'c':
99 case 'm':
100 dochar = 1;
101 break;
102 case '?':
103 default:
104 usage();
105 }
106 argv += optind;
107 argc -= optind;
108
109 /* Wc's flags are on by default. */
110 if (doline + doword + dochar == 0)
111 doline = doword = dochar = 1;
112
113 if (!*argv) {
114 cnt(NULL);
115 } else {
116 int dototal = (argc > 1);
117
118 do {
119 cnt(*argv);
120 } while(*++argv);
121
122 if (dototal) {
123 print_counts(tlinect, twordct, tcharct, "total");
124 }
125 }
126
127 exit(rval);
128 }
129
130 static void
131 cnt(file)
132 char *file;
133 {
134 u_char *C;
135 short gotsp;
136 int len;
137 u_int64_t linect, wordct, charct;
138 struct stat sb;
139 int fd;
140 u_char buf[MAXBSIZE];
141
142 linect = wordct = charct = 0;
143 if (file) {
144 if ((fd = open(file, O_RDONLY, 0)) < 0) {
145 warn("%s", file);
146 rval = 1;
147 return;
148 }
149 } else {
150 fd = STDIN_FILENO;
151 }
152
153 if (!doword) {
154 /*
155 * line counting is split out because it's a lot
156 * faster to get lines than to get words, since
157 * the word count requires some logic.
158 */
159 if (doline) {
160 while ((len = read(fd, buf, MAXBSIZE)) > 0) {
161 charct += len;
162 for (C = buf; len--; ++C)
163 if (*C == '\n')
164 ++linect;
165 }
166 if (len == -1) {
167 warn ("%s", file);
168 rval = 1;
169 }
170 }
171
172 /*
173 * if all we need is the number of characters and
174 * it's a directory or a regular or linked file, just
175 * stat the puppy. We avoid testing for it not being
176 * a special device in case someone adds a new type
177 * of inode.
178 */
179 else if (dochar) {
180 if (fstat(fd, &sb)) {
181 warn("%s", file);
182 rval = 1;
183 } else {
184 if (S_ISREG(sb.st_mode) ||
185 S_ISLNK(sb.st_mode) ||
186 S_ISDIR(sb.st_mode)) {
187 charct = sb.st_size;
188 } else {
189 while ((len = read(fd, buf, MAXBSIZE)) > 0)
190 charct += len;
191 if (len == -1) {
192 warn ("%s", file);
193 rval = 1;
194 }
195 }
196 }
197 }
198 }
199 else
200 {
201 /* do it the hard way... */
202 gotsp = 1;
203 while ((len = read(fd, buf, MAXBSIZE)) > 0) {
204 charct += len;
205 for (C = buf; len--; ++C) {
206 if (isspace(*C)) {
207 gotsp = 1;
208 if (*C == '\n') {
209 ++linect;
210 }
211 } else {
212 /*
213 * This line implements the POSIX
214 * spec, i.e. a word is a "maximal
215 * string of characters delimited by
216 * whitespace." Notice nothing was
217 * said about a character being
218 * printing or non-printing.
219 */
220 if (gotsp) {
221 gotsp = 0;
222 ++wordct;
223 }
224 }
225 }
226 }
227 if (len == -1) {
228 warn("%s", file);
229 rval = 1;
230 }
231 }
232
233 print_counts(linect, wordct, charct, file ? file : "");
234
235 /* don't bother checkint doline, doword, or dochar --- speeds
236 up the common case */
237 tlinect += linect;
238 twordct += wordct;
239 tcharct += charct;
240
241 if (close(fd)) {
242 warn ("%s", file);
243 rval = 1;
244 }
245 }
246
247 static void
248 print_counts(lines, words, chars, name)
249 u_int64_t lines;
250 u_int64_t words;
251 u_int64_t chars;
252 char *name;
253 {
254
255 if (doline)
256 printf(" %7qu", lines);
257 if (doword)
258 printf(" %7qu", words);
259 if (dochar)
260 printf(" %7qu", chars);
261
262 printf(" %s\n", name);
263 }
264
265 static void
266 usage()
267 {
268 (void)fprintf(stderr, "usage: wc [-clw] [files]\n");
269 exit(1);
270 }
271