| /* wc.c - Word count |
| * |
| * Copyright 2011 Rob Landley <rob@landley.net> |
| * |
| * See http://opengroup.org/onlinepubs/9699919799/utilities/wc.html |
| |
| USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE)) |
| |
| config WC |
| bool "wc" |
| default y |
| help |
| usage: wc -lwcm [FILE...] |
| |
| Count lines, words, and characters in input. |
| |
| -l show lines |
| -w show words |
| -c show bytes |
| -m show characters |
| |
| By default outputs lines, words, bytes, and filename for each |
| argument (or from stdin if none). Displays only either bytes |
| or characters. |
| */ |
| |
| #define FOR_wc |
| #include "toys.h" |
| |
| GLOBALS( |
| unsigned long totals[4]; |
| ) |
| |
| static void show_lengths(unsigned long *lengths, char *name) |
| { |
| int i, space = 7, first = 1; |
| |
| for (i = 0; i<4; i++) if (toys.optflags == (1<<i)) space = 0; |
| for (i = 0; i<4; i++) { |
| if (toys.optflags&(1<<i)) { |
| printf(" %*ld"+first, space, lengths[i]); |
| first = 0; |
| } |
| TT.totals[i] += lengths[i]; |
| } |
| if (*toys.optargs) printf(" %s", name); |
| xputc('\n'); |
| } |
| |
| static void do_wc(int fd, char *name) |
| { |
| int len = 0, clen = 1, space = 0; |
| unsigned long word = 0, lengths[] = {0,0,0,0}; |
| |
| // Speed up common case: wc -c normalfile is file length. |
| if (toys.optflags == FLAG_c) { |
| struct stat st; |
| |
| // On Linux, files in /proc often report their size as 0. |
| if (!fstat(fd, &st) && S_ISREG(st.st_mode) && st.st_size) { |
| lengths[2] = st.st_size; |
| goto show; |
| } |
| } |
| |
| for (;;) { |
| int pos, done = 0, len2 = read(fd, toybuf+len, sizeof(toybuf)-len); |
| |
| if (len2<0) perror_msg_raw(name); |
| else len += len2; |
| if (len2<1) done++; |
| |
| for (pos = 0; pos<len; pos++) { |
| if (toybuf[pos]=='\n') lengths[0]++; |
| lengths[2]++; |
| if (toys.optflags&FLAG_m) { |
| // If we've consumed next wide char |
| if (--clen<1) { |
| wchar_t wchar; |
| |
| // next wide size, don't count invalid, fetch more data if necessary |
| clen = mbrtowc(&wchar, toybuf+pos, len-pos, 0); |
| if (clen == -1) continue; |
| if (clen == -2 && !done) break; |
| |
| lengths[3]++; |
| space = iswspace(wchar); |
| } |
| } else space = isspace(toybuf[pos]); |
| |
| if (space) word=0; |
| else { |
| if (!word) lengths[1]++; |
| word=1; |
| } |
| } |
| if (done) break; |
| if (pos != len) memmove(toybuf, toybuf+pos, len-pos); |
| len -= pos; |
| } |
| |
| show: |
| show_lengths(lengths, name); |
| } |
| |
| void wc_main(void) |
| { |
| if (!toys.optflags) toys.optflags = FLAG_l|FLAG_w|FLAG_c; |
| loopfiles(toys.optargs, do_wc); |
| if (toys.optc>1) show_lengths(TT.totals, "total"); |
| } |