| //===-- 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<int>(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<FormatFlags>(flags | FormatFlags::FORCE_SIGN); | |
| break; | |
| case '0': | |
| flags = static_cast<FormatFlags>(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 |