wc.c revision 13380
1174604Sscottl/*
2174604Sscottl * Copyright (c) 1980, 1987, 1991, 1993
3174604Sscottl *	The Regents of the University of California.  All rights reserved.
4174604Sscottl *
5174604Sscottl * Redistribution and use in source and binary forms, with or without
6174604Sscottl * modification, are permitted provided that the following conditions
7174604Sscottl * are met:
8174604Sscottl * 1. Redistributions of source code must retain the above copyright
9174604Sscottl *    notice, this list of conditions and the following disclaimer.
10174604Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11174604Sscottl *    notice, this list of conditions and the following disclaimer in the
12174604Sscottl *    documentation and/or other materials provided with the distribution.
13174604Sscottl * 3. All advertising materials mentioning features or use of this software
14174604Sscottl *    must display the following acknowledgement:
15174604Sscottl *	This product includes software developed by the University of
16174604Sscottl *	California, Berkeley and its contributors.
17174604Sscottl * 4. Neither the name of the University nor the names of its contributors
18174604Sscottl *    may be used to endorse or promote products derived from this software
19174604Sscottl *    without specific prior written permission.
20174604Sscottl *
21174604Sscottl * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22174604Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23174604Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24174604Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25174604Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26174604Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27174604Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28174604Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29176018Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30174604Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31174604Sscottl * SUCH DAMAGE.
32174604Sscottl */
33174604Sscottl
34174604Sscottl#ifndef lint
35174604Sscottlstatic char copyright[] =
36174604Sscottl"@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
37199043Smav	The Regents of the University of California.  All rights reserved.\n";
38199043Smav#endif /* not lint */
39199043Smav
40174604Sscottl#ifndef lint
41174604Sscottlstatic char sccsid[] = "@(#)wc.c	8.1 (Berkeley) 6/6/93";
42174604Sscottl#endif /* not lint */
43174604Sscottl
44174604Sscottl#include <sys/param.h>
45174604Sscottl#include <sys/stat.h>
46174604Sscottl#include <fcntl.h>
47199043Smav#include <locale.h>
48199043Smav#include <unistd.h>
49199043Smav#include <errno.h>
50174604Sscottl#include <stdio.h>
51174604Sscottl#include <stdlib.h>
52174604Sscottl#include <string.h>
53174604Sscottl#include <ctype.h>
54174604Sscottl
55174604Sscottlu_long tlinect, twordct, tcharct;
56174604Sscottlint doline, doword, dochar;
57174604Sscottl
58174604Sscottlvoid cnt __P((char *));
59174604Sscottlvoid err __P((const char *, ...));
60174604Sscottlvoid usage __P((void));
61174604Sscottl
62174604Sscottlint
63174604Sscottlmain(argc, argv)
64174604Sscottl	int argc;
65174604Sscottl	char *argv[];
66174604Sscottl{
67174604Sscottl	register int ch;
68174604Sscottl	int total;
69174604Sscottl
70174604Sscottl	(void) setlocale(LC_CTYPE, "");
71174604Sscottl
72174604Sscottl	while ((ch = getopt(argc, argv, "lwc")) != EOF)
73174604Sscottl		switch((char)ch) {
74174604Sscottl		case 'l':
75174604Sscottl			doline = 1;
76174604Sscottl			break;
77174604Sscottl		case 'w':
78174604Sscottl			doword = 1;
79174604Sscottl			break;
80174604Sscottl		case 'c':
81174604Sscottl			dochar = 1;
82174604Sscottl			break;
83174604Sscottl		case '?':
84174604Sscottl		default:
85174604Sscottl			usage();
86174604Sscottl		}
87174604Sscottl	argv += optind;
88174604Sscottl	argc -= optind;
89174604Sscottl
90174604Sscottl	/* Wc's flags are on by default. */
91174604Sscottl	if (doline + doword + dochar == 0)
92174604Sscottl		doline = doword = dochar = 1;
93174604Sscottl
94174604Sscottl	total = 0;
95174604Sscottl	if (!*argv) {
96174604Sscottl		cnt(NULL);
97174604Sscottl		(void)printf("\n");
98174604Sscottl	}
99174604Sscottl	else do {
100174604Sscottl		cnt(*argv);
101174604Sscottl		(void)printf(" %s\n", *argv);
102174604Sscottl		++total;
103174604Sscottl	} while(*++argv);
104174604Sscottl
105174604Sscottl	if (total > 1) {
106174604Sscottl		if (doline)
107174604Sscottl			(void)printf(" %7ld", tlinect);
108174604Sscottl		if (doword)
109174604Sscottl			(void)printf(" %7ld", twordct);
110174604Sscottl		if (dochar)
111174604Sscottl			(void)printf(" %7ld", tcharct);
112174604Sscottl		(void)printf(" total\n");
113174604Sscottl	}
114174604Sscottl	exit(0);
115174604Sscottl}
116174604Sscottl
117174604Sscottlvoid
118174604Sscottlcnt(file)
119174604Sscottl	char *file;
120174604Sscottl{
121174604Sscottl	register u_char *p, ch;
122174604Sscottl	register short gotsp;
123174604Sscottl	register int len;
124174604Sscottl	register u_long linect, wordct, charct;
125174604Sscottl	struct stat sb;
126174604Sscottl	int fd;
127174604Sscottl	u_char buf[MAXBSIZE];
128174604Sscottl
129174604Sscottl	fd = STDIN_FILENO;
130174604Sscottl	linect = wordct = charct = 0;
131174604Sscottl	if (file) {
132174604Sscottl		if ((fd = open(file, O_RDONLY, 0)) < 0)
133174604Sscottl			err("%s: %s", file, strerror(errno));
134174604Sscottl		if (doword)
135174604Sscottl			goto word;
136174604Sscottl		/*
137174604Sscottl		 * Line counting is split out because it's a lot faster to get
138174604Sscottl		 * lines than to get words, since the word count requires some
139174604Sscottl		 * logic.
140174604Sscottl		 */
141174604Sscottl		if (doline) {
142174604Sscottl			while (len = read(fd, buf, MAXBSIZE)) {
143174604Sscottl				if (len == -1)
144174604Sscottl					err("%s: %s", file, strerror(errno));
145174604Sscottl				charct += len;
146174604Sscottl				for (p = buf; len--; ++p)
147174604Sscottl					if (*p == '\n')
148174604Sscottl						++linect;
149174604Sscottl			}
150174604Sscottl			tlinect += linect;
151174604Sscottl			(void)printf(" %7lu", linect);
152174604Sscottl			if (dochar) {
153174604Sscottl				tcharct += charct;
154174604Sscottl				(void)printf(" %7lu", charct);
155174604Sscottl			}
156174604Sscottl			(void)close(fd);
157174604Sscottl			return;
158174604Sscottl		}
159174604Sscottl		/*
160174604Sscottl		 * If all we need is the number of characters and it's a
161174604Sscottl		 * regular or linked file, just stat the puppy.
162174604Sscottl		 */
163174604Sscottl		if (dochar) {
164174604Sscottl			if (fstat(fd, &sb))
165174604Sscottl				err("%s: %s", file, strerror(errno));
166174604Sscottl			if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
167174604Sscottl				(void)printf(" %7qu", sb.st_size);
168174604Sscottl				tcharct += sb.st_size;
169174604Sscottl				(void)close(fd);
170174604Sscottl				return;
171174604Sscottl			}
172174604Sscottl		}
173174604Sscottl	}
174174604Sscottl
175174604Sscottl	/* Do it the hard way... */
176174604Sscottlword:	for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
177174604Sscottl		if (len == -1)
178174604Sscottl			err("%s: %s", file, strerror(errno));
179174604Sscottl		/*
180174604Sscottl		 * This loses in the presence of multi-byte characters.
181174604Sscottl		 * To do it right would require a function to return a
182174604Sscottl		 * character while knowing how many bytes it consumed.
183174604Sscottl		 */
184174604Sscottl		charct += len;
185174604Sscottl		for (p = buf; len--;) {
186174604Sscottl			ch = *p++;
187174604Sscottl			if (ch == '\n')
188174604Sscottl				++linect;
189174604Sscottl			if (isspace(ch))
190174604Sscottl				gotsp = 1;
191174604Sscottl			else if (gotsp) {
192174604Sscottl				gotsp = 0;
193174604Sscottl				++wordct;
194174604Sscottl			}
195174604Sscottl		}
196174604Sscottl	}
197174604Sscottl	if (doline) {
198174604Sscottl		tlinect += linect;
199174604Sscottl		(void)printf(" %7lu", linect);
200174604Sscottl	}
201174604Sscottl	if (doword) {
202174604Sscottl		twordct += wordct;
203174604Sscottl		(void)printf(" %7lu", wordct);
204174604Sscottl	}
205174604Sscottl	if (dochar) {
206174604Sscottl		tcharct += charct;
207174604Sscottl		(void)printf(" %7lu", charct);
208174604Sscottl	}
209174604Sscottl	(void)close(fd);
210174604Sscottl}
211174604Sscottl
212174604Sscottlvoid
213174604Sscottlusage()
214176939Sscottl{
215174604Sscottl	(void)fprintf(stderr, "usage: wc [-clw] [files]\n");
216174604Sscottl	exit(1);
217174604Sscottl}
218174604Sscottl
219174604Sscottl#if __STDC__
220174604Sscottl#include <stdarg.h>
221174604Sscottl#else
222174604Sscottl#include <varargs.h>
223174604Sscottl#endif
224174604Sscottl
225174604Sscottlvoid
226174604Sscottl#if __STDC__
227174604Sscottlerr(const char *fmt, ...)
228174604Sscottl#else
229174604Sscottlerr(fmt, va_alist)
230174604Sscottl	char *fmt;
231176939Sscottl        va_dcl
232174604Sscottl#endif
233174604Sscottl{
234174604Sscottl	va_list ap;
235174604Sscottl#if __STDC__
236174604Sscottl	va_start(ap, fmt);
237174604Sscottl#else
238174604Sscottl	va_start(ap);
239174604Sscottl#endif
240174604Sscottl	(void)fprintf(stderr, "wc: ");
241174604Sscottl	(void)vfprintf(stderr, fmt, ap);
242174604Sscottl	va_end(ap);
243174604Sscottl	(void)fprintf(stderr, "\n");
244174604Sscottl	exit(1);
245174604Sscottl	/* NOTREACHED */
246174604Sscottl}
247174604Sscottl