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