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.9 1994/01/03 03:11:06 andrew Exp $"; 43 #endif /* not lint */ 44 45 /* wc line, word and char count */ 46 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <locale.h> 51 #include <ctype.h> 52 #include <errno.h> 53 #include <sys/param.h> 54 #include <sys/stat.h> 55 #include <sys/file.h> 56 #include <unistd.h> 57 #include <err.h> 58 59 static void print_counts(); 60 static void cnt(); 61 static long tlinect, twordct, tcharct; 62 static int doline, doword, dochar; 63 static int rval = 0; 64 65 int 66 main(argc, argv) 67 int argc; 68 char **argv; 69 { 70 extern int optind; 71 register int ch; 72 73 setlocale(LC_ALL, ""); 74 75 while ((ch = getopt(argc, argv, "lwcm")) != -1) 76 switch((char)ch) { 77 case 'l': 78 doline = 1; 79 break; 80 case 'w': 81 doword = 1; 82 break; 83 case 'c': 84 case 'm': 85 dochar = 1; 86 break; 87 case '?': 88 default: 89 fprintf(stderr, "usage: wc [-c | -m] [-lw] [file ...]\n"); 90 exit(1); 91 } 92 argv += optind; 93 argc -= optind; 94 95 /* 96 * wc is unusual in that its flags are on by default, so, 97 * if you don't get any arguments, you have to turn them 98 * all on. 99 */ 100 if (!doline && !doword && !dochar) { 101 doline = doword = dochar = 1; 102 } 103 104 if (!*argv) { 105 cnt((char *)NULL); 106 } else { 107 int dototal = (argc > 1); 108 109 do { 110 cnt(*argv); 111 } while(*++argv); 112 113 if (dototal) { 114 print_counts (tlinect, twordct, tcharct, "total"); 115 } 116 } 117 118 exit(rval); 119 } 120 121 122 static void 123 cnt(file) 124 char *file; 125 { 126 register u_char *C; 127 register short gotsp; 128 register int len; 129 register long linect, wordct, charct; 130 struct stat sbuf; 131 int fd; 132 u_char buf[MAXBSIZE]; 133 134 linect = wordct = charct = 0; 135 if (file) { 136 if ((fd = open(file, O_RDONLY, 0)) < 0) { 137 warn ("%s", file); 138 rval = 1; 139 return; 140 } 141 } else { 142 fd = STDIN_FILENO; 143 } 144 145 if (!doword) { 146 /* 147 * line counting is split out because it's a lot 148 * faster to get lines than to get words, since 149 * the word count requires some logic. 150 */ 151 if (doline) { 152 while((len = read(fd, buf, MAXBSIZE)) > 0) { 153 charct += len; 154 for (C = buf; len--; ++C) 155 if (*C == '\n') 156 ++linect; 157 } 158 if (len == -1) { 159 warn ("%s", file); 160 rval = 1; 161 } 162 } 163 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 else if (dochar) { 172 int ifmt; 173 174 if (fstat(fd, &sbuf)) { 175 warn ("%s", file); 176 rval = 1; 177 } else { 178 ifmt = sbuf.st_mode & S_IFMT; 179 if (ifmt == S_IFREG || ifmt == S_IFLNK 180 || ifmt == S_IFDIR) { 181 charct = sbuf.st_size; 182 } else { 183 while((len = read(fd, buf, MAXBSIZE)) > 0) 184 charct += len; 185 if (len == -1) { 186 warn ("%s", file); 187 rval = 1; 188 } 189 } 190 } 191 } 192 } 193 else 194 { 195 /* do it the hard way... */ 196 gotsp = 1; 197 while ((len = read(fd, buf, MAXBSIZE)) > 0) { 198 charct += len; 199 for (C = buf; len--; ++C) { 200 if (isspace (*C)) { 201 gotsp = 1; 202 if (*C == '\n') { 203 ++linect; 204 } 205 } else { 206 /* 207 * This line implements the POSIX 208 * spec, i.e. a word is a "maximal 209 * string of characters delimited by 210 * whitespace." Notice nothing was 211 * said about a character being 212 * printing or non-printing. 213 */ 214 if (gotsp) { 215 gotsp = 0; 216 ++wordct; 217 } 218 } 219 } 220 } 221 if (len == -1) { 222 warn ("%s", file); 223 rval = 1; 224 } 225 } 226 227 print_counts (linect, wordct, charct, file ? file : ""); 228 229 /* don't bother checkint doline, doword, or dochar --- speeds 230 up the common case */ 231 tlinect += linect; 232 twordct += wordct; 233 tcharct += charct; 234 235 if (close(fd)) { 236 warn ("%s", file); 237 rval = 1; 238 } 239 } 240 241 242 void 243 print_counts (lines, words, chars, name) 244 long lines; 245 long words; 246 long chars; 247 char *name; 248 { 249 250 if (doline) 251 printf(" %7ld", lines); 252 if (doword) 253 printf(" %7ld", words); 254 if (dochar) 255 printf(" %7ld", chars); 256 257 printf (" %s\n", name); 258 } 259