Contents of /trunk/mkinitrd-magellan/busybox/coreutils/wc.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
File MIME type: text/plain
File size: 5022 byte(s)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
File MIME type: text/plain
File size: 5022 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
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 "busybox.h" |
45 | |
46 | #ifdef CONFIG_LOCALE_SUPPORT |
47 | #define isspace_given_isprint(c) isspace(c) |
48 | #else |
49 | #undef isspace |
50 | #undef isprint |
51 | #define isspace(c) ((((c) == ' ') || (((unsigned int)((c) - 9)) <= (13 - 9)))) |
52 | #define isprint(c) (((unsigned int)((c) - 0x20)) <= (0x7e - 0x20)) |
53 | #define isspace_given_isprint(c) ((c) == ' ') |
54 | #endif |
55 | |
56 | #if ENABLE_FEATURE_WC_LARGE |
57 | #define COUNT_T unsigned long long |
58 | #define COUNT_FMT "llu" |
59 | #else |
60 | #define COUNT_T unsigned |
61 | #define COUNT_FMT "u" |
62 | #endif |
63 | |
64 | enum { |
65 | WC_LINES = 0, |
66 | WC_WORDS = 1, |
67 | WC_CHARS = 2, |
68 | WC_LENGTH = 3 |
69 | }; |
70 | |
71 | int wc_main(int argc, char **argv) |
72 | { |
73 | FILE *fp; |
74 | const char *s, *arg; |
75 | const char *start_fmt = "%9"COUNT_FMT; |
76 | const char *fname_fmt = " %s\n"; |
77 | COUNT_T *pcounts; |
78 | COUNT_T counts[4]; |
79 | COUNT_T totals[4]; |
80 | unsigned linepos; |
81 | unsigned u; |
82 | int num_files = 0; |
83 | int c; |
84 | char status = EXIT_SUCCESS; |
85 | char in_word; |
86 | unsigned print_type; |
87 | |
88 | print_type = getopt32(argc, argv, "lwcL"); |
89 | |
90 | if (print_type == 0) { |
91 | print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS); |
92 | } |
93 | |
94 | argv += optind; |
95 | if (!argv[0]) { |
96 | *--argv = (char *) bb_msg_standard_input; |
97 | fname_fmt = "\n"; |
98 | if (!((print_type-1) & print_type)) /* exactly one option? */ |
99 | start_fmt = "%"COUNT_FMT; |
100 | } |
101 | |
102 | memset(totals, 0, sizeof(totals)); |
103 | |
104 | pcounts = counts; |
105 | |
106 | while ((arg = *argv++) != 0) { |
107 | ++num_files; |
108 | fp = fopen_or_warn_stdin(arg); |
109 | if (!fp) { |
110 | status = EXIT_FAILURE; |
111 | continue; |
112 | } |
113 | |
114 | memset(counts, 0, sizeof(counts)); |
115 | linepos = 0; |
116 | in_word = 0; |
117 | |
118 | do { |
119 | /* Our -w doesn't match GNU wc exactly... oh well */ |
120 | |
121 | ++counts[WC_CHARS]; |
122 | c = getc(fp); |
123 | if (isprint(c)) { |
124 | ++linepos; |
125 | if (!isspace_given_isprint(c)) { |
126 | in_word = 1; |
127 | continue; |
128 | } |
129 | } else if (((unsigned int)(c - 9)) <= 4) { |
130 | /* \t 9 |
131 | * \n 10 |
132 | * \v 11 |
133 | * \f 12 |
134 | * \r 13 |
135 | */ |
136 | if (c == '\t') { |
137 | linepos = (linepos | 7) + 1; |
138 | } else { /* '\n', '\r', '\f', or '\v' */ |
139 | DO_EOF: |
140 | if (linepos > counts[WC_LENGTH]) { |
141 | counts[WC_LENGTH] = linepos; |
142 | } |
143 | if (c == '\n') { |
144 | ++counts[WC_LINES]; |
145 | } |
146 | if (c != '\v') { |
147 | linepos = 0; |
148 | } |
149 | } |
150 | } else if (c == EOF) { |
151 | if (ferror(fp)) { |
152 | bb_perror_msg("%s", arg); |
153 | status = EXIT_FAILURE; |
154 | } |
155 | --counts[WC_CHARS]; |
156 | goto DO_EOF; /* Treat an EOF as '\r'. */ |
157 | } else { |
158 | continue; |
159 | } |
160 | |
161 | counts[WC_WORDS] += in_word; |
162 | in_word = 0; |
163 | if (c == EOF) { |
164 | break; |
165 | } |
166 | } while (1); |
167 | |
168 | if (totals[WC_LENGTH] < counts[WC_LENGTH]) { |
169 | totals[WC_LENGTH] = counts[WC_LENGTH]; |
170 | } |
171 | totals[WC_LENGTH] -= counts[WC_LENGTH]; |
172 | |
173 | fclose_if_not_stdin(fp); |
174 | |
175 | OUTPUT: |
176 | /* coreutils wc tries hard to print pretty columns |
177 | * (saves results for all files, find max col len etc...) |
178 | * we won't try that hard, it will bloat us too much */ |
179 | s = start_fmt; |
180 | u = 0; |
181 | do { |
182 | if (print_type & (1 << u)) { |
183 | printf(s, pcounts[u]); |
184 | s = " %9"COUNT_FMT; /* Ok... restore the leading space. */ |
185 | } |
186 | totals[u] += pcounts[u]; |
187 | } while (++u < 4); |
188 | printf(fname_fmt, arg); |
189 | } |
190 | |
191 | /* If more than one file was processed, we want the totals. To save some |
192 | * space, we set the pcounts ptr to the totals array. This has the side |
193 | * effect of trashing the totals array after outputting it, but that's |
194 | * irrelavent since we no longer need it. */ |
195 | if (num_files > 1) { |
196 | num_files = 0; /* Make sure we don't get here again. */ |
197 | arg = "total"; |
198 | pcounts = totals; |
199 | --argv; |
200 | goto OUTPUT; |
201 | } |
202 | |
203 | fflush_stdout_and_exit(status); |
204 | } |