| 291 | } |
| 292 | |
| 293 | bool is_printf_format(const std::string& format) |
| 294 | { |
| 295 | // Compile the regex objects |
| 296 | static std::regex printf_escape_regex_obj{ std::string(printf_escape_regex) }; |
| 297 | static std::regex printf_specifier_regex_obj{ std::string(printf_specifier_regex) }; |
| 298 | |
| 299 | size_t pos = 0; |
| 300 | size_t escapes_found = 0; |
| 301 | size_t specifiers_found = 0; |
| 302 | while (pos < format.size()) |
| 303 | { |
| 304 | if (format[pos] != '%') |
| 305 | { |
| 306 | // Consume plain text until '%' or end |
| 307 | while (pos < format.size() && format[pos] != '%') |
| 308 | { |
| 309 | pos++; |
| 310 | } |
| 311 | } |
| 312 | else |
| 313 | { |
| 314 | std::smatch match; |
| 315 | // Handle '%' by checking for escape sequence |
| 316 | if (std::regex_search(format.begin() + pos, format.end(), match, printf_escape_regex_obj, |
| 317 | std::regex_constants::match_continuous)) |
| 318 | { |
| 319 | ++escapes_found; |
| 320 | pos += match.length(); // e.g., "%%" advances by 2 |
| 321 | } |
| 322 | // Handle any variable specifier |
| 323 | else if (std::regex_search(format.begin() + pos, format.end(), match, |
| 324 | printf_specifier_regex_obj, std::regex_constants::match_continuous)) |
| 325 | { |
| 326 | ++specifiers_found; |
| 327 | { |
| 328 | // check for duplicate flags |
| 329 | std::array<ClassType, 6> classes = { SIGNED_DECIMAL_INTEGER, OCTAL_HEX_INTEGER, |
| 330 | FLOATING_POINT_DECIMAL, FLOATING_POINT_DECIMAL_EXPONENT, FLOATING_POINT_HEX_EXPONENT, |
| 331 | FLOATING_POINT_GENERAL_EXPONENT }; |
| 332 | for (const auto& classType : classes) |
| 333 | { |
| 334 | if (!match[classType].str().empty()) |
| 335 | { // group 1: flags |
| 336 | if (has_duplicates_flags(match[classType + FLAGS].str())) |
| 337 | { |
| 338 | return false; // Duplicate flags |
| 339 | } |
| 340 | break; |
| 341 | } |
| 342 | } |
| 343 | } |
| 344 | { |
| 345 | // check if both plus and space/minus flags are present |
| 346 | std::array<ClassType, 5> classes = { SIGNED_DECIMAL_INTEGER, FLOATING_POINT_DECIMAL, |
| 347 | FLOATING_POINT_DECIMAL_EXPONENT, FLOATING_POINT_HEX_EXPONENT, |
| 348 | FLOATING_POINT_GENERAL_EXPONENT }; |
| 349 | for (const auto& classType : classes) |
| 350 | { |