1 /* $NetBSD: wc.c,v 1.12 1997/10/19 19:33:37 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1987, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 static char copyright[] = 38 "@(#) Copyright (c) 1980, 1987, 1991, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"; 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)wc.c 8.2 (Berkeley) 5/2/95"; 45 #else 46 static char rcsid[] = "$NetBSD: wc.c,v 1.12 1997/10/19 19:33:37 mycroft Exp $"; 47 #endif 48 #endif /* not lint */ 49 50 /* wc line, word and char count */ 51 52 #include <sys/param.h> 53 #include <sys/stat.h> 54 55 #include <fcntl.h> 56 #include <unistd.h> 57 #include <errno.h> 58 #include <stdio.h> 59 60 #include <stdlib.h> 61 #include <string.h> 62 #include <locale.h> 63 #include <ctype.h> 64 #include <errno.h> 65 #include <sys/param.h> 66 #include <sys/stat.h> 67 #include <sys/file.h> 68 #include <unistd.h> 69 #include <err.h> 70 71 static ulong tlinect, twordct, tcharct; 72 static int doline, doword, dochar; 73 static int rval = 0; 74 75 static void cnt __P((char *)); 76 static void print_counts __P((long, long, long, char *)); 77 static void usage __P((void)); 78 79 int 80 main(argc, argv) 81 int argc; 82 char *argv[]; 83 { 84 register int ch; 85 86 setlocale(LC_ALL, ""); 87 88 while ((ch = getopt(argc, argv, "lwcm")) != -1) 89 switch((char)ch) { 90 case 'l': 91 doline = 1; 92 break; 93 case 'w': 94 doword = 1; 95 break; 96 case 'c': 97 case 'm': 98 dochar = 1; 99 break; 100 case '?': 101 default: 102 usage(); 103 } 104 argv += optind; 105 argc -= optind; 106 107 /* Wc's flags are on by default. */ 108 if (doline + doword + dochar == 0) 109 doline = doword = dochar = 1; 110 111 if (!*argv) { 112 cnt(NULL); 113 } else { 114 int dototal = (argc > 1); 115 116 do { 117 cnt(*argv); 118 } while(*++argv); 119 120 if (dototal) { 121 print_counts(tlinect, twordct, tcharct, "total"); 122 } 123 } 124 125 exit(rval); 126 } 127 128 static void 129 cnt(file) 130 char *file; 131 { 132 register u_char *C; 133 register short gotsp; 134 register int ch, len; 135 register u_long linect, wordct, charct; 136 struct stat sb; 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 warn("%s", file); 144 rval = 1; 145 return; 146 } 147 } else { 148 fd = STDIN_FILENO; 149 } 150 151 if (!doword) { 152 /* 153 * line counting is split out because it's a lot 154 * faster to get lines than to get words, since 155 * the word count requires some logic. 156 */ 157 if (doline) { 158 while ((len = read(fd, buf, MAXBSIZE)) > 0) { 159 charct += len; 160 for (C = buf; len--; ++C) 161 if (*C == '\n') 162 ++linect; 163 } 164 if (len == -1) { 165 warn ("%s", file); 166 rval = 1; 167 } 168 } 169 170 /* 171 * if all we need is the number of characters and 172 * it's a directory or a regular or linked file, just 173 * stat the puppy. We avoid testing for it not being 174 * a special device in case someone adds a new type 175 * of inode. 176 */ 177 else if (dochar) { 178 if (fstat(fd, &sb)) { 179 warn("%s", file); 180 rval = 1; 181 } else { 182 if (S_ISREG(sb.st_mode) || 183 S_ISLNK(sb.st_mode) || 184 S_ISDIR(sb.st_mode)) { 185 charct = sb.st_size; 186 } else { 187 while ((len = read(fd, buf, MAXBSIZE)) > 0) 188 charct += len; 189 if (len == -1) { 190 warn ("%s", file); 191 rval = 1; 192 } 193 } 194 } 195 } 196 } 197 else 198 { 199 /* do it the hard way... */ 200 gotsp = 1; 201 while ((len = read(fd, buf, MAXBSIZE)) > 0) { 202 charct += len; 203 for (C = buf; len--; ++C) { 204 if (isspace(*C)) { 205 gotsp = 1; 206 if (*C == '\n') { 207 ++linect; 208 } 209 } else { 210 /* 211 * This line implements the POSIX 212 * spec, i.e. a word is a "maximal 213 * string of characters delimited by 214 * whitespace." Notice nothing was 215 * said about a character being 216 * printing or non-printing. 217 */ 218 if (gotsp) { 219 gotsp = 0; 220 ++wordct; 221 } 222 } 223 } 224 } 225 if (len == -1) { 226 warn("%s", file); 227 rval = 1; 228 } 229 } 230 231 print_counts(linect, wordct, charct, file ? file : ""); 232 233 /* don't bother checkint doline, doword, or dochar --- speeds 234 up the common case */ 235 tlinect += linect; 236 twordct += wordct; 237 tcharct += charct; 238 239 if (close(fd)) { 240 warn ("%s", file); 241 rval = 1; 242 } 243 } 244 245 static void 246 print_counts(lines, words, chars, name) 247 long lines; 248 long words; 249 long chars; 250 char *name; 251 { 252 253 if (doline) 254 printf(" %7ld", lines); 255 if (doword) 256 printf(" %7ld", words); 257 if (dochar) 258 printf(" %7ld", chars); 259 260 printf(" %s\n", name); 261 } 262 263 static void 264 usage() 265 { 266 (void)fprintf(stderr, "usage: wc [-clw] [files]\n"); 267 exit(1); 268 } 269