xref: /original-bsd/usr.bin/wc/wc.c (revision 0842ddeb)
1 /*
2  * Copyright (c) 1980, 1987, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)wc.c	8.2 (Berkeley) 05/02/95";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 
28 u_long tlinect, twordct, tcharct;
29 int doline, doword, dochar;
30 
31 void cnt __P((char *));
32 void err __P((const char *, ...));
33 void usage __P((void));
34 
35 int
36 main(argc, argv)
37 	int argc;
38 	char *argv[];
39 {
40 	register int ch;
41 	int total;
42 
43 	while ((ch = getopt(argc, argv, "lwc")) != EOF)
44 		switch((char)ch) {
45 		case 'l':
46 			doline = 1;
47 			break;
48 		case 'w':
49 			doword = 1;
50 			break;
51 		case 'c':
52 			dochar = 1;
53 			break;
54 		case '?':
55 		default:
56 			usage();
57 		}
58 	argv += optind;
59 	argc -= optind;
60 
61 	/* Wc's flags are on by default. */
62 	if (doline + doword + dochar == 0)
63 		doline = doword = dochar = 1;
64 
65 	total = 0;
66 	if (!*argv) {
67 		cnt(NULL);
68 		(void)printf("\n");
69 	}
70 	else do {
71 		cnt(*argv);
72 		(void)printf(" %s\n", *argv);
73 		++total;
74 	} while(*++argv);
75 
76 	if (total > 1) {
77 		if (doline)
78 			(void)printf(" %7ld", tlinect);
79 		if (doword)
80 			(void)printf(" %7ld", twordct);
81 		if (dochar)
82 			(void)printf(" %7ld", tcharct);
83 		(void)printf(" total\n");
84 	}
85 	exit(0);
86 }
87 
88 void
89 cnt(file)
90 	char *file;
91 {
92 	register u_char *p;
93 	register short gotsp;
94 	register int ch, len;
95 	register u_long linect, wordct, charct;
96 	struct stat sb;
97 	int fd;
98 	u_char buf[MAXBSIZE];
99 
100 	fd = STDIN_FILENO;
101 	linect = wordct = charct = 0;
102 	if (file) {
103 		if ((fd = open(file, O_RDONLY, 0)) < 0)
104 			err("%s: %s", file, strerror(errno));
105 		if (doword)
106 			goto word;
107 		/*
108 		 * Line counting is split out because it's a lot faster to get
109 		 * lines than to get words, since the word count requires some
110 		 * logic.
111 		 */
112 		if (doline) {
113 			while (len = read(fd, buf, MAXBSIZE)) {
114 				if (len == -1)
115 					err("%s: %s", file, strerror(errno));
116 				charct += len;
117 				for (p = buf; len--; ++p)
118 					if (*p == '\n')
119 						++linect;
120 			}
121 			tlinect += linect;
122 			(void)printf(" %7lu", linect);
123 			if (dochar) {
124 				tcharct += charct;
125 				(void)printf(" %7lu", charct);
126 			}
127 			(void)close(fd);
128 			return;
129 		}
130 		/*
131 		 * If all we need is the number of characters and it's a
132 		 * regular or linked file, just stat the puppy.
133 		 */
134 		if (dochar) {
135 			if (fstat(fd, &sb))
136 				err("%s: %s", file, strerror(errno));
137 			if (S_ISREG(sb.st_mode)) {
138 				(void)printf(" %7qu", sb.st_size);
139 				tcharct += sb.st_size;
140 				(void)close(fd);
141 				return;
142 			}
143 		}
144 	}
145 
146 	/* Do it the hard way... */
147 word:	for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
148 		if (len == -1)
149 			err("%s: %s", file, strerror(errno));
150 		/*
151 		 * This loses in the presence of multi-byte characters.
152 		 * To do it right would require a function to return a
153 		 * character while knowing how many bytes it consumed.
154 		 */
155 		charct += len;
156 		for (p = buf; len--;) {
157 			ch = *p++;
158 			if (ch == '\n')
159 				++linect;
160 			if (isspace(ch))
161 				gotsp = 1;
162 			else if (gotsp) {
163 				gotsp = 0;
164 				++wordct;
165 			}
166 		}
167 	}
168 	if (doline) {
169 		tlinect += linect;
170 		(void)printf(" %7lu", linect);
171 	}
172 	if (doword) {
173 		twordct += wordct;
174 		(void)printf(" %7lu", wordct);
175 	}
176 	if (dochar) {
177 		tcharct += charct;
178 		(void)printf(" %7lu", charct);
179 	}
180 	(void)close(fd);
181 }
182 
183 void
184 usage()
185 {
186 	(void)fprintf(stderr, "usage: wc [-clw] [files]\n");
187 	exit(1);
188 }
189 
190 #if __STDC__
191 #include <stdarg.h>
192 #else
193 #include <varargs.h>
194 #endif
195 
196 void
197 #if __STDC__
198 err(const char *fmt, ...)
199 #else
200 err(fmt, va_alist)
201 	char *fmt;
202         va_dcl
203 #endif
204 {
205 	va_list ap;
206 #if __STDC__
207 	va_start(ap, fmt);
208 #else
209 	va_start(ap);
210 #endif
211 	(void)fprintf(stderr, "wc: ");
212 	(void)vfprintf(stderr, fmt, ap);
213 	va_end(ap);
214 	(void)fprintf(stderr, "\n");
215 	exit(1);
216 	/* NOTREACHED */
217 }
218