Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/coreutils/printf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 53  Line 53 
53   *  (but negative numbers are not "bad").   *  (but negative numbers are not "bad").
54   * Both accept negative numbers for %u specifier.   * Both accept negative numbers for %u specifier.
55   *   *
56   * We try to be compatible. We are not compatible here:   * We try to be compatible.
  * - we do not accept -NUM for %u  
  * - exit code is 0 even if "invalid number" was seen (FIXME)  
  * See "if (errno)" checks in the code below.  
57   */   */
58    
59  typedef void FAST_FUNC (*converter)(const char *arg, void *result);  typedef void FAST_FUNC (*converter)(const char *arg, void *result);
# Line 75  static int multiconvert(const char *arg, Line 72  static int multiconvert(const char *arg,
72   return 0;   return 0;
73  }  }
74    
75  static void FAST_FUNC conv_strtoul(const char *arg, void *result)  static void FAST_FUNC conv_strtoull(const char *arg, void *result)
76  {  {
77   *(unsigned long*)result = bb_strtoul(arg, NULL, 0);   *(unsigned long long*)result = bb_strtoull(arg, NULL, 0);
78     /* both coreutils 6.10 and bash 3.2:
79     * $ printf '%x\n' -2
80     * fffffffffffffffe
81     * Mimic that:
82     */
83     if (errno) {
84     *(unsigned long long*)result = bb_strtoll(arg, NULL, 0);
85     }
86  }  }
87  static void FAST_FUNC conv_strtol(const char *arg, void *result)  static void FAST_FUNC conv_strtoll(const char *arg, void *result)
88  {  {
89   *(long*)result = bb_strtol(arg, NULL, 0);   *(long long*)result = bb_strtoll(arg, NULL, 0);
90  }  }
91  static void FAST_FUNC conv_strtod(const char *arg, void *result)  static void FAST_FUNC conv_strtod(const char *arg, void *result)
92  {  {
# Line 96  static void FAST_FUNC conv_strtod(const Line 101  static void FAST_FUNC conv_strtod(const
101  }  }
102    
103  /* Callers should check errno to detect errors */  /* Callers should check errno to detect errors */
104  static unsigned long my_xstrtoul(const char *arg)  static unsigned long long my_xstrtoull(const char *arg)
105  {  {
106   unsigned long result;   unsigned long long result;
107   if (multiconvert(arg, &result, conv_strtoul))   if (multiconvert(arg, &result, conv_strtoull))
108   result = 0;   result = 0;
109   return result;   return result;
110  }  }
111  static long my_xstrtol(const char *arg)  static long long my_xstrtoll(const char *arg)
112  {  {
113   long result;   long long result;
114   if (multiconvert(arg, &result, conv_strtol))   if (multiconvert(arg, &result, conv_strtoll))
115   result = 0;   result = 0;
116   return result;   return result;
117  }  }
# Line 134  static void print_direc(char *format, un Line 139  static void print_direc(char *format, un
139   int field_width, int precision,   int field_width, int precision,
140   const char *argument)   const char *argument)
141  {  {
142   long lv;   long long llv;
143   double dv;   double dv;
144   char saved;   char saved;
145   char *have_prec, *have_width;   char *have_prec, *have_width;
# Line 147  static void print_direc(char *format, un Line 152  static void print_direc(char *format, un
152   if (have_width - 1 == have_prec)   if (have_width - 1 == have_prec)
153   have_width = NULL;   have_width = NULL;
154    
155     errno = 0;
156    
157   switch (format[fmt_length - 1]) {   switch (format[fmt_length - 1]) {
158   case 'c':   case 'c':
159   printf(format, *argument);   printf(format, *argument);
160   break;   break;
161   case 'd':   case 'd':
162   case 'i':   case 'i':
163   lv = my_xstrtol(argument);   llv = my_xstrtoll(argument);
164   print_long:   print_long:
  /* if (errno) return; - see comment at the top */  
165   if (!have_width) {   if (!have_width) {
166   if (!have_prec)   if (!have_prec)
167   printf(format, lv);   printf(format, llv);
168   else   else
169   printf(format, precision, lv);   printf(format, precision, llv);
170   } else {   } else {
171   if (!have_prec)   if (!have_prec)
172   printf(format, field_width, lv);   printf(format, field_width, llv);
173   else   else
174   printf(format, field_width, precision, lv);   printf(format, field_width, precision, llv);
175   }   }
176   break;   break;
177   case 'o':   case 'o':
178   case 'u':   case 'u':
179   case 'x':   case 'x':
180   case 'X':   case 'X':
181   lv = my_xstrtoul(argument);   llv = my_xstrtoull(argument);
182   /* cheat: unsigned long and long have same width, so... */   /* cheat: unsigned long and long have same width, so... */
183   goto print_long;   goto print_long;
184   case 's':   case 's':
185   /* Are char* and long the same? (true for most arches) */   /* Are char* and long long the same? */
186   if (sizeof(argument) == sizeof(lv)) {   if (sizeof(argument) == sizeof(llv)) {
187   lv = (long)(ptrdiff_t)argument;   llv = (long long)(ptrdiff_t)argument;
188   goto print_long;   goto print_long;
189   } else { /* Hope compiler will optimize it out */   } else {
190     /* Hope compiler will optimize it out by moving call
191     * instruction after the ifs... */
192   if (!have_width) {   if (!have_width) {
193   if (!have_prec)   if (!have_prec)
194   printf(format, argument);   printf(format, argument, /*unused:*/ argument, argument);
195   else   else
196   printf(format, precision, argument);   printf(format, precision, argument, /*unused:*/ argument);
197   } else {   } else {
198   if (!have_prec)   if (!have_prec)
199   printf(format, field_width, argument);   printf(format, field_width, argument, /*unused:*/ argument);
200   else   else
201   printf(format, field_width, precision, argument);   printf(format, field_width, precision, argument);
202   }   }
# Line 200  static void print_direc(char *format, un Line 208  static void print_direc(char *format, un
208   case 'g':   case 'g':
209   case 'G':   case 'G':
210   dv = my_xstrtod(argument);   dv = my_xstrtod(argument);
  /* if (errno) return; */  
211   if (!have_width) {   if (!have_width) {
212   if (!have_prec)   if (!have_prec)
213   printf(format, dv);   printf(format, dv);
# Line 231  static int get_width_prec(const char *st Line 238  static int get_width_prec(const char *st
238    
239  /* Print the text in FORMAT, using ARGV for arguments to any '%' directives.  /* Print the text in FORMAT, using ARGV for arguments to any '%' directives.
240     Return advanced ARGV.  */     Return advanced ARGV.  */
241  static char **print_formatted(char *f, char **argv)  static char **print_formatted(char *f, char **argv, int *conv_err)
242  {  {
243   char *direc_start;      /* Start of % directive.  */   char *direc_start;      /* Start of % directive.  */
244   unsigned direc_length;  /* Length of % directive.  */   unsigned direc_length;  /* Length of % directive.  */
# Line 286  static char **print_formatted(char *f, c Line 293  static char **print_formatted(char *f, c
293   }   }
294   }   }
295   }   }
296   /* Remove size modifiers - "%Ld" would try to printf  
297   * long long, we pass long, and it spews garbage */   /* Remove "lLhz" size modifiers, repeatedly.
298   if ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') {   * bash does not like "%lld", but coreutils
299     * happily takes even "%Llllhhzhhzd"!
300     * We are permissive like coreutils */
301     while ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') {
302   overlapping_strcpy(f, f + 1);   overlapping_strcpy(f, f + 1);
303   }   }
304  //FIXME: actually, the same happens with bare "%d":   /* Add "ll" if integer modifier, then print */
305  //it printfs an int, but we pass long!   {
306  //What saves us is that on most arches stack slot   static const char format_chars[] ALIGN1 = "diouxXfeEgGcs";
307  //is pointer-sized -> long-sized -> ints are promoted to longs   char *p = strchr(format_chars, *f);
308  // for variadic functions -> printf("%d", int_v) is in reality   /* needed - try "printf %" without it */
309  // indistinqushable from printf("%d", long_v) ->   if (p == NULL) {
310  // since printf("%d", int_v) works, printf("%d", long_v) has to work.   bb_error_msg("%s: invalid format", direc_start);
311  //But "clean" solution would be to add "l" to d,i,o,x,X.   /* causes main() to exit with error */
312  //Probably makes sense to go all the way to "ll" then.   return saved_argv - 1;
313  //Coreutils support long long-sized arguments.   }
314     ++direc_length;
315   /* needed - try "printf %" without it */   if (p - format_chars <= 5) {
316   if (!strchr("diouxXfeEgGcs", *f)) {   /* it is one of "diouxX" */
317   bb_error_msg("%s: invalid format", direc_start);   p = xmalloc(direc_length + 3);
318   /* causes main() to exit with error */   memcpy(p, direc_start, direc_length);
319   return saved_argv - 1;   p[direc_length + 1] = p[direc_length - 1];
320   }   p[direc_length - 1] = 'l';
321   ++direc_length;   p[direc_length] = 'l';
322   if (*argv) {   //bb_error_msg("<%s>", p);
323   print_direc(direc_start, direc_length, field_width,   direc_length += 2;
324   precision, *argv);   direc_start = p;
325   ++argv;   } else {
326   } else {   p = NULL;
327   print_direc(direc_start, direc_length, field_width,   }
328   precision, "");   if (*argv) {
329     print_direc(direc_start, direc_length, field_width,
330     precision, *argv++);
331     } else {
332     print_direc(direc_start, direc_length, field_width,
333     precision, "");
334     }
335     *conv_err |= errno;
336     free(p);
337   }   }
  /* if (errno) return saved_argv - 1; */  
338   break;   break;
339   case '\\':   case '\\':
340   if (*++f == 'c') {   if (*++f == 'c') {
# Line 336  static char **print_formatted(char *f, c Line 353  static char **print_formatted(char *f, c
353    
354  int printf_main(int argc UNUSED_PARAM, char **argv)  int printf_main(int argc UNUSED_PARAM, char **argv)
355  {  {
356     int conv_err;
357   char *format;   char *format;
358   char **argv2;   char **argv2;
359    
# Line 372  int printf_main(int argc UNUSED_PARAM, c Line 390  int printf_main(int argc UNUSED_PARAM, c
390   format = argv[1];   format = argv[1];
391   argv2 = argv + 2;   argv2 = argv + 2;
392    
393     conv_err = 0;
394   do {   do {
395   argv = argv2;   argv = argv2;
396   argv2 = print_formatted(format, argv);   argv2 = print_formatted(format, argv, &conv_err);
397   } while (argv2 > argv && *argv2);   } while (argv2 > argv && *argv2);
398    
399   /* coreutils compat (bash doesn't do this):   /* coreutils compat (bash doesn't do this):
# Line 382  int printf_main(int argc UNUSED_PARAM, c Line 401  int printf_main(int argc UNUSED_PARAM, c
401   fprintf(stderr, "excess args ignored");   fprintf(stderr, "excess args ignored");
402   */   */
403    
404   return (argv2 < argv); /* if true, print_formatted errored out */   return (argv2 < argv) /* if true, print_formatted errored out */
405     || conv_err; /* print_formatted saw invalid number */
406  }  }

Legend:
Removed from v.983  
changed lines
  Added in v.984