//===-- Format string parser for printf -------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H #define LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H #include "core_structs.h" #include "hdr/types/struct_tm.h" #include "src/__support/CPP/string_view.h" #include "src/__support/ctype_utils.h" #include "src/__support/macros/config.h" #include "src/__support/str_to_integer.h" namespace LIBC_NAMESPACE_DECL { namespace strftime_core { class Parser { const char *str; size_t cur_pos = 0; public: LIBC_INLINE Parser(const char *new_str) : str(new_str) {} // get_next_section will parse the format string until it has a fully // specified format section. This can either be a raw format section with no // conversion, or a format section with a conversion that has all of its // variables stored in the format section. LIBC_INLINE FormatSection get_next_section() { FormatSection section; size_t starting_pos = cur_pos; if (str[cur_pos] != '%') { // raw section section.has_conv = false; while (str[cur_pos] != '%' && str[cur_pos] != '\0') ++cur_pos; section.raw_string = {str + starting_pos, cur_pos - starting_pos}; return section; } // format section section.has_conv = true; ++cur_pos; // flags section.flags = parse_flags(&cur_pos); // handle width section.min_width = 0; if (internal::isdigit(str[cur_pos])) { auto result = internal::strtointeger(str + cur_pos, 10); section.min_width = result.value; cur_pos = cur_pos + result.parsed_len; } // modifiers switch (str[cur_pos]) { case ('E'): section.modifier = ConvModifier::E; ++cur_pos; break; case ('O'): section.modifier = ConvModifier::O; ++cur_pos; break; default: section.modifier = ConvModifier::none; } section.conv_name = str[cur_pos]; // If the end of the format section is on the '\0'. This means we need to // not advance the cur_pos. if (str[cur_pos] != '\0') ++cur_pos; section.raw_string = {str + starting_pos, cur_pos - starting_pos}; return section; } private: LIBC_INLINE FormatFlags parse_flags(size_t *local_pos) { bool found_flag = true; FormatFlags flags = FormatFlags(0); while (found_flag) { switch (str[*local_pos]) { case '+': flags = static_cast(flags | FormatFlags::FORCE_SIGN); break; case '0': flags = static_cast(flags | FormatFlags::LEADING_ZEROES); break; default: found_flag = false; } if (found_flag) ++*local_pos; } return flags; } }; } // namespace strftime_core } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H