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