1*cf5a6c84SAndroid Build Coastguard Worker /* wc.c - Word count
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2011 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://opengroup.org/onlinepubs/9699919799/utilities/wc.html
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker USE_WC(NEWTOY(wc, "Lcmwl", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker config WC
10*cf5a6c84SAndroid Build Coastguard Worker bool "wc"
11*cf5a6c84SAndroid Build Coastguard Worker default y
12*cf5a6c84SAndroid Build Coastguard Worker help
13*cf5a6c84SAndroid Build Coastguard Worker usage: wc [-Llwcm] [FILE...]
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker Count lines, words, and characters in input.
16*cf5a6c84SAndroid Build Coastguard Worker
17*cf5a6c84SAndroid Build Coastguard Worker -L Show max line length
18*cf5a6c84SAndroid Build Coastguard Worker -l Show lines
19*cf5a6c84SAndroid Build Coastguard Worker -w Show words
20*cf5a6c84SAndroid Build Coastguard Worker -c Show bytes
21*cf5a6c84SAndroid Build Coastguard Worker -m Show characters
22*cf5a6c84SAndroid Build Coastguard Worker
23*cf5a6c84SAndroid Build Coastguard Worker By default outputs lines, words, bytes, and filename for each
24*cf5a6c84SAndroid Build Coastguard Worker argument (or from stdin if none). Displays only either bytes
25*cf5a6c84SAndroid Build Coastguard Worker or characters.
26*cf5a6c84SAndroid Build Coastguard Worker */
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker #define FOR_wc
29*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
30*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(unsigned long totals[5];)31*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
32*cf5a6c84SAndroid Build Coastguard Worker unsigned long totals[5];
33*cf5a6c84SAndroid Build Coastguard Worker )
34*cf5a6c84SAndroid Build Coastguard Worker
35*cf5a6c84SAndroid Build Coastguard Worker static void show_lengths(unsigned long *lengths, char *name)
36*cf5a6c84SAndroid Build Coastguard Worker {
37*cf5a6c84SAndroid Build Coastguard Worker int i, space = 0, first = 1;
38*cf5a6c84SAndroid Build Coastguard Worker
39*cf5a6c84SAndroid Build Coastguard Worker // POSIX says there should never be leading spaces, but accepts that
40*cf5a6c84SAndroid Build Coastguard Worker // traditional implementations use 7 spaces, unless only one file (or
41*cf5a6c84SAndroid Build Coastguard Worker // just stdin) is being counted, when there should be no leading spaces,
42*cf5a6c84SAndroid Build Coastguard Worker // *except* for the case where we're going to output multiple numbers.
43*cf5a6c84SAndroid Build Coastguard Worker // And, yes, folks have test scripts that rely on all this nonsense :-(
44*cf5a6c84SAndroid Build Coastguard Worker // Note: sufficiently modern versions of coreutils wc will use the smallest
45*cf5a6c84SAndroid Build Coastguard Worker // column width necessary to have all columns be equal width rather than 0.
46*cf5a6c84SAndroid Build Coastguard Worker if (!(!toys.optc && !(toys.optflags & (toys.optflags-1))) && toys.optc!=1)
47*cf5a6c84SAndroid Build Coastguard Worker space = 7;
48*cf5a6c84SAndroid Build Coastguard Worker
49*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<ARRAY_LEN(TT.totals); i++) {
50*cf5a6c84SAndroid Build Coastguard Worker if (toys.optflags&(1<<i)) {
51*cf5a6c84SAndroid Build Coastguard Worker printf(" %*ld"+first, space, lengths[i]);
52*cf5a6c84SAndroid Build Coastguard Worker first = 0;
53*cf5a6c84SAndroid Build Coastguard Worker }
54*cf5a6c84SAndroid Build Coastguard Worker if (i==4) TT.totals[i] = maxof(TT.totals[i], lengths[i]);
55*cf5a6c84SAndroid Build Coastguard Worker else TT.totals[i] += lengths[i];
56*cf5a6c84SAndroid Build Coastguard Worker }
57*cf5a6c84SAndroid Build Coastguard Worker if (*toys.optargs) printf(" %s", name);
58*cf5a6c84SAndroid Build Coastguard Worker xputc('\n');
59*cf5a6c84SAndroid Build Coastguard Worker }
60*cf5a6c84SAndroid Build Coastguard Worker
do_wc(int fd,char * name)61*cf5a6c84SAndroid Build Coastguard Worker static void do_wc(int fd, char *name)
62*cf5a6c84SAndroid Build Coastguard Worker {
63*cf5a6c84SAndroid Build Coastguard Worker int len = 0, clen = 1, space = 0;
64*cf5a6c84SAndroid Build Coastguard Worker unsigned long word = 0, lengths[ARRAY_LEN(TT.totals)] = {0}, line = 0;
65*cf5a6c84SAndroid Build Coastguard Worker
66*cf5a6c84SAndroid Build Coastguard Worker // fast path: wc -c normalfile is file length.
67*cf5a6c84SAndroid Build Coastguard Worker if (toys.optflags == FLAG_c) {
68*cf5a6c84SAndroid Build Coastguard Worker struct stat st;
69*cf5a6c84SAndroid Build Coastguard Worker
70*cf5a6c84SAndroid Build Coastguard Worker // On Linux, files in /proc often report their size as 0.
71*cf5a6c84SAndroid Build Coastguard Worker if (!fstat(fd, &st) && S_ISREG(st.st_mode) && st.st_size) {
72*cf5a6c84SAndroid Build Coastguard Worker lengths[3] = st.st_size;
73*cf5a6c84SAndroid Build Coastguard Worker goto show;
74*cf5a6c84SAndroid Build Coastguard Worker }
75*cf5a6c84SAndroid Build Coastguard Worker }
76*cf5a6c84SAndroid Build Coastguard Worker
77*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
78*cf5a6c84SAndroid Build Coastguard Worker int pos, done = 0, len2 = read(fd, toybuf+len, sizeof(toybuf)-len);
79*cf5a6c84SAndroid Build Coastguard Worker unsigned wchar;
80*cf5a6c84SAndroid Build Coastguard Worker
81*cf5a6c84SAndroid Build Coastguard Worker if (len2<0) perror_msg_raw(name);
82*cf5a6c84SAndroid Build Coastguard Worker else len += len2;
83*cf5a6c84SAndroid Build Coastguard Worker if (len2<1) done++;
84*cf5a6c84SAndroid Build Coastguard Worker
85*cf5a6c84SAndroid Build Coastguard Worker for (pos = 0; pos<len; pos++) {
86*cf5a6c84SAndroid Build Coastguard Worker if (toybuf[pos]=='\n') lengths[0]++;
87*cf5a6c84SAndroid Build Coastguard Worker lengths[3]++;
88*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(m)||FLAG(L)) {
89*cf5a6c84SAndroid Build Coastguard Worker // If we've consumed next wide char
90*cf5a6c84SAndroid Build Coastguard Worker if (--clen<1) {
91*cf5a6c84SAndroid Build Coastguard Worker // next wide size, don't count invalid, fetch more data if necessary
92*cf5a6c84SAndroid Build Coastguard Worker clen = utf8towc(&wchar, toybuf+pos, len-pos);
93*cf5a6c84SAndroid Build Coastguard Worker if (clen == -1) continue;
94*cf5a6c84SAndroid Build Coastguard Worker if (clen == -2 && !done) break;
95*cf5a6c84SAndroid Build Coastguard Worker
96*cf5a6c84SAndroid Build Coastguard Worker lengths[2]++;
97*cf5a6c84SAndroid Build Coastguard Worker line += maxof(wcwidth(wchar), 0);
98*cf5a6c84SAndroid Build Coastguard Worker if (wchar=='\t') line += 8-(line&7);
99*cf5a6c84SAndroid Build Coastguard Worker else if (wchar=='\n' || wchar=='\r') {
100*cf5a6c84SAndroid Build Coastguard Worker if (line>lengths[4]) lengths[4] = line;
101*cf5a6c84SAndroid Build Coastguard Worker line = 0;
102*cf5a6c84SAndroid Build Coastguard Worker }
103*cf5a6c84SAndroid Build Coastguard Worker
104*cf5a6c84SAndroid Build Coastguard Worker space = iswspace(wchar);
105*cf5a6c84SAndroid Build Coastguard Worker }
106*cf5a6c84SAndroid Build Coastguard Worker } else space = isspace(toybuf[pos]);
107*cf5a6c84SAndroid Build Coastguard Worker
108*cf5a6c84SAndroid Build Coastguard Worker if (space) word=0;
109*cf5a6c84SAndroid Build Coastguard Worker else {
110*cf5a6c84SAndroid Build Coastguard Worker if (!word) lengths[1]++;
111*cf5a6c84SAndroid Build Coastguard Worker word=1;
112*cf5a6c84SAndroid Build Coastguard Worker }
113*cf5a6c84SAndroid Build Coastguard Worker }
114*cf5a6c84SAndroid Build Coastguard Worker if (done) break;
115*cf5a6c84SAndroid Build Coastguard Worker if (pos != len) memmove(toybuf, toybuf+pos, len-pos);
116*cf5a6c84SAndroid Build Coastguard Worker len -= pos;
117*cf5a6c84SAndroid Build Coastguard Worker }
118*cf5a6c84SAndroid Build Coastguard Worker if (line>lengths[4]) lengths[4] = line;
119*cf5a6c84SAndroid Build Coastguard Worker
120*cf5a6c84SAndroid Build Coastguard Worker show:
121*cf5a6c84SAndroid Build Coastguard Worker show_lengths(lengths, name);
122*cf5a6c84SAndroid Build Coastguard Worker }
123*cf5a6c84SAndroid Build Coastguard Worker
wc_main(void)124*cf5a6c84SAndroid Build Coastguard Worker void wc_main(void)
125*cf5a6c84SAndroid Build Coastguard Worker {
126*cf5a6c84SAndroid Build Coastguard Worker if (!toys.optflags) toys.optflags = FLAG_l|FLAG_w|FLAG_c;
127*cf5a6c84SAndroid Build Coastguard Worker loopfiles(toys.optargs, do_wc);
128*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc>1) show_lengths(TT.totals, "total");
129*cf5a6c84SAndroid Build Coastguard Worker }
130