rationalized handling of child processes, cleaned up mail1 some more
[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 *
5 * Redistribution and use in source and binary forms are permitted
5e8b0e60
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
f42904bc
DF
16 */
17
18#ifndef lint
19char copyright[] =
2d5da4ef 20"@(#) Copyright (c) 1980, 1987 Regents of the University of California.\n\
f42904bc 21 All rights reserved.\n";
2d5da4ef 22#endif /* not lint */
f42904bc
DF
23
24#ifndef lint
5e8b0e60 25static char sccsid[] = "@(#)wc.c 5.4 (Berkeley) %G%";
2d5da4ef 26#endif /* not lint */
f42904bc 27
93b63814 28/* wc line, word and char count */
66690d0f 29
93b63814
KB
30#include <sys/param.h>
31#include <sys/stat.h>
32#include <sys/file.h>
66690d0f 33#include <stdio.h>
66690d0f 34
93b63814 35#define DEL 0177 /* del char */
93b63814 36#define NL 012 /* newline char */
93b63814
KB
37#define SPACE 040 /* space char */
38#define TAB 011 /* tab char */
93b63814 39
2d5da4ef
KB
40static long tlinect, twordct, tcharct;
41static int doline, doword, dochar;
93b63814
KB
42
43main(argc,argv)
2d5da4ef
KB
44 int argc;
45 char **argv;
66690d0f 46{
2d5da4ef
KB
47 extern int optind;
48 register int ch;
66690d0f 49
93b63814
KB
50 /*
51 * wc is unusual in that its flags are on by default, so,
52 * if you don't get any arguments, you have to turn them
53 * all on.
54 */
55 if (argc > 1 && argv[1][0] == '-' && argv[1][1]) {
56 while ((ch = getopt(argc,argv,"lwc")) != EOF)
57 switch((char)ch) {
2d5da4ef
KB
58 case 'l':
59 doline = 1;
60 break;
61 case 'w':
62 doword = 1;
63 break;
64 case 'c':
65 dochar = 1;
66 break;
67 case '?':
68 default:
69 fputs("usage: wc [-lwc] [files]\n",stderr);
70 exit(1);
93b63814
KB
71 }
72 argv += optind;
73 argc -= optind;
74 }
75 else {
76 ++argv;
77 --argc;
2d5da4ef 78 doline = doword = dochar = 1;
93b63814
KB
79 }
80
81 /* should print "stdin" as the file name, here */
82 if (argc <= 1) {
2d5da4ef 83 if (!*argv || !strcmp(*argv, "-")) {
93b63814
KB
84 cnt((char *)NULL);
85 putchar('\n');
86 }
87 else {
88 cnt(*argv);
2d5da4ef 89 printf(" %s\n", *argv);
66690d0f 90 }
2d5da4ef 91 exit(0);
66690d0f
BJ
92 }
93
93b63814
KB
94 /*
95 * cat allows "-" as stdin anywhere in the arg list,
96 * might as well here, too. Again, should use "stdin"
97 * as the file name.
98 */
66690d0f 99 do {
2d5da4ef 100 if (!strcmp(*argv, "-")) {
93b63814
KB
101 cnt((char *)NULL);
102 putchar('\n');
66690d0f 103 }
93b63814
KB
104 else {
105 cnt(*argv);
2d5da4ef 106 printf(" %s\n", *argv);
93b63814
KB
107 }
108 } while(*++argv);
109
110 if (doline)
2d5da4ef 111 printf(" %7ld", tlinect);
93b63814 112 if (doword)
2d5da4ef 113 printf(" %7ld", twordct);
93b63814 114 if (dochar)
2d5da4ef 115 printf(" %7ld", tcharct);
93b63814 116 puts(" total");
2d5da4ef 117 exit(0);
93b63814
KB
118}
119
120static
121cnt(file)
2d5da4ef 122 char *file;
93b63814 123{
2d5da4ef
KB
124 register u_char *C;
125 register short gotsp;
126 register int len;
127 register long linect, wordct,charct;
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;
2d5da4ef 159 printf(" %7ld", sbuf.st_size);
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}