Parse a format string and set the stream state accordingly. The format mini-language recognized here is meant to be the one from C99, with the form "%[flags][width][.precision][length]type" with POSIX positional arguments extension. POSIX positional arguments extension: Conversions can be applied to the nth argument after the format in the argument list, rather than to the next unused argument.
| 662 | // necessary to pull out variable width and precision. The function returns a |
| 663 | // pointer to the character after the end of the current format spec. |
| 664 | inline const char* streamStateFromFormat(std::ostream& out, bool& positionalMode, |
| 665 | bool& spacePadPositive, |
| 666 | int& ntrunc, const char* fmtStart, |
| 667 | const detail::FormatArg* args, |
| 668 | int& argIndex, int numArgs) |
| 669 | { |
| 670 | TINYFORMAT_ASSERT(*fmtStart == '%'); |
| 671 | // Reset stream state to defaults. |
| 672 | out.width(0); |
| 673 | out.precision(6); |
| 674 | out.fill(' '); |
| 675 | // Reset most flags; ignore irrelevant unitbuf & skipws. |
| 676 | out.unsetf(std::ios::adjustfield | std::ios::basefield | |
| 677 | std::ios::floatfield | std::ios::showbase | std::ios::boolalpha | |
| 678 | std::ios::showpoint | std::ios::showpos | std::ios::uppercase); |
| 679 | bool precisionSet = false; |
| 680 | bool widthSet = false; |
| 681 | int widthExtra = 0; |
| 682 | const char* c = fmtStart + 1; |
| 683 | |
| 684 | // 1) Parse an argument index (if followed by '$') or a width possibly |
| 685 | // preceded with '0' flag. |
| 686 | if (*c >= '0' && *c <= '9') { |
| 687 | const char tmpc = *c; |
| 688 | int value = parseIntAndAdvance(c); |
| 689 | if (*c == '$') { |
| 690 | // value is an argument index |
| 691 | if (value > 0 && value <= numArgs) |
| 692 | argIndex = value - 1; |
| 693 | else |
| 694 | TINYFORMAT_ERROR("tinyformat: Positional argument out of range"); |
| 695 | ++c; |
| 696 | positionalMode = true; |
| 697 | } |
| 698 | else if (positionalMode) { |
| 699 | TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one"); |
| 700 | } |
| 701 | else { |
| 702 | if (tmpc == '0') { |
| 703 | // Use internal padding so that numeric values are |
| 704 | // formatted correctly, eg -00010 rather than 000-10 |
| 705 | out.fill('0'); |
| 706 | out.setf(std::ios::internal, std::ios::adjustfield); |
| 707 | } |
| 708 | if (value != 0) { |
| 709 | // Nonzero value means that we parsed width. |
| 710 | widthSet = true; |
| 711 | out.width(value); |
| 712 | } |
| 713 | } |
| 714 | } |
| 715 | else if (positionalMode) { |
| 716 | TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one"); |
| 717 | } |
| 718 | // 2) Parse flags and width if we did not do it in previous step. |
| 719 | if (!widthSet) { |
| 720 | // Parse flags |
| 721 | for (;; ++c) { |
no test coverage detected