add Berkeley header; format a little better
[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
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
14char 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
20static 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
35static long tlinect, twordct, tcharct;
36static int doline, doword, dochar;
93b63814
KB
37
38main(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
115static
116cnt(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}