| 404 | |
| 405 | template <typename Char, typename Context> |
| 406 | void vprintf(buffer<Char>& buf, basic_string_view<Char> format, |
| 407 | basic_format_args<Context> args) { |
| 408 | using iterator = basic_appender<Char>; |
| 409 | auto out = iterator(buf); |
| 410 | auto context = basic_printf_context<Char>(out, args); |
| 411 | auto parse_ctx = parse_context<Char>(format); |
| 412 | |
| 413 | // Returns the argument with specified index or, if arg_index is -1, the next |
| 414 | // argument. |
| 415 | auto get_arg = [&](int arg_index) { |
| 416 | if (arg_index < 0) |
| 417 | arg_index = parse_ctx.next_arg_id(); |
| 418 | else |
| 419 | parse_ctx.check_arg_id(--arg_index); |
| 420 | auto arg = context.arg(arg_index); |
| 421 | if (!arg) report_error("argument not found"); |
| 422 | return arg; |
| 423 | }; |
| 424 | |
| 425 | const Char* start = parse_ctx.begin(); |
| 426 | const Char* end = parse_ctx.end(); |
| 427 | auto it = start; |
| 428 | while (it != end) { |
| 429 | if (!find<false, Char>(it, end, '%', it)) { |
| 430 | it = end; // find leaves it == nullptr if it doesn't find '%'. |
| 431 | break; |
| 432 | } |
| 433 | Char c = *it++; |
| 434 | if (it != end && *it == c) { |
| 435 | write(out, basic_string_view<Char>(start, to_unsigned(it - start))); |
| 436 | start = ++it; |
| 437 | continue; |
| 438 | } |
| 439 | write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start))); |
| 440 | |
| 441 | if (it == end) report_error("invalid format string"); |
| 442 | |
| 443 | auto specs = format_specs(); |
| 444 | specs.set_align(align::right); |
| 445 | |
| 446 | // Parse argument index, flags and width. |
| 447 | int arg_index = parse_header(it, end, specs, get_arg); |
| 448 | if (arg_index == 0) report_error("argument not found"); |
| 449 | |
| 450 | // Parse precision. |
| 451 | if (it != end && *it == '.') { |
| 452 | ++it; |
| 453 | c = it != end ? *it : 0; |
| 454 | if ('0' <= c && c <= '9') { |
| 455 | specs.precision = parse_nonnegative_int(it, end, 0); |
| 456 | } else if (c == '*') { |
| 457 | ++it; |
| 458 | // Check for positional precision argument like .*1$ |
| 459 | if (it != end && *it >= '0' && *it <= '9') { |
| 460 | int precision_index = parse_nonnegative_int(it, end, -1); |
| 461 | if (it != end && *it == '$') { |
| 462 | ++it; |
| 463 | specs.precision = static_cast<int>( |