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
main(argc,argv)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
cnt(file)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
usage()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__
err(const char * fmt,...)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