Commit | Line | Data |
---|---|---|
f42904bc | 1 | /* |
2d5da4ef KB |
2 | * Copyright (c) 1980, 1987 Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that this notice is preserved and that due credit is given | |
7 | * to the University of California at Berkeley. The name of the University | |
8 | * may not be used to endorse or promote products derived from this | |
9 | * software without specific prior written permission. This software | |
10 | * is provided ``as is'' without express or implied warranty. | |
f42904bc DF |
11 | */ |
12 | ||
13 | #ifndef lint | |
14 | char copyright[] = | |
2d5da4ef | 15 | "@(#) Copyright (c) 1980, 1987 Regents of the University of California.\n\ |
f42904bc | 16 | All rights reserved.\n"; |
2d5da4ef | 17 | #endif /* not lint */ |
f42904bc DF |
18 | |
19 | #ifndef lint | |
2d5da4ef KB |
20 | static char sccsid[] = "@(#)wc.c 5.3 (Berkeley) %G%"; |
21 | #endif /* not lint */ | |
f42904bc | 22 | |
93b63814 | 23 | /* wc line, word and char count */ |
66690d0f | 24 | |
93b63814 KB |
25 | #include <sys/param.h> |
26 | #include <sys/stat.h> | |
27 | #include <sys/file.h> | |
66690d0f | 28 | #include <stdio.h> |
66690d0f | 29 | |
93b63814 | 30 | #define DEL 0177 /* del char */ |
93b63814 | 31 | #define NL 012 /* newline char */ |
93b63814 KB |
32 | #define SPACE 040 /* space char */ |
33 | #define TAB 011 /* tab char */ | |
93b63814 | 34 | |
2d5da4ef KB |
35 | static long tlinect, twordct, tcharct; |
36 | static int doline, doword, dochar; | |
93b63814 KB |
37 | |
38 | main(argc,argv) | |
2d5da4ef KB |
39 | int argc; |
40 | char **argv; | |
66690d0f | 41 | { |
2d5da4ef KB |
42 | extern int optind; |
43 | register int ch; | |
66690d0f | 44 | |
93b63814 KB |
45 | /* |
46 | * wc is unusual in that its flags are on by default, so, | |
47 | * if you don't get any arguments, you have to turn them | |
48 | * all on. | |
49 | */ | |
50 | if (argc > 1 && argv[1][0] == '-' && argv[1][1]) { | |
51 | while ((ch = getopt(argc,argv,"lwc")) != EOF) | |
52 | switch((char)ch) { | |
2d5da4ef KB |
53 | case 'l': |
54 | doline = 1; | |
55 | break; | |
56 | case 'w': | |
57 | doword = 1; | |
58 | break; | |
59 | case 'c': | |
60 | dochar = 1; | |
61 | break; | |
62 | case '?': | |
63 | default: | |
64 | fputs("usage: wc [-lwc] [files]\n",stderr); | |
65 | exit(1); | |
93b63814 KB |
66 | } |
67 | argv += optind; | |
68 | argc -= optind; | |
69 | } | |
70 | else { | |
71 | ++argv; | |
72 | --argc; | |
2d5da4ef | 73 | doline = doword = dochar = 1; |
93b63814 KB |
74 | } |
75 | ||
76 | /* should print "stdin" as the file name, here */ | |
77 | if (argc <= 1) { | |
2d5da4ef | 78 | if (!*argv || !strcmp(*argv, "-")) { |
93b63814 KB |
79 | cnt((char *)NULL); |
80 | putchar('\n'); | |
81 | } | |
82 | else { | |
83 | cnt(*argv); | |
2d5da4ef | 84 | printf(" %s\n", *argv); |
66690d0f | 85 | } |
2d5da4ef | 86 | exit(0); |
66690d0f BJ |
87 | } |
88 | ||
93b63814 KB |
89 | /* |
90 | * cat allows "-" as stdin anywhere in the arg list, | |
91 | * might as well here, too. Again, should use "stdin" | |
92 | * as the file name. | |
93 | */ | |
66690d0f | 94 | do { |
2d5da4ef | 95 | if (!strcmp(*argv, "-")) { |
93b63814 KB |
96 | cnt((char *)NULL); |
97 | putchar('\n'); | |
66690d0f | 98 | } |
93b63814 KB |
99 | else { |
100 | cnt(*argv); | |
2d5da4ef | 101 | printf(" %s\n", *argv); |
93b63814 KB |
102 | } |
103 | } while(*++argv); | |
104 | ||
105 | if (doline) | |
2d5da4ef | 106 | printf(" %7ld", tlinect); |
93b63814 | 107 | if (doword) |
2d5da4ef | 108 | printf(" %7ld", twordct); |
93b63814 | 109 | if (dochar) |
2d5da4ef | 110 | printf(" %7ld", tcharct); |
93b63814 | 111 | puts(" total"); |
2d5da4ef | 112 | exit(0); |
93b63814 KB |
113 | } |
114 | ||
115 | static | |
116 | cnt(file) | |
2d5da4ef | 117 | char *file; |
93b63814 | 118 | { |
2d5da4ef KB |
119 | register u_char *C; |
120 | register short gotsp; | |
121 | register int len; | |
122 | register long linect, wordct,charct; | |
123 | struct stat sbuf; | |
124 | int fd; | |
125 | u_char buf[MAXBSIZE]; | |
93b63814 KB |
126 | |
127 | linect = wordct = charct = 0; | |
128 | if (file) { | |
2d5da4ef | 129 | if ((fd = open(file, O_RDONLY, 0)) < 0) { |
93b63814 | 130 | perror(file); |
2d5da4ef | 131 | exit(1); |
93b63814 KB |
132 | } |
133 | if (!doword) { | |
134 | /* | |
135 | * line counting is split out because it's a lot | |
136 | * faster to get lines than to get words, since | |
137 | * the word count requires some logic. | |
138 | */ | |
139 | if (doline) { | |
2d5da4ef | 140 | while(len = read(fd, buf, MAXBSIZE)) { |
93b63814 KB |
141 | if (len == -1) { |
142 | perror(file); | |
2d5da4ef | 143 | exit(1); |
93b63814 KB |
144 | } |
145 | charct += len; | |
2d5da4ef | 146 | for (C = buf; len--; ++C) |
93b63814 KB |
147 | if (*C == '\n') |
148 | ++linect; | |
149 | } | |
150 | tlinect += linect; | |
2d5da4ef | 151 | printf(" %7ld", linect); |
93b63814 KB |
152 | if (dochar) { |
153 | tcharct += charct; | |
2d5da4ef | 154 | printf(" %7ld", sbuf.st_size); |
66690d0f | 155 | } |
93b63814 KB |
156 | close(fd); |
157 | return; | |
66690d0f | 158 | } |
93b63814 KB |
159 | /* |
160 | * if all we need is the number of characters and | |
161 | * it's a directory or a regular or linked file, just | |
162 | * stat the puppy. We avoid testing for it not being | |
163 | * a special device in case someone adds a new type | |
164 | * of inode. | |
165 | */ | |
166 | if (dochar) { | |
2d5da4ef | 167 | if (fstat(fd, &sbuf)) { |
93b63814 | 168 | perror(file); |
2d5da4ef | 169 | exit(1); |
93b63814 KB |
170 | } |
171 | if (sbuf.st_mode & (S_IFREG | S_IFLNK | S_IFDIR)) { | |
2d5da4ef | 172 | printf(" %7ld", sbuf.st_size); |
93b63814 KB |
173 | tcharct += sbuf.st_size; |
174 | close(fd); | |
175 | return; | |
176 | } | |
66690d0f | 177 | } |
66690d0f | 178 | } |
93b63814 KB |
179 | } |
180 | else | |
181 | fd = 0; | |
182 | /* do it the hard way... */ | |
2d5da4ef | 183 | for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) { |
93b63814 KB |
184 | if (len == -1) { |
185 | perror(file); | |
2d5da4ef | 186 | exit(1); |
93b63814 KB |
187 | } |
188 | charct += len; | |
2d5da4ef | 189 | for (C = buf; len--; ++C) |
93b63814 KB |
190 | switch(*C) { |
191 | case NL: | |
192 | ++linect; | |
193 | case TAB: | |
194 | case SPACE: | |
2d5da4ef | 195 | gotsp = 1; |
93b63814 KB |
196 | continue; |
197 | default: | |
2d5da4ef | 198 | #ifdef notdef |
93b63814 KB |
199 | /* |
200 | * This line of code implements the | |
201 | * original V7 wc algorithm, i.e. | |
202 | * a non-printing character doesn't | |
203 | * toggle the "word" count, so that | |
204 | * " ^D^F " counts as 6 spaces, | |
205 | * while "foo^D^Fbar" counts as 8 | |
206 | * characters. | |
207 | * | |
208 | * test order is important -- gotsp | |
209 | * will normally be NO, so test it | |
210 | * first | |
211 | */ | |
212 | if (gotsp && *C > SPACE && *C < DEL) { | |
2d5da4ef | 213 | #endif |
93b63814 KB |
214 | /* |
215 | * This line implements the manual | |
216 | * page, i.e. a word is a "maximal | |
217 | * string of characters delimited by | |
218 | * spaces, tabs or newlines." Notice | |
219 | * nothing was said about a character | |
220 | * being printing or non-printing. | |
221 | */ | |
222 | if (gotsp) { | |
2d5da4ef | 223 | gotsp = 0; |
93b63814 KB |
224 | ++wordct; |
225 | } | |
226 | } | |
227 | } | |
228 | if (doline) { | |
66690d0f | 229 | tlinect += linect; |
2d5da4ef | 230 | printf(" %7ld", linect); |
93b63814 KB |
231 | } |
232 | if (doword) { | |
66690d0f | 233 | twordct += wordct; |
2d5da4ef | 234 | printf(" %7ld", wordct); |
66690d0f | 235 | } |
93b63814 KB |
236 | if (dochar) { |
237 | tcharct += charct; | |
2d5da4ef | 238 | printf(" %7ld", charct); |
66690d0f | 239 | } |
93b63814 | 240 | close(fd); |
66690d0f | 241 | } |