Annotation of src/usr.bin/wc/wc.c, Revision 1.4
1.4 ! millert 1: /* $OpenBSD: wc.c,v 1.3 1999/02/02 03:44:07 millert Exp $ */
1.2 deraadt 2:
1.1 deraadt 3: /*
1.3 millert 4: * Copyright (c) 1980, 1987, 1991, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 deraadt 6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
1.3 millert 37: static char copyright[] =
38: "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
39: The Regents of the University of California. All rights reserved.\n";
1.1 deraadt 40: #endif /* not lint */
41:
42: #ifndef lint
1.3 millert 43: #if 0
44: static char sccsid[] = "@(#)wc.c 8.2 (Berkeley) 5/2/95";
45: #else
1.4 ! millert 46: static char rcsid[] = "$OpenBSD: wc.c,v 1.3 1999/02/02 03:44:07 millert Exp $";
1.3 millert 47: #endif
1.1 deraadt 48: #endif /* not lint */
49:
50: #include <stdio.h>
51: #include <stdlib.h>
52: #include <string.h>
53: #include <locale.h>
54: #include <ctype.h>
1.3 millert 55: #include <err.h>
1.1 deraadt 56: #include <sys/param.h>
57: #include <sys/stat.h>
58: #include <sys/file.h>
59: #include <unistd.h>
60:
1.3 millert 61: int64_t tlinect, twordct, tcharct;
62: int doline, doword, dochar;
63: int rval;
64: extern char *__progname;
65:
66: void print_counts __P((int64_t, int64_t, int64_t, char *));
67: void cnt __P((char *));
1.1 deraadt 68:
69: int
70: main(argc, argv)
71: int argc;
1.3 millert 72: char *argv[];
1.1 deraadt 73: {
74: register int ch;
75:
76: setlocale(LC_ALL, "");
77:
78: while ((ch = getopt(argc, argv, "lwcm")) != -1)
79: switch((char)ch) {
80: case 'l':
81: doline = 1;
82: break;
83: case 'w':
84: doword = 1;
85: break;
86: case 'c':
87: case 'm':
88: dochar = 1;
89: break;
90: case '?':
91: default:
1.3 millert 92: (void)fprintf(stderr,
93: "usage: %s [-c | -m] [-lw] [file ...]\n",
94: __progname);
1.1 deraadt 95: exit(1);
96: }
97: argv += optind;
98: argc -= optind;
99:
100: /*
101: * wc is unusual in that its flags are on by default, so,
102: * if you don't get any arguments, you have to turn them
103: * all on.
104: */
1.3 millert 105: if (!doline && !doword && !dochar)
1.1 deraadt 106: doline = doword = dochar = 1;
107:
108: if (!*argv) {
109: cnt((char *)NULL);
110: } else {
111: int dototal = (argc > 1);
112:
113: do {
114: cnt(*argv);
115: } while(*++argv);
116:
1.3 millert 117: if (dototal)
118: print_counts(tlinect, twordct, tcharct, "total");
1.1 deraadt 119: }
120:
121: exit(rval);
122: }
123:
1.3 millert 124: void
1.1 deraadt 125: cnt(file)
126: char *file;
127: {
128: register u_char *C;
129: register short gotsp;
130: register int len;
1.3 millert 131: register int64_t linect, wordct, charct;
1.1 deraadt 132: struct stat sbuf;
133: int fd;
134: u_char buf[MAXBSIZE];
135:
136: linect = wordct = charct = 0;
137: if (file) {
138: if ((fd = open(file, O_RDONLY, 0)) < 0) {
1.3 millert 139: warn("%s", file);
1.1 deraadt 140: rval = 1;
141: return;
142: }
143: } else {
144: fd = STDIN_FILENO;
145: }
146:
147: if (!doword) {
148: /*
1.3 millert 149: * Line counting is split out because it's a lot
1.1 deraadt 150: * faster to get lines than to get words, since
151: * the word count requires some logic.
152: */
153: if (doline) {
1.3 millert 154: while ((len = read(fd, buf, MAXBSIZE)) > 0) {
1.1 deraadt 155: charct += len;
156: for (C = buf; len--; ++C)
157: if (*C == '\n')
158: ++linect;
159: }
160: if (len == -1) {
1.3 millert 161: warn("%s", file);
1.1 deraadt 162: rval = 1;
163: }
164: }
165: /*
1.3 millert 166: * If all we need is the number of characters and
1.1 deraadt 167: * it's a directory or a regular or linked file, just
168: * stat the puppy. We avoid testing for it not being
169: * a special device in case someone adds a new type
170: * of inode.
171: */
172: else if (dochar) {
1.3 millert 173: mode_t ifmt;
1.1 deraadt 174:
175: if (fstat(fd, &sbuf)) {
1.3 millert 176: warn("%s", file);
1.1 deraadt 177: rval = 1;
178: } else {
179: ifmt = sbuf.st_mode & S_IFMT;
180: if (ifmt == S_IFREG || ifmt == S_IFLNK
1.3 millert 181: || ifmt == S_IFDIR) {
1.1 deraadt 182: charct = sbuf.st_size;
183: } else {
1.3 millert 184: while ((len = read(fd, buf, MAXBSIZE)) > 0)
1.1 deraadt 185: charct += len;
186: if (len == -1) {
1.3 millert 187: warn("%s", file);
1.1 deraadt 188: rval = 1;
189: }
190: }
191: }
192: }
1.3 millert 193: } else {
194: /* Do it the hard way... */
1.1 deraadt 195: gotsp = 1;
196: while ((len = read(fd, buf, MAXBSIZE)) > 0) {
1.3 millert 197: /*
198: * This loses in the presence of multi-byte characters.
199: * To do it right would require a function to return a
200: * character while knowing how many bytes it consumed.
201: */
1.1 deraadt 202: charct += len;
203: for (C = buf; len--; ++C) {
204: if (isspace (*C)) {
205: gotsp = 1;
1.3 millert 206: if (*C == '\n')
1.1 deraadt 207: ++linect;
208: } else {
209: /*
210: * This line implements the POSIX
211: * spec, i.e. a word is a "maximal
212: * string of characters delimited by
213: * whitespace." Notice nothing was
214: * said about a character being
215: * printing or non-printing.
216: */
217: if (gotsp) {
218: gotsp = 0;
219: ++wordct;
220: }
221: }
222: }
223: }
224: if (len == -1) {
1.3 millert 225: warn("%s", file);
1.1 deraadt 226: rval = 1;
227: }
228: }
229:
1.3 millert 230: print_counts(linect, wordct, charct, file ? file : "");
1.1 deraadt 231:
1.3 millert 232: /*
233: * Don't bother checking doline, doword, or dochar -- speeds
234: * up the common case
235: */
1.1 deraadt 236: tlinect += linect;
237: twordct += wordct;
238: tcharct += charct;
239:
1.3 millert 240: if (close(fd) != 0) {
241: warn("%s", file);
1.1 deraadt 242: rval = 1;
243: }
244: }
245:
246: void
1.3 millert 247: print_counts(lines, words, chars, name)
248: int64_t lines;
249: int64_t words;
250: int64_t chars;
1.1 deraadt 251: char *name;
252: {
253:
254: if (doline)
1.4 ! millert 255: (void)printf(" %7qd", lines);
1.1 deraadt 256: if (doword)
1.4 ! millert 257: (void)printf(" %7qd", words);
1.1 deraadt 258: if (dochar)
1.4 ! millert 259: (void)printf(" %7qd", chars);
1.1 deraadt 260:
1.3 millert 261: (void)printf(" %s\n", name);
1.1 deraadt 262: }