aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-01-04 02:58:58 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-01-04 02:58:58 +0000
commitcb39a7ca6dba94388657873651547c5ff320ad93 (patch)
treef1d01cd38f5c8830f10496cbdc3a9bd620409979
parent0416e3dde17ea9295635c52183b30fe3d7172333 (diff)
downloadbusybox-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.c118
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
78static void FAST_FUNC conv_strtoul(const char *arg, void *result) 78static 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}
82static void FAST_FUNC conv_strtol(const char *arg, void *result) 82static 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}
86static void FAST_FUNC conv_strtod(const char *arg, void *result) 86static 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 */
99static unsigned long my_xstrtoul(const char *arg) 99static 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}
106static long my_xstrtol(const char *arg) 106static 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') {