Contents of /trunk/mkinitrd-magellan/busybox/coreutils/wc.c
Parent Directory | Revision Log
Revision 984 -
(show annotations)
(download)
Sun May 30 11:32:42 2010 UTC (14 years, 4 months ago) by niro
File MIME type: text/plain
File size: 5022 byte(s)
Sun May 30 11:32:42 2010 UTC (14 years, 4 months ago) by niro
File MIME type: text/plain
File size: 5022 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * wc implementation for busybox |
4 | * |
5 | * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> |
6 | * |
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 | */ |
9 | |
10 | /* BB_AUDIT SUSv3 _NOT_ compliant -- option -m is not currently supported. */ |
11 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/wc.html */ |
12 | |
13 | /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) |
14 | * |
15 | * Rewritten to fix a number of problems and do some size optimizations. |
16 | * Problems in the previous busybox implementation (besides bloat) included: |
17 | * 1) broken 'wc -c' optimization (read note below) |
18 | * 2) broken handling of '-' args |
19 | * 3) no checking of ferror on EOF returns |
20 | * 4) isprint() wasn't considered when word counting. |
21 | * |
22 | * TODO: |
23 | * |
24 | * When locale support is enabled, count multibyte chars in the '-m' case. |
25 | * |
26 | * NOTES: |
27 | * |
28 | * The previous busybox wc attempted an optimization using stat for the |
29 | * case of counting chars only. I omitted that because it was broken. |
30 | * It didn't take into account the possibility of input coming from a |
31 | * pipe, or input from a file with file pointer not at the beginning. |
32 | * |
33 | * To implement such a speed optimization correctly, not only do you |
34 | * need the size, but also the file position. Note also that the |
35 | * file position may be past the end of file. Consider the example |
36 | * (adapted from example in gnu wc.c) |
37 | * |
38 | * echo hello > /tmp/testfile && |
39 | * (dd ibs=1k skip=1 count=0 &> /dev/null; wc -c) < /tmp/testfile |
40 | * |
41 | * for which 'wc -c' should output '0'. |
42 | */ |
43 | |
44 | #include "libbb.h" |
45 | |
46 | #if !ENABLE_LOCALE_SUPPORT |
47 | # undef isprint |
48 | # undef isspace |
49 | # define isprint(c) ((unsigned)((c) - 0x20) <= (0x7e - 0x20)) |
50 | # define isspace(c) ((c) == ' ') |
51 | #endif |
52 | |
53 | #if ENABLE_FEATURE_WC_LARGE |
54 | # define COUNT_T unsigned long long |
55 | # define COUNT_FMT "llu" |
56 | #else |
57 | # define COUNT_T unsigned |
58 | # define COUNT_FMT "u" |
59 | #endif |
60 | |
61 | enum { |
62 | WC_LINES = 0, |
63 | WC_WORDS = 1, |
64 | WC_CHARS = 2, |
65 | WC_LENGTH = 3 |
66 | }; |
67 | |
68 | int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
69 | int wc_main(int argc UNUSED_PARAM, char **argv) |
70 | { |
71 | const char *arg; |
72 | const char *start_fmt = " %9"COUNT_FMT + 1; |
73 | const char *fname_fmt = " %s\n"; |
74 | COUNT_T *pcounts; |
75 | COUNT_T counts[4]; |
76 | COUNT_T totals[4]; |
77 | int num_files; |
78 | smallint status = EXIT_SUCCESS; |
79 | unsigned print_type; |
80 | |
81 | print_type = getopt32(argv, "lwcL"); |
82 | |
83 | if (print_type == 0) { |
84 | print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS); |
85 | } |
86 | |
87 | argv += optind; |
88 | if (!argv[0]) { |
89 | *--argv = (char *) bb_msg_standard_input; |
90 | fname_fmt = "\n"; |
91 | } |
92 | if (!argv[1]) { /* zero or one filename? */ |
93 | if (!((print_type-1) & print_type)) /* exactly one option? */ |
94 | start_fmt = "%"COUNT_FMT; |
95 | } |
96 | |
97 | memset(totals, 0, sizeof(totals)); |
98 | |
99 | pcounts = counts; |
100 | |
101 | num_files = 0; |
102 | while ((arg = *argv++) != 0) { |
103 | FILE *fp; |
104 | const char *s; |
105 | unsigned u; |
106 | unsigned linepos; |
107 | smallint in_word; |
108 | |
109 | ++num_files; |
110 | fp = fopen_or_warn_stdin(arg); |
111 | if (!fp) { |
112 | status = EXIT_FAILURE; |
113 | continue; |
114 | } |
115 | |
116 | memset(counts, 0, sizeof(counts)); |
117 | linepos = 0; |
118 | in_word = 0; |
119 | |
120 | do { |
121 | int c; |
122 | /* Our -w doesn't match GNU wc exactly... oh well */ |
123 | |
124 | ++counts[WC_CHARS]; |
125 | c = getc(fp); |
126 | if (c == EOF) { |
127 | if (ferror(fp)) { |
128 | bb_simple_perror_msg(arg); |
129 | status = EXIT_FAILURE; |
130 | } |
131 | --counts[WC_CHARS]; |
132 | goto DO_EOF; /* Treat an EOF as '\r'. */ |
133 | } |
134 | if (isprint_asciionly(c)) { |
135 | ++linepos; |
136 | if (!isspace(c)) { |
137 | in_word = 1; |
138 | continue; |
139 | } |
140 | } else if ((unsigned)(c - 9) <= 4) { |
141 | /* \t 9 |
142 | * \n 10 |
143 | * \v 11 |
144 | * \f 12 |
145 | * \r 13 |
146 | */ |
147 | if (c == '\t') { |
148 | linepos = (linepos | 7) + 1; |
149 | } else { /* '\n', '\r', '\f', or '\v' */ |
150 | DO_EOF: |
151 | if (linepos > counts[WC_LENGTH]) { |
152 | counts[WC_LENGTH] = linepos; |
153 | } |
154 | if (c == '\n') { |
155 | ++counts[WC_LINES]; |
156 | } |
157 | if (c != '\v') { |
158 | linepos = 0; |
159 | } |
160 | } |
161 | } else { |
162 | continue; |
163 | } |
164 | |
165 | counts[WC_WORDS] += in_word; |
166 | in_word = 0; |
167 | if (c == EOF) { |
168 | break; |
169 | } |
170 | } while (1); |
171 | |
172 | if (totals[WC_LENGTH] < counts[WC_LENGTH]) { |
173 | totals[WC_LENGTH] = counts[WC_LENGTH]; |
174 | } |
175 | totals[WC_LENGTH] -= counts[WC_LENGTH]; |
176 | |
177 | fclose_if_not_stdin(fp); |
178 | |
179 | OUTPUT: |
180 | /* coreutils wc tries hard to print pretty columns |
181 | * (saves results for all files, find max col len etc...) |
182 | * we won't try that hard, it will bloat us too much */ |
183 | s = start_fmt; |
184 | u = 0; |
185 | do { |
186 | if (print_type & (1 << u)) { |
187 | printf(s, pcounts[u]); |
188 | s = " %9"COUNT_FMT; /* Ok... restore the leading space. */ |
189 | } |
190 | totals[u] += pcounts[u]; |
191 | } while (++u < 4); |
192 | printf(fname_fmt, arg); |
193 | } |
194 | |
195 | /* If more than one file was processed, we want the totals. To save some |
196 | * space, we set the pcounts ptr to the totals array. This has the side |
197 | * effect of trashing the totals array after outputting it, but that's |
198 | * irrelavent since we no longer need it. */ |
199 | if (num_files > 1) { |
200 | num_files = 0; /* Make sure we don't get here again. */ |
201 | arg = "total"; |
202 | pcounts = totals; |
203 | --argv; |
204 | goto OUTPUT; |
205 | } |
206 | |
207 | fflush_stdout_and_exit(status); |
208 | } |