static void print_direc(char *start, size_t length, int field_width, int precision, const char *argument) { char *p; /* Null-terminated copy of % directive. */ p = xmalloc((unsigned) (length + 1)); strncpy(p, start, length); p[length] = 0; switch (p[length - 1]) { case 'd': case 'i': if (field_width < 0) { if (precision < 0) printf(p, my_xstrtol(argument)); else printf(p, precision, my_xstrtol(argument)); } else { if (precision < 0) printf(p, field_width, my_xstrtol(argument)); else printf(p, field_width, precision, my_xstrtol(argument)); } break; case 'o': case 'u': case 'x': case 'X': if (field_width < 0) { if (precision < 0) printf(p, my_xstrtoul(argument)); else printf(p, precision, my_xstrtoul(argument)); } else { if (precision < 0) printf(p, field_width, my_xstrtoul(argument)); else printf(p, field_width, precision, my_xstrtoul(argument)); } break; case 'f': case 'e': case 'E': case 'g': case 'G': if (field_width < 0) { if (precision < 0) printf(p, my_xstrtod(argument)); else printf(p, precision, my_xstrtod(argument)); } else { if (precision < 0) printf(p, field_width, my_xstrtod(argument)); else printf(p, field_width, precision, my_xstrtod(argument)); } break; case 'c': printf(p, *argument); break; case 's': if (field_width < 0) { if (precision < 0) printf(p, argument); else printf(p, precision, argument); } else { if (precision < 0) printf(p, field_width, argument); else printf(p, field_width, precision, argument); } break; } free(p); }
static int print_formatted(char *format, int argc, char **argv) { int save_argc = argc; /* Preserve original value. */ char *f; /* Pointer into 'format'. */ char *direc_start; /* Start of % directive. */ size_t direc_length; /* Length of % directive. */ int field_width; /* Arg to first '*', or -1 if none. */ int precision; /* Arg to second '*', or -1 if none. */ for (f = format; *f; ++f) { switch (*f) { case '%': direc_start = f++; direc_length = 1; field_width = precision = -1; if (*f == '%') { bb_putchar('%'); break; } if (*f == 'b') { if (argc > 0) { print_esc_string(*argv); ++argv; --argc; } break; } if (strchr("-+ #", *f)) { ++f; ++direc_length; } if (*f == '*') { ++f; ++direc_length; if (argc > 0) { field_width = my_xstrtoul(*argv); ++argv; --argc; } else field_width = 0; } else { while (isdigit(*f)) { ++f; ++direc_length; } } if (*f == '.') { ++f; ++direc_length; if (*f == '*') { ++f; ++direc_length; if (argc > 0) { precision = my_xstrtoul(*argv); ++argv; --argc; } else precision = 0; } else while (isdigit(*f)) { ++f; ++direc_length; } } if (*f == 'l' || *f == 'L' || *f == 'h') { ++f; ++direc_length; } /* if (!strchr ("diouxXfeEgGcs", *f)) fprintf(stderr, "%%%c: invalid directive", *f); */ ++direc_length; if (argc > 0) { print_direc(direc_start, direc_length, field_width, precision, *argv); ++argv; --argc; } else print_direc(direc_start, direc_length, field_width, precision, ""); break; case '\\': if (*++f == 'c') exit(0); bb_putchar(bb_process_escape_sequence((const char **)&f)); f--; break; default: bb_putchar(*f); } } return save_argc - argc; }
static void print_direc(char *format, unsigned fmt_length, int field_width, int precision, const char *argument) { long lv; double dv; char saved; char *have_prec, *have_width; have_prec = strstr(format, ".*"); have_width = strchr(format, '*'); if (have_width - 1 == have_prec) have_width = NULL; saved = format[fmt_length]; format[fmt_length] = '\0'; switch (format[fmt_length - 1]) { case 'c': printf(format, *argument); break; case 'd': case 'i': lv = my_xstrtol(argument); print_long: /* if (errno) return; - see comment at the top */ if (!have_width) { if (!have_prec) printf(format, lv); else printf(format, precision, lv); } else { if (!have_prec) printf(format, field_width, lv); else printf(format, field_width, precision, lv); } break; case 'o': case 'u': case 'x': case 'X': lv = my_xstrtoul(argument); /* cheat: unsigned long and long have same width, so... */ goto print_long; case 's': /* Are char* and long the same? (true for most arches) */ if (sizeof(argument) == sizeof(lv)) { lv = (long)(ptrdiff_t)argument; goto print_long; } else { /* Hope compiler will optimize it out */ if (!have_width) { if (!have_prec) printf(format, argument); else printf(format, precision, argument); } else { if (!have_prec) printf(format, field_width, argument); else printf(format, field_width, precision, argument); } break; } case 'f': case 'e': case 'E': case 'g': case 'G': dv = my_xstrtod(argument); /* if (errno) return; */ if (!have_width) { if (!have_prec) printf(format, dv); else printf(format, precision, dv); } else { if (!have_prec) printf(format, field_width, dv); else printf(format, field_width, precision, dv); } break; } /* switch */ format[fmt_length] = saved; }