xref: /csrg-svn/usr.bin/wc/wc.c (revision 51587)
121588Sdist /*
233163Sbostic  * Copyright (c) 1980, 1987 Regents of the University of California.
333163Sbostic  * All rights reserved.
433163Sbostic  *
542785Sbostic  * %sccs.include.redist.c%
621588Sdist  */
721588Sdist 
821588Sdist #ifndef lint
921588Sdist char copyright[] =
10*51587Sbostic "@(#) Copyright (c) 1987, 1991 Regents of the University of California.\n\
1121588Sdist  All rights reserved.\n";
1233163Sbostic #endif /* not lint */
1321588Sdist 
1421588Sdist #ifndef lint
15*51587Sbostic static char sccsid[] = "@(#)wc.c	5.8 (Berkeley) 11/06/91";
1633163Sbostic #endif /* not lint */
1721588Sdist 
1830103Sbostic #include <sys/param.h>
1930103Sbostic #include <sys/stat.h>
20*51587Sbostic #include <fcntl.h>
21*51587Sbostic #include <unistd.h>
22*51587Sbostic #include <errno.h>
231161Sbill #include <stdio.h>
24*51587Sbostic #include <stdlib.h>
25*51587Sbostic #include <string.h>
26*51587Sbostic #include <ctype.h>
271161Sbill 
28*51587Sbostic u_long tlinect, twordct, tcharct;
29*51587Sbostic int doline, doword, dochar;
3030103Sbostic 
31*51587Sbostic void cnt __P((char *));
32*51587Sbostic void err __P((const char *, ...));
33*51587Sbostic void usage __P((void));
3430103Sbostic 
35*51587Sbostic int
3635284Sbostic main(argc, argv)
3733163Sbostic 	int argc;
38*51587Sbostic 	char *argv[];
391161Sbill {
4033163Sbostic 	register int ch;
4135284Sbostic 	int total;
421161Sbill 
43*51587Sbostic 	while ((ch = getopt(argc, argv, "lwc")) != EOF)
44*51587Sbostic 		switch((char)ch) {
45*51587Sbostic 		case 'l':
46*51587Sbostic 			doline = 1;
47*51587Sbostic 			break;
48*51587Sbostic 		case 'w':
49*51587Sbostic 			doword = 1;
50*51587Sbostic 			break;
51*51587Sbostic 		case 'c':
52*51587Sbostic 			dochar = 1;
53*51587Sbostic 			break;
54*51587Sbostic 		case '?':
55*51587Sbostic 		default:
56*51587Sbostic 			usage();
57*51587Sbostic 		}
58*51587Sbostic 	argv += optind;
59*51587Sbostic 	argc -= optind;
60*51587Sbostic 
61*51587Sbostic 	/* Wc's flags are on by default. */
62*51587Sbostic 	if (doline + doword + dochar == 0)
6333163Sbostic 		doline = doword = dochar = 1;
6430103Sbostic 
6535284Sbostic 	total = 0;
6635284Sbostic 	if (!*argv) {
67*51587Sbostic 		cnt(NULL);
68*51587Sbostic 		(void)printf("\n");
691161Sbill 	}
7035284Sbostic 	else do {
7135284Sbostic 		cnt(*argv);
72*51587Sbostic 		(void)printf(" %s\n", *argv);
7335284Sbostic 		++total;
7430103Sbostic 	} while(*++argv);
7530103Sbostic 
7635284Sbostic 	if (total > 1) {
7735284Sbostic 		if (doline)
78*51587Sbostic 			(void)printf(" %7ld", tlinect);
7935284Sbostic 		if (doword)
80*51587Sbostic 			(void)printf(" %7ld", twordct);
8135284Sbostic 		if (dochar)
82*51587Sbostic 			(void)printf(" %7ld", tcharct);
83*51587Sbostic 		(void)printf(" total\n");
8435284Sbostic 	}
8533163Sbostic 	exit(0);
8630103Sbostic }
8730103Sbostic 
88*51587Sbostic void
8930103Sbostic cnt(file)
9033163Sbostic 	char *file;
9130103Sbostic {
92*51587Sbostic 	register u_char *p;
9333163Sbostic 	register short gotsp;
94*51587Sbostic 	register int ch, len;
95*51587Sbostic 	register u_long linect, wordct, charct;
96*51587Sbostic 	struct stat sb;
9733163Sbostic 	int fd;
9833163Sbostic 	u_char buf[MAXBSIZE];
9930103Sbostic 
100*51587Sbostic 	fd = STDIN_FILENO;
10130103Sbostic 	linect = wordct = charct = 0;
10230103Sbostic 	if (file) {
103*51587Sbostic 		if ((fd = open(file, O_RDONLY, 0)) < 0)
104*51587Sbostic 			err("%s: %s", file, strerror(errno));
105*51587Sbostic 		if (doword)
106*51587Sbostic 			goto word;
107*51587Sbostic 		/*
108*51587Sbostic 		 * Line counting is split out because it's a lot faster to get
109*51587Sbostic 		 * lines than to get words, since the word count requires some
110*51587Sbostic 		 * logic.
111*51587Sbostic 		 */
112*51587Sbostic 		if (doline) {
113*51587Sbostic 			while (len = read(fd, buf, MAXBSIZE)) {
114*51587Sbostic 				if (len == -1)
115*51587Sbostic 					err("%s: %s", file, strerror(errno));
116*51587Sbostic 				charct += len;
117*51587Sbostic 				for (p = buf; len--; ++p)
118*51587Sbostic 					if (*p == '\n')
119*51587Sbostic 						++linect;
1201161Sbill 			}
121*51587Sbostic 			tlinect += linect;
122*51587Sbostic 			(void)printf(" %7lu", linect);
12330103Sbostic 			if (dochar) {
124*51587Sbostic 				tcharct += charct;
125*51587Sbostic 				(void)printf(" %7lu", charct);
1261161Sbill 			}
127*51587Sbostic 			(void)close(fd);
128*51587Sbostic 			return;
1291161Sbill 		}
130*51587Sbostic 		/*
131*51587Sbostic 		 * If all we need is the number of characters and it's a
132*51587Sbostic 		 * regular or linked file, just stat the puppy.
133*51587Sbostic 		 */
134*51587Sbostic 		if (dochar) {
135*51587Sbostic 			if (fstat(fd, &sb))
136*51587Sbostic 				err("%s: %s", file, strerror(errno));
137*51587Sbostic 			if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
138*51587Sbostic 				(void)printf(" %7lu", sb.st_size);
139*51587Sbostic 				tcharct += sb.st_size;
140*51587Sbostic 				(void)close(fd);
141*51587Sbostic 				return;
142*51587Sbostic 			}
143*51587Sbostic 		}
14430103Sbostic 	}
145*51587Sbostic 
146*51587Sbostic 	/* Do it the hard way... */
147*51587Sbostic word:	for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
148*51587Sbostic 		if (len == -1)
149*51587Sbostic 			err("%s: %s", file, strerror(errno));
150*51587Sbostic 		/*
151*51587Sbostic 		 * This loses in the presence of multi-byte characters.
152*51587Sbostic 		 * To do it right would require a function to return a
153*51587Sbostic 		 * character while knowing how many bytes it consumed.
154*51587Sbostic 		 */
15530103Sbostic 		charct += len;
156*51587Sbostic 		for (p = buf; len--;) {
157*51587Sbostic 			ch = *p++;
158*51587Sbostic 			if (ch == '\n')
159*51587Sbostic 				++linect;
160*51587Sbostic 			if (isspace(ch))
161*51587Sbostic 				gotsp = 1;
162*51587Sbostic 			else if (gotsp) {
163*51587Sbostic 				gotsp = 0;
164*51587Sbostic 				++wordct;
16530103Sbostic 			}
166*51587Sbostic 		}
16730103Sbostic 	}
16830103Sbostic 	if (doline) {
1691161Sbill 		tlinect += linect;
170*51587Sbostic 		(void)printf(" %7lu", linect);
17130103Sbostic 	}
17230103Sbostic 	if (doword) {
1731161Sbill 		twordct += wordct;
174*51587Sbostic 		(void)printf(" %7lu", wordct);
17530103Sbostic 	}
17630103Sbostic 	if (dochar) {
1771161Sbill 		tcharct += charct;
178*51587Sbostic 		(void)printf(" %7lu", charct);
1791161Sbill 	}
180*51587Sbostic 	(void)close(fd);
1811161Sbill }
182*51587Sbostic 
183*51587Sbostic void
184*51587Sbostic usage()
185*51587Sbostic {
186*51587Sbostic 	(void)fprintf(stderr, "usage: wc [-clw] [files]\n");
187*51587Sbostic 	exit(1);
188*51587Sbostic }
189*51587Sbostic 
190*51587Sbostic #if __STDC__
191*51587Sbostic #include <stdarg.h>
192*51587Sbostic #else
193*51587Sbostic #include <varargs.h>
194*51587Sbostic #endif
195*51587Sbostic 
196*51587Sbostic void
197*51587Sbostic #if __STDC__
198*51587Sbostic err(const char *fmt, ...)
199*51587Sbostic #else
200*51587Sbostic err(fmt, va_alist)
201*51587Sbostic 	char *fmt;
202*51587Sbostic         va_dcl
203*51587Sbostic #endif
204*51587Sbostic {
205*51587Sbostic 	va_list ap;
206*51587Sbostic #if __STDC__
207*51587Sbostic 	va_start(ap, fmt);
208*51587Sbostic #else
209*51587Sbostic 	va_start(ap);
210*51587Sbostic #endif
211*51587Sbostic 	(void)fprintf(stderr, "wc: ");
212*51587Sbostic 	(void)vfprintf(stderr, fmt, ap);
213*51587Sbostic 	va_end(ap);
214*51587Sbostic 	(void)fprintf(stderr, "\n");
215*51587Sbostic 	exit(1);
216*51587Sbostic 	/* NOTREACHED */
217*51587Sbostic }
218