| 1045 | |
| 1046 | template <CFormatter TFormatter> |
| 1047 | void RunFormatterFullScan( |
| 1048 | TStringBuilderBase* builder, |
| 1049 | TStringBuf format, |
| 1050 | const TFormatter& formatter, |
| 1051 | int argIndex = 0) |
| 1052 | { |
| 1053 | auto current = std::begin(format); |
| 1054 | auto end = std::end(format); |
| 1055 | while (true) { |
| 1056 | // Scan verbatim part until stop symbol. |
| 1057 | auto verbatimBegin = current; |
| 1058 | auto verbatimEnd = std::find(current, end, IntroductorySymbol); |
| 1059 | |
| 1060 | // Copy verbatim part, if any. |
| 1061 | size_t verbatimSize = verbatimEnd - verbatimBegin; |
| 1062 | if (verbatimSize > 0) { |
| 1063 | builder->AppendString(TStringBuf(verbatimBegin, verbatimSize)); |
| 1064 | } |
| 1065 | |
| 1066 | // Handle stop symbol. |
| 1067 | current = verbatimEnd; |
| 1068 | if (current == end) { |
| 1069 | break; |
| 1070 | } |
| 1071 | |
| 1072 | YT_ASSERT(*current == IntroductorySymbol); |
| 1073 | ++current; |
| 1074 | |
| 1075 | if (*current == IntroductorySymbol) { |
| 1076 | // Verbatim %. |
| 1077 | builder->AppendChar(IntroductorySymbol); |
| 1078 | ++current; |
| 1079 | continue; |
| 1080 | } |
| 1081 | |
| 1082 | // Scan format part until stop symbol. |
| 1083 | auto argFormatBegin = current; |
| 1084 | auto argFormatEnd = argFormatBegin; |
| 1085 | bool singleQuotes = false; |
| 1086 | bool doubleQuotes = false; |
| 1087 | |
| 1088 | static constexpr TStringBuf conversionSpecifiers = |
| 1089 | "diuoxXfFeEgGaAcspn"; |
| 1090 | |
| 1091 | while ( |
| 1092 | argFormatEnd != end && |
| 1093 | *argFormatEnd != GenericSpecSymbol && // value in generic format |
| 1094 | !conversionSpecifiers.Contains(*argFormatEnd)) // others are standard specifiers supported by printf |
| 1095 | { |
| 1096 | switch (*argFormatEnd) { |
| 1097 | case 'q': |
| 1098 | singleQuotes = true; |
| 1099 | break; |
| 1100 | case 'Q': |
| 1101 | doubleQuotes = true; |
| 1102 | break; |
| 1103 | case 'h': |
| 1104 | break; |
no test coverage detected