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. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#) Copyright (c) 1980, 1987, 1991, 1993 The Regents of the University of California. All rights reserved. 30 * @(#)wc.c 8.1 (Berkeley) 6/6/93 31 * $FreeBSD: src/usr.bin/wc/wc.c,v 1.11.2.1 2002/08/25 02:47:04 tjr Exp $ 32 * $DragonFly: src/usr.bin/wc/wc.c,v 1.5 2005/02/05 16:07:08 liamfoy Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/stat.h> 37 38 #include <ctype.h> 39 #include <err.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <locale.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 uintmax_t tlinect, twordct, tcharct; 49 int doline, doword, dochar, domulti; 50 51 static int cnt(const char *); 52 static void usage(void); 53 54 int 55 main(int argc, char **argv) 56 { 57 int ch, errors, total; 58 59 setlocale(LC_CTYPE, ""); 60 61 while ((ch = getopt(argc, argv, "clmw")) != -1) { 62 switch (ch) { 63 case 'l': 64 doline = 1; 65 break; 66 case 'w': 67 doword = 1; 68 break; 69 case 'c': 70 dochar = 1; 71 domulti = 0; 72 break; 73 case 'm': 74 domulti = 1; 75 dochar = 0; 76 break; 77 case '?': 78 default: 79 usage(); 80 } 81 } 82 argv += optind; 83 argc -= optind; 84 85 /* Wc's flags are on by default. */ 86 if (doline + doword + dochar + domulti == 0) 87 doline = doword = dochar = 1; 88 89 errors = 0; 90 total = 0; 91 if (*argv == NULL) { 92 if (cnt(NULL) != 0) 93 ++errors; 94 else 95 printf("\n"); 96 } 97 else do { 98 if (cnt(*argv) != 0) 99 ++errors; 100 else 101 printf(" %s\n", *argv); 102 ++total; 103 } while(*++argv); 104 105 if (total > 1) { 106 if (doline) 107 printf(" %7ju", tlinect); 108 if (doword) 109 printf(" %7ju", twordct); 110 if (dochar || domulti) 111 printf(" %7ju", tcharct); 112 printf(" total\n"); 113 } 114 exit(errors == 0 ? 0 : 1); 115 } 116 117 static int 118 cnt(const char *file) 119 { 120 struct stat sb; 121 u_quad_t linect, wordct, charct; 122 ssize_t nread; 123 int clen, fd, len, warned; 124 short gotsp; 125 u_char *p; 126 u_char buf[MAXBSIZE]; 127 wchar_t wch; 128 129 linect = wordct = charct = 0; 130 if (file == NULL) { 131 file = "stdin"; 132 fd = STDIN_FILENO; 133 } else { 134 if ((fd = open(file, O_RDONLY)) < 0) { 135 warn("%s: open", file); 136 return (1); 137 } 138 if (doword || (domulti && MB_CUR_MAX != 1)) 139 goto word; 140 /* 141 * Line counting is split out because it's a lot faster to get 142 * lines than to get words, since the word count requires some 143 * logic. 144 */ 145 if (doline) { 146 while ((len = read(fd, buf, MAXBSIZE))) { 147 if (len == -1) { 148 warn("%s: read", file); 149 close(fd); 150 return (1); 151 } 152 charct += len; 153 for (p = buf; len--; ++p) { 154 if (*p == '\n') 155 ++linect; 156 } 157 } 158 tlinect += linect; 159 printf(" %7ju", linect); 160 if (dochar) { 161 tcharct += charct; 162 printf(" %7ju", charct); 163 } 164 close(fd); 165 return (0); 166 } 167 /* 168 * If all we need is the number of characters and it's a 169 * regular file, just stat the puppy. 170 */ 171 if (dochar || domulti) { 172 if (fstat(fd, &sb)) { 173 warn("%s: fstat", file); 174 close(fd); 175 return (1); 176 } 177 if (S_ISREG(sb.st_mode)) { 178 printf(" %7lld", (long long)sb.st_size); 179 tcharct += sb.st_size; 180 close(fd); 181 return (0); 182 } 183 } 184 } 185 186 /* Do it the hard way... */ 187 word: gotsp = 1; 188 len = 0; 189 warned = 0; 190 while ((nread = read(fd, buf + len, MAXBSIZE - len)) != 0) { 191 if (nread == -1) { 192 warn("%s: read", file); 193 close(fd); 194 return (1); 195 } 196 len += nread; 197 p = buf; 198 while (len > 0) { 199 if (!domulti || MB_CUR_MAX == 1) { 200 clen = 1; 201 wch = (unsigned char)*p; 202 } else if ((clen = mbtowc(&wch, p, len)) <= 0) { 203 if (len > MB_CUR_MAX) { 204 clen = 1; 205 wch = (unsigned char)*p; 206 if (!warned) { 207 errno = EILSEQ; 208 warn("%s", file); 209 warned = 1; 210 } 211 } else { 212 memmove(buf, p, len); 213 break; 214 } 215 } 216 charct++; 217 len -= clen; 218 p += clen; 219 if (wch == L'\n') 220 ++linect; 221 if (isspace(wch)) 222 gotsp = 1; 223 else if (gotsp) { 224 gotsp = 0; 225 ++wordct; 226 } 227 } 228 } 229 if (doline) { 230 tlinect += linect; 231 printf(" %7ju", linect); 232 } 233 if (doword) { 234 twordct += wordct; 235 printf(" %7ju", wordct); 236 } 237 if (dochar || domulti) { 238 tcharct += charct; 239 printf(" %7ju", charct); 240 } 241 close(fd); 242 return (0); 243 } 244 245 static void 246 usage(void) 247 { 248 fprintf(stderr, "usage: wc [-clmw] [file ...]\n"); 249 exit(1); 250 } 251