OSDN Git Service

Merge remote-tracking branch 'toybox/master' into HEAD
[android-x86/external-toybox.git] / toys / posix / wc.c
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
7 USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
8
9 config 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
30 GLOBALS(
31   unsigned long totals[4];
32 )
33
34 static 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
50 static 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
102 show:
103   show_lengths(lengths, name);
104 }
105
106 void 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 }