Beispiel #1
0
/// 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;
}
Beispiel #3
0
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;
}