1 | //===-- Format specifier converter implmentation for scanf -----*- 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 | #include "src/stdio/scanf_core/converter.h" |
10 | |
11 | #include "src/__support/ctype_utils.h" |
12 | #include "src/stdio/scanf_core/core_structs.h" |
13 | #include "src/stdio/scanf_core/reader.h" |
14 | |
15 | #ifndef LIBC_COPT_SCANF_DISABLE_FLOAT |
16 | #include "src/stdio/scanf_core/float_converter.h" |
17 | #endif // LIBC_COPT_SCANF_DISABLE_FLOAT |
18 | #include "src/stdio/scanf_core/current_pos_converter.h" |
19 | #include "src/stdio/scanf_core/int_converter.h" |
20 | #include "src/stdio/scanf_core/ptr_converter.h" |
21 | #include "src/stdio/scanf_core/string_converter.h" |
22 | |
23 | #include <stddef.h> |
24 | |
25 | namespace LIBC_NAMESPACE { |
26 | namespace scanf_core { |
27 | |
28 | int convert(Reader *reader, const FormatSection &to_conv) { |
29 | int ret_val = 0; |
30 | switch (to_conv.conv_name) { |
31 | case '%': |
32 | return raw_match(reader, raw_string: "%" ); |
33 | case 's': |
34 | ret_val = raw_match(reader, raw_string: " " ); |
35 | if (ret_val != READ_OK) |
36 | return ret_val; |
37 | return convert_string(reader, to_conv); |
38 | case 'c': |
39 | case '[': |
40 | return convert_string(reader, to_conv); |
41 | case 'd': |
42 | case 'i': |
43 | case 'u': |
44 | case 'o': |
45 | case 'x': |
46 | case 'X': |
47 | ret_val = raw_match(reader, raw_string: " " ); |
48 | if (ret_val != READ_OK) |
49 | return ret_val; |
50 | return convert_int(reader, to_conv); |
51 | #ifndef LIBC_COPT_SCANF_DISABLE_FLOAT |
52 | case 'f': |
53 | case 'F': |
54 | case 'e': |
55 | case 'E': |
56 | case 'a': |
57 | case 'A': |
58 | case 'g': |
59 | case 'G': |
60 | ret_val = raw_match(reader, raw_string: " " ); |
61 | if (ret_val != READ_OK) |
62 | return ret_val; |
63 | return convert_float(reader, to_conv); |
64 | #endif // LIBC_COPT_SCANF_DISABLE_FLOAT |
65 | case 'n': |
66 | return convert_current_pos(reader, to_conv); |
67 | case 'p': |
68 | ret_val = raw_match(reader, raw_string: " " ); |
69 | if (ret_val != READ_OK) |
70 | return ret_val; |
71 | return convert_pointer(reader, to_conv); |
72 | default: |
73 | return raw_match(reader, raw_string: to_conv.raw_string); |
74 | } |
75 | return -1; |
76 | } |
77 | |
78 | // raw_string is assumed to have a positive size. |
79 | int raw_match(Reader *reader, cpp::string_view raw_string) { |
80 | char cur_char = reader->getc(); |
81 | int ret_val = READ_OK; |
82 | for (size_t i = 0; i < raw_string.size(); ++i) { |
83 | // Any space character matches any number of space characters. |
84 | if (internal::isspace(ch: raw_string[i])) { |
85 | while (internal::isspace(ch: cur_char)) { |
86 | cur_char = reader->getc(); |
87 | } |
88 | } else { |
89 | if (raw_string[i] == cur_char) { |
90 | cur_char = reader->getc(); |
91 | } else { |
92 | ret_val = MATCHING_FAILURE; |
93 | break; |
94 | } |
95 | } |
96 | } |
97 | reader->ungetc(c: cur_char); |
98 | return ret_val; |
99 | } |
100 | |
101 | } // namespace scanf_core |
102 | } // namespace LIBC_NAMESPACE |
103 | |