diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-01-04 02:58:58 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-01-04 02:58:58 +0000 |
commit | cb39a7ca6dba94388657873651547c5ff320ad93 (patch) | |
tree | f1d01cd38f5c8830f10496cbdc3a9bd620409979 | |
parent | 0416e3dde17ea9295635c52183b30fe3d7172333 (diff) | |
download | busybox-w32-cb39a7ca6dba94388657873651547c5ff320ad93.tar.gz busybox-w32-cb39a7ca6dba94388657873651547c5ff320ad93.tar.bz2 busybox-w32-cb39a7ca6dba94388657873651547c5ff320ad93.zip |
printf: make integer format strings print long long-sized values.
function old new delta
printf_main 668 834 +166
bb_strtoll - 84 +84
print_direc 391 431 +40
conv_strtoull - 19 +19
conv_strtoll - 19 +19
conv_strtoul 16 - -16
conv_strtol 16 - -16
------------------------------------------------------------------------------
(add/remove: 4/2 grow/shrink: 2/0 up/down: 342/-32) Total: 296 bytes
-rw-r--r-- | coreutils/printf.c | 118 |
1 files changed, 65 insertions, 53 deletions
diff --git a/coreutils/printf.c b/coreutils/printf.c index b0a48cda4..d4f1de99b 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c | |||
@@ -75,13 +75,13 @@ static int multiconvert(const char *arg, void *result, converter convert) | |||
75 | return 0; | 75 | return 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | static void FAST_FUNC conv_strtoul(const char *arg, void *result) | 78 | static void FAST_FUNC conv_strtoull(const char *arg, void *result) |
79 | { | 79 | { |
80 | *(unsigned long*)result = bb_strtoul(arg, NULL, 0); | 80 | *(unsigned long long*)result = bb_strtoull(arg, NULL, 0); |
81 | } | 81 | } |
82 | static void FAST_FUNC conv_strtol(const char *arg, void *result) | 82 | static void FAST_FUNC conv_strtoll(const char *arg, void *result) |
83 | { | 83 | { |
84 | *(long*)result = bb_strtol(arg, NULL, 0); | 84 | *(long long*)result = bb_strtoll(arg, NULL, 0); |
85 | } | 85 | } |
86 | static void FAST_FUNC conv_strtod(const char *arg, void *result) | 86 | static void FAST_FUNC conv_strtod(const char *arg, void *result) |
87 | { | 87 | { |
@@ -96,17 +96,17 @@ static void FAST_FUNC conv_strtod(const char *arg, void *result) | |||
96 | } | 96 | } |
97 | 97 | ||
98 | /* Callers should check errno to detect errors */ | 98 | /* Callers should check errno to detect errors */ |
99 | static unsigned long my_xstrtoul(const char *arg) | 99 | static unsigned long long my_xstrtoull(const char *arg) |
100 | { | 100 | { |
101 | unsigned long result; | 101 | unsigned long long result; |
102 | if (multiconvert(arg, &result, conv_strtoul)) | 102 | if (multiconvert(arg, &result, conv_strtoull)) |
103 | result = 0; | 103 | result = 0; |
104 | return result; | 104 | return result; |
105 | } | 105 | } |
106 | static long my_xstrtol(const char *arg) | 106 | static long long my_xstrtoll(const char *arg) |
107 | { | 107 | { |
108 | long result; | 108 | long long result; |
109 | if (multiconvert(arg, &result, conv_strtol)) | 109 | if (multiconvert(arg, &result, conv_strtoll)) |
110 | result = 0; | 110 | result = 0; |
111 | return result; | 111 | return result; |
112 | } | 112 | } |
@@ -134,7 +134,7 @@ static void print_direc(char *format, unsigned fmt_length, | |||
134 | int field_width, int precision, | 134 | int field_width, int precision, |
135 | const char *argument) | 135 | const char *argument) |
136 | { | 136 | { |
137 | long lv; | 137 | long long llv; |
138 | double dv; | 138 | double dv; |
139 | char saved; | 139 | char saved; |
140 | char *have_prec, *have_width; | 140 | char *have_prec, *have_width; |
@@ -153,42 +153,44 @@ static void print_direc(char *format, unsigned fmt_length, | |||
153 | break; | 153 | break; |
154 | case 'd': | 154 | case 'd': |
155 | case 'i': | 155 | case 'i': |
156 | lv = my_xstrtol(argument); | 156 | llv = my_xstrtoll(argument); |
157 | print_long: | 157 | print_long: |
158 | /* if (errno) return; - see comment at the top */ | 158 | /* if (errno) return; - see comment at the top */ |
159 | if (!have_width) { | 159 | if (!have_width) { |
160 | if (!have_prec) | 160 | if (!have_prec) |
161 | printf(format, lv); | 161 | printf(format, llv); |
162 | else | 162 | else |
163 | printf(format, precision, lv); | 163 | printf(format, precision, llv); |
164 | } else { | 164 | } else { |
165 | if (!have_prec) | 165 | if (!have_prec) |
166 | printf(format, field_width, lv); | 166 | printf(format, field_width, llv); |
167 | else | 167 | else |
168 | printf(format, field_width, precision, lv); | 168 | printf(format, field_width, precision, llv); |
169 | } | 169 | } |
170 | break; | 170 | break; |
171 | case 'o': | 171 | case 'o': |
172 | case 'u': | 172 | case 'u': |
173 | case 'x': | 173 | case 'x': |
174 | case 'X': | 174 | case 'X': |
175 | lv = my_xstrtoul(argument); | 175 | llv = my_xstrtoull(argument); |
176 | /* cheat: unsigned long and long have same width, so... */ | 176 | /* cheat: unsigned long and long have same width, so... */ |
177 | goto print_long; | 177 | goto print_long; |
178 | case 's': | 178 | case 's': |
179 | /* Are char* and long the same? (true for most arches) */ | 179 | /* Are char* and long long the same? */ |
180 | if (sizeof(argument) == sizeof(lv)) { | 180 | if (sizeof(argument) == sizeof(llv)) { |
181 | lv = (long)(ptrdiff_t)argument; | 181 | llv = (long long)(ptrdiff_t)argument; |
182 | goto print_long; | 182 | goto print_long; |
183 | } else { /* Hope compiler will optimize it out */ | 183 | } else { |
184 | /* Hope compiler will optimize it out by moving call | ||
185 | * instruction after the ifs... */ | ||
184 | if (!have_width) { | 186 | if (!have_width) { |
185 | if (!have_prec) | 187 | if (!have_prec) |
186 | printf(format, argument); | 188 | printf(format, argument, /*unused:*/ argument, argument); |
187 | else | 189 | else |
188 | printf(format, precision, argument); | 190 | printf(format, precision, argument, /*unused:*/ argument); |
189 | } else { | 191 | } else { |
190 | if (!have_prec) | 192 | if (!have_prec) |
191 | printf(format, field_width, argument); | 193 | printf(format, field_width, argument, /*unused:*/ argument); |
192 | else | 194 | else |
193 | printf(format, field_width, precision, argument); | 195 | printf(format, field_width, precision, argument); |
194 | } | 196 | } |
@@ -286,38 +288,48 @@ static char **print_formatted(char *f, char **argv) | |||
286 | } | 288 | } |
287 | } | 289 | } |
288 | } | 290 | } |
289 | /* Remove size modifiers - "%Ld" would try to printf | 291 | |
290 | * long long, we pass long, and it spews garbage */ | 292 | /* Remove "lLhz" size modifiers, repeatedly. |
291 | if ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') { | 293 | * bash does not like "%lld", but coreutils |
294 | * would happily take even "%Llllhhzhhzd"! | ||
295 | * We will be permissive like coreutils */ | ||
296 | while ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') { | ||
292 | overlapping_strcpy(f, f + 1); | 297 | overlapping_strcpy(f, f + 1); |
293 | } | 298 | } |
294 | //FIXME: actually, the same happens with bare "%d": | 299 | /* Add "ll" if integer modifier, then print */ |
295 | //it printfs an int, but we pass long! | 300 | { |
296 | //What saves us is that on most arches stack slot | 301 | static const char format_chars[] ALIGN1 = "diouxXfeEgGcs"; |
297 | //is pointer-sized -> long-sized -> ints are promoted to longs | 302 | char *p = strchr(format_chars, *f); |
298 | // for variadic functions -> printf("%d", int_v) is in reality | 303 | /* needed - try "printf %" without it */ |
299 | // indistinqushable from printf("%d", long_v) -> | 304 | if (p == NULL) { |
300 | // since printf("%d", int_v) works, printf("%d", long_v) has to work. | 305 | bb_error_msg("%s: invalid format", direc_start); |
301 | //But "clean" solution would be to add "l" to d,i,o,x,X. | 306 | /* causes main() to exit with error */ |
302 | //Probably makes sense to go all the way to "ll" then. | 307 | return saved_argv - 1; |
303 | //Coreutils support long long-sized arguments. | 308 | } |
304 | 309 | ++direc_length; | |
305 | /* needed - try "printf %" without it */ | 310 | if (p - format_chars <= 5) { |
306 | if (!strchr("diouxXfeEgGcs", *f)) { | 311 | /* it is one of "diouxX" */ |
307 | bb_error_msg("%s: invalid format", direc_start); | 312 | p = xmalloc(direc_length + 3); |
308 | /* causes main() to exit with error */ | 313 | memcpy(p, direc_start, direc_length); |
309 | return saved_argv - 1; | 314 | p[direc_length + 1] = p[direc_length - 1]; |
310 | } | 315 | p[direc_length - 1] = 'l'; |
311 | ++direc_length; | 316 | p[direc_length] = 'l'; |
312 | if (*argv) { | 317 | //bb_error_msg("<%s>", p); |
313 | print_direc(direc_start, direc_length, field_width, | 318 | direc_length += 2; |
314 | precision, *argv); | 319 | direc_start = p; |
315 | ++argv; | 320 | } else { |
316 | } else { | 321 | p = NULL; |
317 | print_direc(direc_start, direc_length, field_width, | 322 | } |
318 | precision, ""); | 323 | if (*argv) { |
324 | print_direc(direc_start, direc_length, field_width, | ||
325 | precision, *argv); | ||
326 | ++argv; | ||
327 | } else { | ||
328 | print_direc(direc_start, direc_length, field_width, | ||
329 | precision, ""); | ||
330 | } | ||
331 | free(p); | ||
319 | } | 332 | } |
320 | /* if (errno) return saved_argv - 1; */ | ||
321 | break; | 333 | break; |
322 | case '\\': | 334 | case '\\': |
323 | if (*++f == 'c') { | 335 | if (*++f == 'c') { |