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