112 lines · c
1//===-- Format string parser for printf -------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H10#define LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H11 12#include "core_structs.h"13#include "hdr/types/struct_tm.h"14#include "src/__support/CPP/string_view.h"15#include "src/__support/ctype_utils.h"16#include "src/__support/macros/config.h"17#include "src/__support/str_to_integer.h"18 19namespace LIBC_NAMESPACE_DECL {20namespace strftime_core {21 22class Parser {23 const char *str;24 size_t cur_pos = 0;25 26public:27 LIBC_INLINE Parser(const char *new_str) : str(new_str) {}28 29 // get_next_section will parse the format string until it has a fully30 // specified format section. This can either be a raw format section with no31 // conversion, or a format section with a conversion that has all of its32 // variables stored in the format section.33 LIBC_INLINE FormatSection get_next_section() {34 FormatSection section;35 size_t starting_pos = cur_pos;36 37 if (str[cur_pos] != '%') {38 // raw section39 section.has_conv = false;40 while (str[cur_pos] != '%' && str[cur_pos] != '\0')41 ++cur_pos;42 section.raw_string = {str + starting_pos, cur_pos - starting_pos};43 return section;44 }45 46 // format section47 section.has_conv = true;48 ++cur_pos;49 50 // flags51 section.flags = parse_flags(&cur_pos);52 53 // handle width54 section.min_width = 0;55 if (internal::isdigit(str[cur_pos])) {56 auto result = internal::strtointeger<int>(str + cur_pos, 10);57 section.min_width = result.value;58 cur_pos = cur_pos + result.parsed_len;59 }60 61 // modifiers62 switch (str[cur_pos]) {63 case ('E'):64 section.modifier = ConvModifier::E;65 ++cur_pos;66 break;67 case ('O'):68 section.modifier = ConvModifier::O;69 ++cur_pos;70 break;71 default:72 section.modifier = ConvModifier::none;73 }74 75 section.conv_name = str[cur_pos];76 77 // If the end of the format section is on the '\0'. This means we need to78 // not advance the cur_pos.79 if (str[cur_pos] != '\0')80 ++cur_pos;81 82 section.raw_string = {str + starting_pos, cur_pos - starting_pos};83 return section;84 }85 86private:87 LIBC_INLINE FormatFlags parse_flags(size_t *local_pos) {88 bool found_flag = true;89 FormatFlags flags = FormatFlags(0);90 while (found_flag) {91 switch (str[*local_pos]) {92 case '+':93 flags = static_cast<FormatFlags>(flags | FormatFlags::FORCE_SIGN);94 break;95 case '0':96 flags = static_cast<FormatFlags>(flags | FormatFlags::LEADING_ZEROES);97 break;98 default:99 found_flag = false;100 }101 if (found_flag)102 ++*local_pos;103 }104 return flags;105 }106};107 108} // namespace strftime_core109} // namespace LIBC_NAMESPACE_DECL110 111#endif // LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H112