wc.c revision 87676
1/*
2 * Copyright (c) 1980, 1987, 1991, 1993
3 *	The Regents of the University of California.  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#include <sys/cdefs.h>
35
36__FBSDID("$FreeBSD: head/usr.bin/wc/wc.c 87676 2001-12-11 22:23:53Z markm $");
37
38#ifndef lint
39static const char copyright[] =
40"@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
41	The Regents of the University of California.  All rights reserved.\n";
42#endif
43
44#ifndef lint
45static const char sccsid[] = "@(#)wc.c	8.1 (Berkeley) 6/6/93";
46#endif
47
48#include <sys/param.h>
49#include <sys/stat.h>
50
51#include <ctype.h>
52#include <err.h>
53#include <fcntl.h>
54#include <locale.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59
60u_quad_t tlinect, twordct, tcharct;
61int doline, doword, dochar;
62
63int cnt __P((const char *));
64void usage __P((void));
65
66int
67main(argc, argv)
68	int argc;
69	char *argv[];
70{
71	int ch, errors, total;
72
73	(void) setlocale(LC_CTYPE, "");
74
75	while ((ch = getopt(argc, argv, "lwc")) != -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			dochar = 1;
85			break;
86		case '?':
87		default:
88			usage();
89		}
90	argv += optind;
91	argc -= optind;
92
93	/* Wc's flags are on by default. */
94	if (doline + doword + dochar == 0)
95		doline = doword = dochar = 1;
96
97	errors = 0;
98	total = 0;
99	if (!*argv) {
100		if (cnt((char *)NULL) != 0)
101			++errors;
102		else
103			(void)printf("\n");
104	}
105	else do {
106		if (cnt(*argv) != 0)
107			++errors;
108		else
109			(void)printf(" %s\n", *argv);
110		++total;
111	} while(*++argv);
112
113	if (total > 1) {
114		if (doline)
115			(void)printf(" %7qu", tlinect);
116		if (doword)
117			(void)printf(" %7qu", twordct);
118		if (dochar)
119			(void)printf(" %7qu", tcharct);
120		(void)printf(" total\n");
121	}
122	exit(errors == 0 ? 0 : 1);
123}
124
125int
126cnt(file)
127	const char *file;
128{
129	struct stat sb;
130	u_quad_t linect, wordct, charct;
131	int fd, len;
132	short gotsp;
133	u_char *p;
134	u_char buf[MAXBSIZE], ch;
135
136	linect = wordct = charct = 0;
137	if (file == NULL) {
138		file = "stdin";
139		fd = STDIN_FILENO;
140	} else {
141		if ((fd = open(file, O_RDONLY, 0)) < 0) {
142			warn("%s: open", file);
143			return (1);
144		}
145		if (doword)
146			goto word;
147		/*
148		 * Line counting is split out because it's a lot faster to get
149		 * lines than to get words, since the word count requires some
150		 * logic.
151		 */
152		if (doline) {
153			while ((len = read(fd, buf, MAXBSIZE))) {
154				if (len == -1) {
155					warn("%s: read", file);
156					(void)close(fd);
157					return (1);
158				}
159				charct += len;
160				for (p = buf; len--; ++p)
161					if (*p == '\n')
162						++linect;
163			}
164			tlinect += linect;
165			(void)printf(" %7qu", linect);
166			if (dochar) {
167				tcharct += charct;
168				(void)printf(" %7qu", charct);
169			}
170			(void)close(fd);
171			return (0);
172		}
173		/*
174		 * If all we need is the number of characters and it's a
175		 * regular or linked file, just stat the puppy.
176		 */
177		if (dochar) {
178			if (fstat(fd, &sb)) {
179				warn("%s: fstat", file);
180				(void)close(fd);
181				return (1);
182			}
183			if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
184				(void)printf(" %7lld", (long long)sb.st_size);
185				tcharct += sb.st_size;
186				(void)close(fd);
187				return (0);
188			}
189		}
190	}
191
192	/* Do it the hard way... */
193word:	for (gotsp = 1; (len = read(fd, buf, MAXBSIZE));) {
194		if (len == -1) {
195			warn("%s: read", file);
196			(void)close(fd);
197			return (1);
198		}
199		/*
200		 * This loses in the presence of multi-byte characters.
201		 * To do it right would require a function to return a
202		 * character while knowing how many bytes it consumed.
203		 */
204		charct += len;
205		for (p = buf; len--;) {
206			ch = *p++;
207			if (ch == '\n')
208				++linect;
209			if (isspace(ch))
210				gotsp = 1;
211			else if (gotsp) {
212				gotsp = 0;
213				++wordct;
214			}
215		}
216	}
217	if (doline) {
218		tlinect += linect;
219		(void)printf(" %7qu", linect);
220	}
221	if (doword) {
222		twordct += wordct;
223		(void)printf(" %7qu", wordct);
224	}
225	if (dochar) {
226		tcharct += charct;
227		(void)printf(" %7qu", charct);
228	}
229	(void)close(fd);
230	return (0);
231}
232
233void
234usage()
235{
236	(void)fprintf(stderr, "usage: wc [-clw] [file ...]\n");
237	exit(1);
238}
239