BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / wc / wc.c
CommitLineData
f42904bc 1/*
2d5da4ef
KB
2 * Copyright (c) 1980, 1987 Regents of the University of California.
3 * All rights reserved.
4 *
af359dea
C
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
f42904bc
DF
32 */
33
34#ifndef lint
35char copyright[] =
2d5da4ef 36"@(#) Copyright (c) 1980, 1987 Regents of the University of California.\n\
f42904bc 37 All rights reserved.\n";
2d5da4ef 38#endif /* not lint */
f42904bc
DF
39
40#ifndef lint
af359dea 41static char sccsid[] = "@(#)wc.c 5.7 (Berkeley) 3/2/91";
2d5da4ef 42#endif /* not lint */
f42904bc 43
93b63814 44/* wc line, word and char count */
66690d0f 45
93b63814
KB
46#include <sys/param.h>
47#include <sys/stat.h>
48#include <sys/file.h>
66690d0f 49#include <stdio.h>
66690d0f 50
93b63814 51#define DEL 0177 /* del char */
93b63814 52#define NL 012 /* newline char */
93b63814
KB
53#define SPACE 040 /* space char */
54#define TAB 011 /* tab char */
93b63814 55
2d5da4ef 56static long tlinect, twordct, tcharct;
e4e131e4 57static int doline, doword, dochar;
93b63814 58
e4e131e4 59main(argc, argv)
2d5da4ef
KB
60 int argc;
61 char **argv;
66690d0f 62{
2d5da4ef
KB
63 extern int optind;
64 register int ch;
e4e131e4 65 int total;
66690d0f 66
93b63814
KB
67 /*
68 * wc is unusual in that its flags are on by default, so,
69 * if you don't get any arguments, you have to turn them
70 * all on.
71 */
72 if (argc > 1 && argv[1][0] == '-' && argv[1][1]) {
e4e131e4 73 while ((ch = getopt(argc, argv, "lwc")) != EOF)
93b63814 74 switch((char)ch) {
2d5da4ef
KB
75 case 'l':
76 doline = 1;
77 break;
78 case 'w':
79 doword = 1;
80 break;
81 case 'c':
82 dochar = 1;
83 break;
84 case '?':
85 default:
e4e131e4 86 fputs("usage: wc [-lwc] [files]\n", stderr);
2d5da4ef 87 exit(1);
93b63814
KB
88 }
89 argv += optind;
90 argc -= optind;
91 }
92 else {
93 ++argv;
94 --argc;
2d5da4ef 95 doline = doword = dochar = 1;
93b63814
KB
96 }
97
e4e131e4
KB
98 total = 0;
99 if (!*argv) {
100 cnt((char *)NULL);
101 putchar('\n');
66690d0f 102 }
e4e131e4
KB
103 else do {
104 cnt(*argv);
105 printf(" %s\n", *argv);
106 ++total;
93b63814
KB
107 } while(*++argv);
108
e4e131e4
KB
109 if (total > 1) {
110 if (doline)
111 printf(" %7ld", tlinect);
112 if (doword)
113 printf(" %7ld", twordct);
114 if (dochar)
115 printf(" %7ld", tcharct);
116 puts(" total");
117 }
2d5da4ef 118 exit(0);
93b63814
KB
119}
120
93b63814 121cnt(file)
2d5da4ef 122 char *file;
93b63814 123{
2d5da4ef
KB
124 register u_char *C;
125 register short gotsp;
126 register int len;
e4e131e4 127 register long linect, wordct, charct;
2d5da4ef
KB
128 struct stat sbuf;
129 int fd;
130 u_char buf[MAXBSIZE];
93b63814
KB
131
132 linect = wordct = charct = 0;
133 if (file) {
2d5da4ef 134 if ((fd = open(file, O_RDONLY, 0)) < 0) {
93b63814 135 perror(file);
2d5da4ef 136 exit(1);
93b63814
KB
137 }
138 if (!doword) {
139 /*
140 * line counting is split out because it's a lot
141 * faster to get lines than to get words, since
142 * the word count requires some logic.
143 */
144 if (doline) {
2d5da4ef 145 while(len = read(fd, buf, MAXBSIZE)) {
93b63814
KB
146 if (len == -1) {
147 perror(file);
2d5da4ef 148 exit(1);
93b63814
KB
149 }
150 charct += len;
2d5da4ef 151 for (C = buf; len--; ++C)
93b63814
KB
152 if (*C == '\n')
153 ++linect;
154 }
155 tlinect += linect;
2d5da4ef 156 printf(" %7ld", linect);
93b63814
KB
157 if (dochar) {
158 tcharct += charct;
e4e131e4 159 printf(" %7ld", charct);
66690d0f 160 }
93b63814
KB
161 close(fd);
162 return;
66690d0f 163 }
93b63814
KB
164 /*
165 * if all we need is the number of characters and
166 * it's a directory or a regular or linked file, just
167 * stat the puppy. We avoid testing for it not being
168 * a special device in case someone adds a new type
169 * of inode.
170 */
171 if (dochar) {
2d5da4ef 172 if (fstat(fd, &sbuf)) {
93b63814 173 perror(file);
2d5da4ef 174 exit(1);
93b63814
KB
175 }
176 if (sbuf.st_mode & (S_IFREG | S_IFLNK | S_IFDIR)) {
2d5da4ef 177 printf(" %7ld", sbuf.st_size);
93b63814
KB
178 tcharct += sbuf.st_size;
179 close(fd);
180 return;
181 }
66690d0f 182 }
66690d0f 183 }
93b63814
KB
184 }
185 else
186 fd = 0;
187 /* do it the hard way... */
2d5da4ef 188 for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) {
93b63814
KB
189 if (len == -1) {
190 perror(file);
2d5da4ef 191 exit(1);
93b63814
KB
192 }
193 charct += len;
2d5da4ef 194 for (C = buf; len--; ++C)
93b63814
KB
195 switch(*C) {
196 case NL:
197 ++linect;
198 case TAB:
199 case SPACE:
2d5da4ef 200 gotsp = 1;
93b63814
KB
201 continue;
202 default:
2d5da4ef 203#ifdef notdef
93b63814
KB
204 /*
205 * This line of code implements the
206 * original V7 wc algorithm, i.e.
207 * a non-printing character doesn't
208 * toggle the "word" count, so that
209 * " ^D^F " counts as 6 spaces,
210 * while "foo^D^Fbar" counts as 8
211 * characters.
212 *
213 * test order is important -- gotsp
214 * will normally be NO, so test it
215 * first
216 */
217 if (gotsp && *C > SPACE && *C < DEL) {
2d5da4ef 218#endif
93b63814
KB
219 /*
220 * This line implements the manual
221 * page, i.e. a word is a "maximal
222 * string of characters delimited by
223 * spaces, tabs or newlines." Notice
224 * nothing was said about a character
225 * being printing or non-printing.
226 */
227 if (gotsp) {
2d5da4ef 228 gotsp = 0;
93b63814
KB
229 ++wordct;
230 }
231 }
232 }
233 if (doline) {
66690d0f 234 tlinect += linect;
2d5da4ef 235 printf(" %7ld", linect);
93b63814
KB
236 }
237 if (doword) {
66690d0f 238 twordct += wordct;
2d5da4ef 239 printf(" %7ld", wordct);
66690d0f 240 }
93b63814
KB
241 if (dochar) {
242 tcharct += charct;
2d5da4ef 243 printf(" %7ld", charct);
66690d0f 244 }
93b63814 245 close(fd);
66690d0f 246}