1/* wc.c - Word count 2 * 3 * Copyright 2011 Rob Landley <rob@landley.net> 4 * 5 * See http://opengroup.org/onlinepubs/9699919799/utilities/wc.html 6 7USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) 8 9config WC 10 bool "wc" 11 default y 12 help 13 usage: wc -lwcm [FILE...] 14 15 Count lines, words, and characters in input. 16 17 -l show lines 18 -w show words 19 -c show bytes 20 -m show characters 21 22 By default outputs lines, words, bytes, and filename for each 23 argument (or from stdin if none). Displays only either bytes 24 or characters. 25*/ 26 27#define FOR_wc 28#include "toys.h" 29 30GLOBALS( 31 unsigned long totals[4]; 32) 33 34static void show_lengths(unsigned long *lengths, char *name) 35{ 36 int i, space = 7, first = 1; 37 38 for (i = 0; i<4; i++) if (toys.optflags == (1<<i)) space = 0; 39 for (i = 0; i<4; i++) { 40 if (toys.optflags&(1<<i)) { 41 printf(" %*ld"+first, space, lengths[i]); 42 first = 0; 43 } 44 TT.totals[i] += lengths[i]; 45 } 46 if (*toys.optargs) printf(" %s", name); 47 xputc('\n'); 48} 49 50static void do_wc(int fd, char *name) 51{ 52 int len = 0, clen = 1, space = 0; 53 unsigned long word = 0, lengths[] = {0,0,0,0}; 54 55 // Speed up common case: wc -c normalfile is file length. 56 if (toys.optflags == FLAG_c) { 57 struct stat st; 58 59 // On Linux, files in /proc often report their size as 0. 60 if (!fstat(fd, &st) && S_ISREG(st.st_mode) && st.st_size) { 61 lengths[2] = st.st_size; 62 goto show; 63 } 64 } 65 66 for (;;) { 67 int pos, done = 0, len2 = read(fd, toybuf+len, sizeof(toybuf)-len); 68 69 if (len2<0) perror_msg_raw(name); 70 else len += len2; 71 if (len2<1) done++; 72 73 for (pos = 0; pos<len; pos++) { 74 if (toybuf[pos]=='\n') lengths[0]++; 75 lengths[2]++; 76 if (toys.optflags&FLAG_m) { 77 // If we've consumed next wide char 78 if (--clen<1) { 79 wchar_t wchar; 80 81 // next wide size, don't count invalid, fetch more data if necessary 82 clen = mbrtowc(&wchar, toybuf+pos, len-pos, 0); 83 if (clen == -1) continue; 84 if (clen == -2 && !done) break; 85 86 lengths[3]++; 87 space = iswspace(wchar); 88 } 89 } else space = isspace(toybuf[pos]); 90 91 if (space) word=0; 92 else { 93 if (!word) lengths[1]++; 94 word=1; 95 } 96 } 97 if (done) break; 98 if (pos != len) memmove(toybuf, toybuf+pos, len-pos); 99 len -= pos; 100 } 101 102show: 103 show_lengths(lengths, name); 104} 105 106void wc_main(void) 107{ 108 if (!toys.optflags) toys.optflags = FLAG_l|FLAG_w|FLAG_c; 109 loopfiles(toys.optargs, do_wc); 110 if (toys.optc>1) show_lengths(TT.totals, "total"); 111} 112