1 /* 2 * Copyright (c) 1980, 1987, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)wc.c 8.2 (Berkeley) 05/02/95"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 #include <fcntl.h> 21 #include <unistd.h> 22 #include <errno.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <ctype.h> 27 28 u_long tlinect, twordct, tcharct; 29 int doline, doword, dochar; 30 31 void cnt __P((char *)); 32 void err __P((const char *, ...)); 33 void usage __P((void)); 34 35 int 36 main(argc, argv) 37 int argc; 38 char *argv[]; 39 { 40 register int ch; 41 int total; 42 43 while ((ch = getopt(argc, argv, "lwc")) != EOF) 44 switch((char)ch) { 45 case 'l': 46 doline = 1; 47 break; 48 case 'w': 49 doword = 1; 50 break; 51 case 'c': 52 dochar = 1; 53 break; 54 case '?': 55 default: 56 usage(); 57 } 58 argv += optind; 59 argc -= optind; 60 61 /* Wc's flags are on by default. */ 62 if (doline + doword + dochar == 0) 63 doline = doword = dochar = 1; 64 65 total = 0; 66 if (!*argv) { 67 cnt(NULL); 68 (void)printf("\n"); 69 } 70 else do { 71 cnt(*argv); 72 (void)printf(" %s\n", *argv); 73 ++total; 74 } while(*++argv); 75 76 if (total > 1) { 77 if (doline) 78 (void)printf(" %7ld", tlinect); 79 if (doword) 80 (void)printf(" %7ld", twordct); 81 if (dochar) 82 (void)printf(" %7ld", tcharct); 83 (void)printf(" total\n"); 84 } 85 exit(0); 86 } 87 88 void 89 cnt(file) 90 char *file; 91 { 92 register u_char *p; 93 register short gotsp; 94 register int ch, len; 95 register u_long linect, wordct, charct; 96 struct stat sb; 97 int fd; 98 u_char buf[MAXBSIZE]; 99 100 fd = STDIN_FILENO; 101 linect = wordct = charct = 0; 102 if (file) { 103 if ((fd = open(file, O_RDONLY, 0)) < 0) 104 err("%s: %s", file, strerror(errno)); 105 if (doword) 106 goto word; 107 /* 108 * Line counting is split out because it's a lot faster to get 109 * lines than to get words, since the word count requires some 110 * logic. 111 */ 112 if (doline) { 113 while (len = read(fd, buf, MAXBSIZE)) { 114 if (len == -1) 115 err("%s: %s", file, strerror(errno)); 116 charct += len; 117 for (p = buf; len--; ++p) 118 if (*p == '\n') 119 ++linect; 120 } 121 tlinect += linect; 122 (void)printf(" %7lu", linect); 123 if (dochar) { 124 tcharct += charct; 125 (void)printf(" %7lu", charct); 126 } 127 (void)close(fd); 128 return; 129 } 130 /* 131 * If all we need is the number of characters and it's a 132 * regular or linked file, just stat the puppy. 133 */ 134 if (dochar) { 135 if (fstat(fd, &sb)) 136 err("%s: %s", file, strerror(errno)); 137 if (S_ISREG(sb.st_mode)) { 138 (void)printf(" %7qu", sb.st_size); 139 tcharct += sb.st_size; 140 (void)close(fd); 141 return; 142 } 143 } 144 } 145 146 /* Do it the hard way... */ 147 word: for (gotsp = 1; len = read(fd, buf, MAXBSIZE);) { 148 if (len == -1) 149 err("%s: %s", file, strerror(errno)); 150 /* 151 * This loses in the presence of multi-byte characters. 152 * To do it right would require a function to return a 153 * character while knowing how many bytes it consumed. 154 */ 155 charct += len; 156 for (p = buf; len--;) { 157 ch = *p++; 158 if (ch == '\n') 159 ++linect; 160 if (isspace(ch)) 161 gotsp = 1; 162 else if (gotsp) { 163 gotsp = 0; 164 ++wordct; 165 } 166 } 167 } 168 if (doline) { 169 tlinect += linect; 170 (void)printf(" %7lu", linect); 171 } 172 if (doword) { 173 twordct += wordct; 174 (void)printf(" %7lu", wordct); 175 } 176 if (dochar) { 177 tcharct += charct; 178 (void)printf(" %7lu", charct); 179 } 180 (void)close(fd); 181 } 182 183 void 184 usage() 185 { 186 (void)fprintf(stderr, "usage: wc [-clw] [files]\n"); 187 exit(1); 188 } 189 190 #if __STDC__ 191 #include <stdarg.h> 192 #else 193 #include <varargs.h> 194 #endif 195 196 void 197 #if __STDC__ 198 err(const char *fmt, ...) 199 #else 200 err(fmt, va_alist) 201 char *fmt; 202 va_dcl 203 #endif 204 { 205 va_list ap; 206 #if __STDC__ 207 va_start(ap, fmt); 208 #else 209 va_start(ap); 210 #endif 211 (void)fprintf(stderr, "wc: "); 212 (void)vfprintf(stderr, fmt, ap); 213 va_end(ap); 214 (void)fprintf(stderr, "\n"); 215 exit(1); 216 /* NOTREACHED */ 217 } 218