| 417 | |
| 418 | template <typename Char, typename Context> |
| 419 | void vprintf(buffer<Char>& buf, basic_string_view<Char> format, |
| 420 | basic_format_args<Context> args) { |
| 421 | using iterator = buffer_appender<Char>; |
| 422 | auto out = iterator(buf); |
| 423 | auto context = basic_printf_context<Char>(out, args); |
| 424 | auto parse_ctx = basic_format_parse_context<Char>(format); |
| 425 | |
| 426 | // Returns the argument with specified index or, if arg_index is -1, the next |
| 427 | // argument. |
| 428 | auto get_arg = [&](int arg_index) { |
| 429 | if (arg_index < 0) |
| 430 | arg_index = parse_ctx.next_arg_id(); |
| 431 | else |
| 432 | parse_ctx.check_arg_id(--arg_index); |
| 433 | return detail::get_arg(context, arg_index); |
| 434 | }; |
| 435 | |
| 436 | const Char* start = parse_ctx.begin(); |
| 437 | const Char* end = parse_ctx.end(); |
| 438 | auto it = start; |
| 439 | while (it != end) { |
| 440 | if (!find<false, Char>(it, end, '%', it)) { |
| 441 | it = end; // find leaves it == nullptr if it doesn't find '%'. |
| 442 | break; |
| 443 | } |
| 444 | Char c = *it++; |
| 445 | if (it != end && *it == c) { |
| 446 | write(out, basic_string_view<Char>(start, to_unsigned(it - start))); |
| 447 | start = ++it; |
| 448 | continue; |
| 449 | } |
| 450 | write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start))); |
| 451 | |
| 452 | auto specs = format_specs<Char>(); |
| 453 | specs.align = align::right; |
| 454 | |
| 455 | // Parse argument index, flags and width. |
| 456 | int arg_index = parse_header(it, end, specs, get_arg); |
| 457 | if (arg_index == 0) throw_format_error("argument not found"); |
| 458 | |
| 459 | // Parse precision. |
| 460 | if (it != end && *it == '.') { |
| 461 | ++it; |
| 462 | c = it != end ? *it : 0; |
| 463 | if ('0' <= c && c <= '9') { |
| 464 | specs.precision = parse_nonnegative_int(it, end, 0); |
| 465 | } else if (c == '*') { |
| 466 | ++it; |
| 467 | specs.precision = static_cast<int>( |
| 468 | visit_format_arg(printf_precision_handler(), get_arg(-1))); |
| 469 | } else { |
| 470 | specs.precision = 0; |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | auto arg = get_arg(arg_index); |
| 475 | // For d, i, o, u, x, and X conversion specifiers, if a precision is |
| 476 | // specified, the '0' flag is ignored |