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