• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Format specifier converter 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 #ifndef LLVM_LIBC_SRC_STDIO_SCANF_CORE_CONVERTER_UTILS_H
10 #define LLVM_LIBC_SRC_STDIO_SCANF_CORE_CONVERTER_UTILS_H
11 
12 #include "src/__support/ctype_utils.h"
13 #include "src/__support/str_to_float.h"
14 #include "src/stdio/scanf_core/core_structs.h"
15 
16 #include <stddef.h>
17 
18 namespace LIBC_NAMESPACE {
19 namespace scanf_core {
20 
to_lower(char a)21 LIBC_INLINE constexpr char to_lower(char a) { return a | 32; }
22 
b36_char_to_int(char input)23 LIBC_INLINE constexpr int b36_char_to_int(char input) {
24   if (internal::isdigit(input))
25     return input - '0';
26   if (internal::isalpha(input))
27     return to_lower(input) + 10 - 'a';
28   return 0;
29 }
30 
write_int_with_length(uintmax_t output_val,const FormatSection & to_conv)31 LIBC_INLINE void write_int_with_length(uintmax_t output_val,
32                                        const FormatSection &to_conv) {
33   if ((to_conv.flags & NO_WRITE) != 0) {
34     return;
35   }
36   void *output_ptr = to_conv.output_ptr;
37   // The %p conversion uses this function, and is always void*.
38   if (to_conv.conv_name == 'p') {
39     *reinterpret_cast<void **>(output_ptr) =
40         reinterpret_cast<void *>(output_val);
41     return;
42   }
43   LengthModifier lm = to_conv.length_modifier;
44   switch (lm) {
45   case (LengthModifier::hh):
46     *reinterpret_cast<unsigned char *>(output_ptr) =
47         static_cast<unsigned char>(output_val);
48     break;
49   case (LengthModifier::h):
50     *reinterpret_cast<unsigned short *>(output_ptr) =
51         static_cast<unsigned short>(output_val);
52     break;
53   case (LengthModifier::NONE):
54     *reinterpret_cast<unsigned int *>(output_ptr) =
55         static_cast<unsigned int>(output_val);
56     break;
57   case (LengthModifier::l):
58     *reinterpret_cast<unsigned long *>(output_ptr) =
59         static_cast<unsigned long>(output_val);
60     break;
61   case (LengthModifier::ll):
62   case (LengthModifier::L):
63     *reinterpret_cast<unsigned long long *>(output_ptr) =
64         static_cast<unsigned long long>(output_val);
65     break;
66   case (LengthModifier::j):
67     *reinterpret_cast<uintmax_t *>(output_ptr) =
68         static_cast<uintmax_t>(output_val);
69     break;
70   case (LengthModifier::z):
71     *reinterpret_cast<size_t *>(output_ptr) = static_cast<size_t>(output_val);
72     break;
73   case (LengthModifier::t):
74     *reinterpret_cast<ptrdiff_t *>(output_ptr) =
75         static_cast<ptrdiff_t>(output_val);
76     break;
77   }
78 }
79 
write_float_with_length(char * str,const FormatSection & to_conv)80 LIBC_INLINE void write_float_with_length(char *str,
81                                          const FormatSection &to_conv) {
82   if ((to_conv.flags & NO_WRITE) != 0) {
83     return;
84   }
85 
86   void *output_ptr = to_conv.output_ptr;
87 
88   LengthModifier lm = to_conv.length_modifier;
89   switch (lm) {
90   case (LengthModifier::l): {
91     auto value = internal::strtofloatingpoint<double>(str);
92     *reinterpret_cast<double *>(output_ptr) = value;
93     break;
94   }
95   case (LengthModifier::L): {
96     auto value = internal::strtofloatingpoint<long double>(str);
97     *reinterpret_cast<long double *>(output_ptr) = value;
98     break;
99   }
100   default: {
101     auto value = internal::strtofloatingpoint<float>(str);
102     *reinterpret_cast<float *>(output_ptr) = value;
103     break;
104   }
105   }
106 }
107 
108 } // namespace scanf_core
109 } // namespace LIBC_NAMESPACE
110 
111 #endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_CONVERTER_UTILS_H
112