1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39#include "libbb.h"
40#include "unicode.h"
41
42#if !ENABLE_LOCALE_SUPPORT
43# undef isprint
44# undef isspace
45# define isprint(c) ((unsigned)((c) - 0x20) <= (0x7e - 0x20))
46# define isspace(c) ((c) == ' ')
47#endif
48
49#if ENABLE_FEATURE_WC_LARGE
50# define COUNT_T unsigned long long
51# define COUNT_FMT "llu"
52#else
53# define COUNT_T unsigned
54# define COUNT_FMT "u"
55#endif
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82enum {
83 WC_LINES = 0,
84 WC_WORDS = 1,
85 WC_UNICHARS = 2,
86 WC_BYTES = 3,
87 WC_LENGTH = 4,
88 NUM_WCS = 5,
89};
90
91int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
92int wc_main(int argc UNUSED_PARAM, char **argv)
93{
94 const char *arg;
95 const char *start_fmt = " %9"COUNT_FMT + 1;
96 const char *fname_fmt = " %s\n";
97 COUNT_T *pcounts;
98 COUNT_T counts[NUM_WCS];
99 COUNT_T totals[NUM_WCS];
100 int num_files;
101 smallint status = EXIT_SUCCESS;
102 unsigned print_type;
103
104 init_unicode();
105
106 print_type = getopt32(argv, "lwmcL");
107
108 if (print_type == 0) {
109 print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_BYTES);
110 }
111
112 argv += optind;
113 if (!argv[0]) {
114 *--argv = (char *) bb_msg_standard_input;
115 fname_fmt = "\n";
116 }
117 if (!argv[1]) {
118 if (!((print_type-1) & print_type))
119 start_fmt = "%"COUNT_FMT;
120 }
121
122 memset(totals, 0, sizeof(totals));
123
124 pcounts = counts;
125
126 num_files = 0;
127 while ((arg = *argv++) != NULL) {
128 FILE *fp;
129 const char *s;
130 unsigned u;
131 unsigned linepos;
132 smallint in_word;
133
134 ++num_files;
135 fp = fopen_or_warn_stdin(arg);
136 if (!fp) {
137 status = EXIT_FAILURE;
138 continue;
139 }
140
141 memset(counts, 0, sizeof(counts));
142 linepos = 0;
143 in_word = 0;
144
145 while (1) {
146 int c;
147
148
149 c = getc(fp);
150 if (c == EOF) {
151 if (ferror(fp)) {
152 bb_simple_perror_msg(arg);
153 status = EXIT_FAILURE;
154 }
155 goto DO_EOF;
156 }
157
158
159 ++counts[WC_BYTES];
160 if (unicode_status != UNICODE_ON
161 || (c & 0xc0) != 0x80
162 ) {
163 ++counts[WC_UNICHARS];
164 }
165
166 if (isprint_asciionly(c)) {
167 ++linepos;
168 if (!isspace(c)) {
169 in_word = 1;
170 continue;
171 }
172 } else if ((unsigned)(c - 9) <= 4) {
173
174
175
176
177
178
179 if (c == '\t') {
180 linepos = (linepos | 7) + 1;
181 } else {
182 DO_EOF:
183 if (linepos > counts[WC_LENGTH]) {
184 counts[WC_LENGTH] = linepos;
185 }
186 if (c == '\n') {
187 ++counts[WC_LINES];
188 }
189 if (c != '\v') {
190 linepos = 0;
191 }
192 }
193 } else {
194 continue;
195 }
196
197 counts[WC_WORDS] += in_word;
198 in_word = 0;
199 if (c == EOF) {
200 break;
201 }
202 }
203
204 fclose_if_not_stdin(fp);
205
206 if (totals[WC_LENGTH] < counts[WC_LENGTH]) {
207 totals[WC_LENGTH] = counts[WC_LENGTH];
208 }
209 totals[WC_LENGTH] -= counts[WC_LENGTH];
210
211 OUTPUT:
212
213
214
215 s = start_fmt;
216 u = 0;
217 do {
218 if (print_type & (1 << u)) {
219 printf(s, pcounts[u]);
220 s = " %9"COUNT_FMT;
221 }
222 totals[u] += pcounts[u];
223 } while (++u < NUM_WCS);
224 printf(fname_fmt, arg);
225 }
226
227
228
229
230
231 if (num_files > 1) {
232 num_files = 0;
233 arg = "total";
234 pcounts = totals;
235 --argv;
236 goto OUTPUT;
237 }
238
239 fflush_stdout_and_exit(status);
240}
241