/// Print the text in FORMAT, using ARGV (with ARGC elements) for arguments to any `%' directives. /// Return the number of elements of ARGV used. int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wchar_t **argv) { int save_argc = argc; /* Preserve original value. */ const wchar_t *f; /* Pointer into `format'. */ const wchar_t *direc_start; /* Start of % directive. */ size_t direc_length; /* Length of % directive. */ bool have_field_width; /* True if FIELD_WIDTH is valid. */ int field_width = 0; /* Arg to first '*'. */ bool have_precision; /* True if PRECISION is valid. */ int precision = 0; /* Arg to second '*'. */ bool ok[UCHAR_MAX + 1] = {}; /* ok['x'] is true if %x is allowed. */ for (f = format; *f != L'\0'; ++f) { switch (*f) { case L'%': { direc_start = f++; direc_length = 1; have_field_width = have_precision = false; if (*f == L'%') { this->append_output(L'%'); break; } if (*f == L'b') { // FIXME: Field width and precision are not supported for %b, even though POSIX // requires it. if (argc > 0) { print_esc_string(*argv); ++argv; --argc; } break; } modify_allowed_format_specifiers(ok, "aAcdeEfFgGiosuxX", true); for (bool continue_looking_for_flags = true; continue_looking_for_flags;) { switch (*f) { case L'I': case L'\'': { modify_allowed_format_specifiers(ok, "aAceEosxX", false); break; } case '-': case '+': case ' ': { break; } case L'#': { modify_allowed_format_specifiers(ok, "cdisu", false); break; } case '0': { modify_allowed_format_specifiers(ok, "cs", false); break; } default: { continue_looking_for_flags = false; break; } } if (continue_looking_for_flags) { f++; direc_length++; } } if (*f == L'*') { ++f; ++direc_length; if (argc > 0) { intmax_t width = string_to_scalar_type<intmax_t>(*argv, this); if (INT_MIN <= width && width <= INT_MAX) field_width = static_cast<int>(width); else this->fatal_error(_(L"invalid field width: %ls"), *argv); ++argv; --argc; } else { field_width = 0; } have_field_width = true; } else { while (iswdigit(*f)) { ++f; ++direc_length; } } if (*f == L'.') { ++f; ++direc_length; modify_allowed_format_specifiers(ok, "c", false); if (*f == L'*') { ++f; ++direc_length; if (argc > 0) { intmax_t prec = string_to_scalar_type<intmax_t>(*argv, this); if (prec < 0) { // A negative precision is taken as if the precision were omitted, // so -1 is safe here even if prec < INT_MIN. precision = -1; } else if (INT_MAX < prec) this->fatal_error(_(L"invalid precision: %ls"), *argv); else { precision = static_cast<int>(prec); } ++argv; --argc; } else { precision = 0; } have_precision = true; } else { while (iswdigit(*f)) { ++f; ++direc_length; } } } while (*f == L'l' || *f == L'L' || *f == L'h' || *f == L'j' || *f == L't' || *f == L'z') { ++f; } wchar_t conversion = *f; if (conversion > 0xFF || !ok[conversion]) { this->fatal_error(_(L"%.*ls: invalid conversion specification"), (int)(f + 1 - direc_start), direc_start); return 0; } print_direc(direc_start, direc_length, *f, have_field_width, field_width, have_precision, precision, (argc <= 0 ? L"" : (argc--, *argv++))); break; } case L'\\': { f += print_esc(f, false); break; } default: { this->append_output(*f); break; } } } return save_argc - argc; }
int builtin_printf_state_t::print_formatted(const wchar_t *format, int argc, wchar_t **argv) { int save_argc = argc; /* Preserve original value. */ const wchar_t *f; /* Pointer into `format'. */ const wchar_t *direc_start; /* Start of % directive. */ size_t direc_length; /* Length of % directive. */ bool have_field_width; /* True if FIELD_WIDTH is valid. */ int field_width = 0; /* Arg to first '*'. */ bool have_precision; /* True if PRECISION is valid. */ int precision = 0; /* Arg to second '*'. */ bool ok[UCHAR_MAX + 1] = { }; /* ok['x'] is true if %x is allowed. */ for (f = format; *f != L'\0'; ++f) { switch (*f) { case L'%': direc_start = f++; direc_length = 1; have_field_width = have_precision = false; if (*f == L'%') { this->append_output(L'%'); break; } if (*f == L'b') { /* FIXME: Field width and precision are not supported for %b, even though POSIX requires it. */ if (argc > 0) { print_esc_string(*argv); ++argv; --argc; } break; } ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] = ok['s'] = ok['u'] = ok['x'] = ok['X'] = true; for (;; f++, direc_length++) { switch (*f) { case L'I': case L'\'': ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = ok['o'] = ok['s'] = ok['x'] = ok['X'] = false; break; case '-': case '+': case ' ': break; case L'#': ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = false; break; case '0': ok['c'] = ok['s'] = false; break; default: goto no_more_flag_characters; } } no_more_flag_characters: ; if (*f == L'*') { ++f; ++direc_length; if (argc > 0) { intmax_t width = string_to_scalar_type<intmax_t>(*argv, this); if (INT_MIN <= width && width <= INT_MAX) field_width = static_cast<int>(width); else this->fatal_error(_(L"invalid field width: %ls"), *argv); ++argv; --argc; } else { field_width = 0; } have_field_width = true; } else { while (iswdigit(*f)) { ++f; ++direc_length; } } if (*f == L'.') { ++f; ++direc_length; ok['c'] = false; if (*f == L'*') { ++f; ++direc_length; if (argc > 0) { intmax_t prec = string_to_scalar_type<intmax_t>(*argv, this); if (prec < 0) { /* A negative precision is taken as if the precision were omitted, so -1 is safe here even if prec < INT_MIN. */ precision = -1; } else if (INT_MAX < prec) this->fatal_error(_(L"invalid precision: %ls"), *argv); else { precision = static_cast<int>(prec); } ++argv; --argc; } else { precision = 0; } have_precision = true; } else { while (iswdigit(*f)) { ++f; ++direc_length; } } } while (*f == L'l' || *f == L'L' || *f == L'h' || *f == L'j' || *f == L't' || *f == L'z') ++f; { unsigned wchar_t conversion = *f; if (! ok[conversion]) { this->fatal_error(_(L"%.*ls: invalid conversion specification"), (int)(f + 1 - direc_start), direc_start); return 0; } } print_direc(direc_start, direc_length, *f, have_field_width, field_width, have_precision, precision, (argc <= 0 ? L"" : (argc--, *argv++))); break; case L'\\': f += print_esc(f, false); break; default: this->append_output(*f); } } return save_argc - argc; }
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; }