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