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