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