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 35 static const 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 #if 0 41 #ifndef lint 42 static char sccsid[] = "@(#)wc.c 8.1 (Berkeley) 6/6/93"; 43 #endif /* not lint */ 44 #endif 45 46 #include <sys/cdefs.h> 47 __FBSDID("$FreeBSD$"); 48 49 #include <sys/param.h> 50 #include <sys/stat.h> 51 52 #include <ctype.h> 53 #include <err.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <locale.h> 57 #include <stdint.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <unistd.h> 62 #include <wchar.h> 63 #include <wctype.h> 64 65 uintmax_t tlinect, twordct, tcharct; 66 int doline, doword, dochar, domulti; 67 68 static int cnt(const char *); 69 static void usage(void); 70 71 int 72 main(int argc, char *argv[]) 73 { 74 int ch, errors, total; 75 76 (void) setlocale(LC_CTYPE, ""); 77 78 while ((ch = getopt(argc, argv, "clmw")) != -1) 79 switch((char)ch) { 80 case 'l': 81 doline = 1; 82 break; 83 case 'w': 84 doword = 1; 85 break; 86 case 'c': 87 dochar = 1; 88 domulti = 0; 89 break; 90 case 'm': 91 domulti = 1; 92 dochar = 0; 93 break; 94 case '?': 95 default: 96 usage(); 97 } 98 argv += optind; 99 argc -= optind; 100 101 /* Wc's flags are on by default. */ 102 if (doline + doword + dochar + domulti == 0) 103 doline = doword = dochar = 1; 104 105 errors = 0; 106 total = 0; 107 if (!*argv) { 108 if (cnt((char *)NULL) != 0) 109 ++errors; 110 else 111 (void)printf("\n"); 112 } 113 else do { 114 if (cnt(*argv) != 0) 115 ++errors; 116 else 117 (void)printf(" %s\n", *argv); 118 ++total; 119 } while(*++argv); 120 121 if (total > 1) { 122 if (doline) 123 (void)printf(" %7ju", tlinect); 124 if (doword) 125 (void)printf(" %7ju", twordct); 126 if (dochar || domulti) 127 (void)printf(" %7ju", tcharct); 128 (void)printf(" total\n"); 129 } 130 exit(errors == 0 ? 0 : 1); 131 } 132 133 static int 134 cnt(const char *file) 135 { 136 struct stat sb; 137 uintmax_t linect, wordct, charct; 138 int fd, len, warned; 139 size_t clen; 140 short gotsp; 141 u_char *p; 142 u_char buf[MAXBSIZE]; 143 wchar_t wch; 144 mbstate_t mbs; 145 146 linect = wordct = charct = 0; 147 if (file == NULL) { 148 file = "stdin"; 149 fd = STDIN_FILENO; 150 } else { 151 if ((fd = open(file, O_RDONLY, 0)) < 0) { 152 warn("%s: open", file); 153 return (1); 154 } 155 if (doword || (domulti && MB_CUR_MAX != 1)) 156 goto word; 157 /* 158 * Line counting is split out because it's a lot faster to get 159 * lines than to get words, since the word count requires some 160 * logic. 161 */ 162 if (doline) { 163 while ((len = read(fd, buf, MAXBSIZE))) { 164 if (len == -1) { 165 warn("%s: read", file); 166 (void)close(fd); 167 return (1); 168 } 169 charct += len; 170 for (p = buf; len--; ++p) 171 if (*p == '\n') 172 ++linect; 173 } 174 tlinect += linect; 175 (void)printf(" %7ju", linect); 176 if (dochar) { 177 tcharct += charct; 178 (void)printf(" %7ju", charct); 179 } 180 (void)close(fd); 181 return (0); 182 } 183 /* 184 * If all we need is the number of characters and it's a 185 * regular file, just stat the puppy. 186 */ 187 if (dochar || domulti) { 188 if (fstat(fd, &sb)) { 189 warn("%s: fstat", file); 190 (void)close(fd); 191 return (1); 192 } 193 if (S_ISREG(sb.st_mode)) { 194 (void)printf(" %7lld", (long long)sb.st_size); 195 tcharct += sb.st_size; 196 (void)close(fd); 197 return (0); 198 } 199 } 200 } 201 202 /* Do it the hard way... */ 203 word: gotsp = 1; 204 warned = 0; 205 memset(&mbs, 0, sizeof(mbs)); 206 while ((len = read(fd, buf, MAXBSIZE)) != 0) { 207 if (len == -1) { 208 warn("%s: read", file); 209 (void)close(fd); 210 return (1); 211 } 212 p = buf; 213 while (len > 0) { 214 if (!domulti || MB_CUR_MAX == 1) { 215 clen = 1; 216 wch = (unsigned char)*p; 217 } else if ((clen = mbrtowc(&wch, p, len, &mbs)) == 218 (size_t)-1) { 219 if (!warned) { 220 errno = EILSEQ; 221 warn("%s", file); 222 warned = 1; 223 } 224 memset(&mbs, 0, sizeof(mbs)); 225 clen = 1; 226 wch = (unsigned char)*p; 227 } else if (clen == (size_t)-2) 228 break; 229 else if (clen == 0) 230 clen = 1; 231 charct++; 232 len -= clen; 233 p += clen; 234 if (wch == L'\n') 235 ++linect; 236 if (iswspace(wch)) 237 gotsp = 1; 238 else if (gotsp) { 239 gotsp = 0; 240 ++wordct; 241 } 242 } 243 } 244 if (domulti && MB_CUR_MAX > 1) 245 if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned) 246 warn("%s", file); 247 if (doline) { 248 tlinect += linect; 249 (void)printf(" %7ju", linect); 250 } 251 if (doword) { 252 twordct += wordct; 253 (void)printf(" %7ju", wordct); 254 } 255 if (dochar || domulti) { 256 tcharct += charct; 257 (void)printf(" %7ju", charct); 258 } 259 (void)close(fd); 260 return (0); 261 } 262 263 static void 264 usage() 265 { 266 (void)fprintf(stderr, "usage: wc [-clmw] [file ...]\n"); 267 exit(1); 268 } 269