1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
//===-- 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_PRINTF_CORE_PARSER_H
#define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/arg_list.h"
#include "src/__support/common.h"
#include "src/stdio/printf_core/core_structs.h"
#include "src/stdio/printf_core/printf_config.h"
#include <stddef.h>
namespace __llvm_libc {
namespace printf_core {
#ifndef LIBC_COPT_MOCK_ARG_LIST
using ArgProvider = internal::ArgList;
#else // not defined LIBC_COPT_MOCK_ARG_LIST
using ArgProvider = internal::MockArgList;
#endif // LIBC_COPT_MOCK_ARG_LIST
class Parser {
const char *__restrict str;
size_t cur_pos = 0;
ArgProvider args_cur;
#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
// args_start stores the start of the va_args, which is allows getting the
// value of arguments that have already been passed. args_index is tracked so
// that we know which argument args_cur is on.
ArgProvider args_start;
size_t args_index = 1;
// Defined in printf_config.h
static constexpr size_t DESC_ARR_LEN = LIBC_COPT_PRINTF_INDEX_ARR_LEN;
// desc_arr stores the sizes of the variables in the ArgProvider. This is used
// in index mode to reduce repeated string parsing. The sizes are stored as
// TypeDesc objects, which store the size as well as minimal type information.
// This is necessary because some systems separate the floating point and
// integer values in va_args.
TypeDesc desc_arr[DESC_ARR_LEN] = {type_desc_from_type<void>()};
// TODO: Look into object stores for optimization.
#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
public:
#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args)
: str(new_str), args_cur(args), args_start(args) {}
#else
LIBC_INLINE Parser(const char *__restrict new_str, ArgProvider &args)
: str(new_str), args_cur(args) {}
#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
// 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.
FormatSection get_next_section();
private:
// parse_flags parses the flags inside a format string. It assumes that
// str[*local_pos] is inside a format specifier, and parses any flags it
// finds. It returns a FormatFlags object containing the set of found flags
// arithmetically or'd together. local_pos will be moved past any flags found.
FormatFlags parse_flags(size_t *local_pos);
// parse_length_modifier parses the length modifier inside a format string. It
// assumes that str[*local_pos] is inside a format specifier. It returns a
// LengthModifier with the length modifier it found. It will advance local_pos
// after the format specifier if one is found.
LengthModifier parse_length_modifier(size_t *local_pos);
// get_next_arg_value gets the next value from the arg list as type T.
template <class T> LIBC_INLINE T get_next_arg_value() {
return args_cur.next_var<T>();
}
//----------------------------------------------------
// INDEX MODE ONLY FUNCTIONS AFTER HERE:
//----------------------------------------------------
#ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
// parse_index parses the index of a value inside a format string. It
// assumes that str[*local_pos] points to character after a '%' or '*', and
// returns 0 if there is no closing $, or if it finds no number. If it finds a
// number, it will move local_pos past the end of the $, else it will not move
// local_pos.
size_t parse_index(size_t *local_pos);
LIBC_INLINE void set_type_desc(size_t index, TypeDesc value) {
if (index != 0 && index <= DESC_ARR_LEN)
desc_arr[index - 1] = value;
}
// get_arg_value gets the value from the arg list at index (starting at 1).
// This may require parsing the format string. An index of 0 is interpreted as
// the next value. If the format string is not valid, it may have gaps in its
// indexes. Requesting the value for any index after a gap will fail, since
// the arg list must be read in order and with the correct types.
template <class T> LIBC_INLINE cpp::optional<T> get_arg_value(size_t index) {
if (!(index == 0 || index == args_index)) {
bool success = args_to_index(index);
if (!success) {
// If we can't get to this index, then the value of the arg can't be
// found.
return cpp::optional<T>();
}
}
set_type_desc(index, type_desc_from_type<T>());
++args_index;
return get_next_arg_value<T>();
}
// the ArgProvider can only return the next item in the list. This function is
// used in index mode when the item that needs to be read is not the next one.
// It moves cur_args to the index requested so the the appropriate value may
// be read. This may involve parsing the format string, and is in the worst
// case an O(n^2) operation.
bool args_to_index(size_t index);
// get_type_desc assumes that this format string uses index mode. It iterates
// through the format string until it finds a format specifier that defines
// the type of index, and returns a TypeDesc describing that type. It does not
// modify cur_pos.
TypeDesc get_type_desc(size_t index);
#endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE
};
} // namespace printf_core
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PARSER_H
|