• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H
10 #define LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H
11 
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 
19 namespace LIBC_NAMESPACE_DECL {
20 namespace strftime_core {
21 
22 class Parser {
23   const char *str;
24   size_t cur_pos = 0;
25 
26 public:
Parser(const char * new_str)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 fully
30   // specified format section. This can either be a raw format section with no
31   // conversion, or a format section with a conversion that has all of its
32   // variables stored in the format section.
get_next_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 section
39       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 section
47     section.has_conv = true;
48     ++cur_pos;
49 
50     // flags
51     section.flags = parse_flags(&cur_pos);
52 
53     // handle width
54     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     // modifiers
62     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 to
78     // 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 
86 private:
parse_flags(size_t * local_pos)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_core
109 } // namespace LIBC_NAMESPACE_DECL
110 
111 #endif // LLVM_LIBC_SRC_STDIO_STRFTIME_CORE_PARSER_H
112