xref: /netbsd-src/usr.bin/wc/wc.c (revision 1394f01b4a9e99092957ca5d824d67219565d9b5)
1 /*	$NetBSD: wc.c,v 1.10 1997/01/09 20:23:20 tls Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1987 Regents of the University of California.
5  * 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 #ifndef lint
37 char copyright[] =
38 "@(#) Copyright (c) 1980, 1987 Regents of the University of California.\n\
39  All rights reserved.\n";
40 #endif /* not lint */
41 
42 #ifndef lint
43 /*static char sccsid[] = "from: @(#)wc.c	5.7 (Berkeley) 3/2/91";*/
44 static char rcsid[] = "$NetBSD: wc.c,v 1.10 1997/01/09 20:23:20 tls Exp $";
45 #endif /* not lint */
46 
47 /* wc line, word and char count */
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <locale.h>
53 #include <ctype.h>
54 #include <errno.h>
55 #include <sys/param.h>
56 #include <sys/stat.h>
57 #include <sys/file.h>
58 #include <unistd.h>
59 #include <err.h>
60 
61 static void	print_counts();
62 static void	cnt();
63 static long	tlinect, twordct, tcharct;
64 static int	doline, doword, dochar;
65 static int 	rval = 0;
66 
67 int
68 main(argc, argv)
69 	int argc;
70 	char **argv;
71 {
72 	extern int optind;
73 	register int ch;
74 
75 	setlocale(LC_ALL, "");
76 
77 	while ((ch = getopt(argc, argv, "lwcm")) != -1)
78 		switch((char)ch) {
79 		case 'l':
80 			doline = 1;
81 			break;
82 		case 'w':
83 			doword = 1;
84 			break;
85 		case 'c':
86 		case 'm':
87 			dochar = 1;
88 			break;
89 		case '?':
90 		default:
91 			fprintf(stderr, "usage: wc [-c | -m] [-lw] [file ...]\n");
92 			exit(1);
93 		}
94 	argv += optind;
95 	argc -= optind;
96 
97 	/*
98 	 * wc is unusual in that its flags are on by default, so,
99 	 * if you don't get any arguments, you have to turn them
100 	 * all on.
101 	 */
102 	if (!doline && !doword && !dochar) {
103 		doline = doword = dochar = 1;
104 	}
105 
106 	if (!*argv) {
107 		cnt((char *)NULL);
108 	} else {
109 		int dototal = (argc > 1);
110 
111 		do {
112 			cnt(*argv);
113 		} while(*++argv);
114 
115 		if (dototal) {
116 			print_counts (tlinect, twordct, tcharct, "total");
117 		}
118 	}
119 
120 	exit(rval);
121 }
122 
123 
124 static void
125 cnt(file)
126 	char *file;
127 {
128 	register u_char *C;
129 	register short gotsp;
130 	register int len;
131 	register long linect, wordct, charct;
132 	struct stat sbuf;
133 	int fd;
134 	u_char buf[MAXBSIZE];
135 
136 	linect = wordct = charct = 0;
137 	if (file) {
138 		if ((fd = open(file, O_RDONLY, 0)) < 0) {
139 			warn ("%s", file);
140 			rval = 1;
141 			return;
142 		}
143 	} else  {
144 		fd = STDIN_FILENO;
145 	}
146 
147 	if (!doword) {
148 		/*
149 		 * line counting is split out because it's a lot
150 		 * faster to get lines than to get words, since
151 		 * the word count requires some logic.
152 		 */
153 		if (doline) {
154 			while((len = read(fd, buf, MAXBSIZE)) > 0) {
155 				charct += len;
156 				for (C = buf; len--; ++C)
157 					if (*C == '\n')
158 						++linect;
159 			}
160 			if (len == -1) {
161 				warn ("%s", file);
162 				rval = 1;
163 			}
164 		}
165 
166 		/*
167 		 * if all we need is the number of characters and
168 		 * it's a directory or a regular or linked file, just
169 		 * stat the puppy.  We avoid testing for it not being
170 		 * a special device in case someone adds a new type
171 		 * of inode.
172 		 */
173 		else if (dochar) {
174 			int ifmt;
175 
176 			if (fstat(fd, &sbuf)) {
177 				warn ("%s", file);
178 				rval = 1;
179 			} else {
180 				ifmt = sbuf.st_mode & S_IFMT;
181 				if (ifmt == S_IFREG || ifmt == S_IFLNK
182 					|| ifmt == S_IFDIR) {
183 					charct = sbuf.st_size;
184 				} else {
185 					while((len = read(fd, buf, MAXBSIZE)) > 0)
186 						charct += len;
187 					if (len == -1) {
188 						warn ("%s", file);
189 						rval = 1;
190 					}
191 				}
192 			}
193 		}
194 	}
195 	else
196 	{
197 		/* do it the hard way... */
198 		gotsp = 1;
199 		while ((len = read(fd, buf, MAXBSIZE)) > 0) {
200 			charct += len;
201 			for (C = buf; len--; ++C) {
202 				if (isspace (*C)) {
203 					gotsp = 1;
204 					if (*C == '\n') {
205 						++linect;
206 					}
207 				} else {
208 					/*
209 					 * This line implements the POSIX
210 					 * spec, i.e. a word is a "maximal
211 					 * string of characters delimited by
212 					 * whitespace."  Notice nothing was
213 					 * said about a character being
214 					 * printing or non-printing.
215 					 */
216 					if (gotsp) {
217 						gotsp = 0;
218 						++wordct;
219 					}
220 				}
221 			}
222 		}
223 		if (len == -1) {
224 			warn ("%s", file);
225 			rval = 1;
226 		}
227 	}
228 
229 	print_counts (linect, wordct, charct, file ? file : "");
230 
231 	/* don't bother checkint doline, doword, or dochar --- speeds
232            up the common case */
233 	tlinect += linect;
234 	twordct += wordct;
235 	tcharct += charct;
236 
237 	if (close(fd)) {
238 		warn ("%s", file);
239 		rval = 1;
240 	}
241 }
242 
243 
244 void
245 print_counts (lines, words, chars, name)
246 	long lines;
247 	long words;
248 	long chars;
249 	char *name;
250 {
251 
252 	if (doline)
253 		printf(" %7ld", lines);
254 	if (doword)
255 		printf(" %7ld", words);
256 	if (dochar)
257 		printf(" %7ld", chars);
258 
259 	printf (" %s\n", name);
260 }
261