xref: /llvm-project/libc/src/stdio/scanf_core/converter_utils.h (revision a0c4f854cad2b97e44a1b58dc1fd982e1c4d60f3)
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/macros/config.h"
14 #include "src/__support/str_to_float.h"
15 #include "src/stdio/scanf_core/core_structs.h"
16 
17 #include <stddef.h>
18 
19 namespace LIBC_NAMESPACE_DECL {
20 namespace scanf_core {
21 
22 LIBC_INLINE void write_int_with_length(uintmax_t output_val,
23                                        const FormatSection &to_conv) {
24   if ((to_conv.flags & NO_WRITE) != 0) {
25     return;
26   }
27   void *output_ptr = to_conv.output_ptr;
28   // The %p conversion uses this function, and is always void*.
29   if (to_conv.conv_name == 'p') {
30     *reinterpret_cast<void **>(output_ptr) =
31         reinterpret_cast<void *>(output_val);
32     return;
33   }
34   LengthModifier lm = to_conv.length_modifier;
35   switch (lm) {
36   case (LengthModifier::hh):
37     *reinterpret_cast<unsigned char *>(output_ptr) =
38         static_cast<unsigned char>(output_val);
39     break;
40   case (LengthModifier::h):
41     *reinterpret_cast<unsigned short *>(output_ptr) =
42         static_cast<unsigned short>(output_val);
43     break;
44   case (LengthModifier::NONE):
45     *reinterpret_cast<unsigned int *>(output_ptr) =
46         static_cast<unsigned int>(output_val);
47     break;
48   case (LengthModifier::l):
49     *reinterpret_cast<unsigned long *>(output_ptr) =
50         static_cast<unsigned long>(output_val);
51     break;
52   case (LengthModifier::ll):
53   case (LengthModifier::L):
54     *reinterpret_cast<unsigned long long *>(output_ptr) =
55         static_cast<unsigned long long>(output_val);
56     break;
57   case (LengthModifier::j):
58     *reinterpret_cast<uintmax_t *>(output_ptr) =
59         static_cast<uintmax_t>(output_val);
60     break;
61   case (LengthModifier::z):
62     *reinterpret_cast<size_t *>(output_ptr) = static_cast<size_t>(output_val);
63     break;
64   case (LengthModifier::t):
65     *reinterpret_cast<ptrdiff_t *>(output_ptr) =
66         static_cast<ptrdiff_t>(output_val);
67     break;
68   }
69 }
70 
71 LIBC_INLINE void write_float_with_length(char *str,
72                                          const FormatSection &to_conv) {
73   if ((to_conv.flags & NO_WRITE) != 0) {
74     return;
75   }
76 
77   void *output_ptr = to_conv.output_ptr;
78 
79   LengthModifier lm = to_conv.length_modifier;
80   switch (lm) {
81   case (LengthModifier::l): {
82     auto value = internal::strtofloatingpoint<double>(str);
83     *reinterpret_cast<double *>(output_ptr) = value;
84     break;
85   }
86   case (LengthModifier::L): {
87     auto value = internal::strtofloatingpoint<long double>(str);
88     *reinterpret_cast<long double *>(output_ptr) = value;
89     break;
90   }
91   default: {
92     auto value = internal::strtofloatingpoint<float>(str);
93     *reinterpret_cast<float *>(output_ptr) = value;
94     break;
95   }
96   }
97 }
98 
99 } // namespace scanf_core
100 } // namespace LIBC_NAMESPACE_DECL
101 
102 #endif // LLVM_LIBC_SRC_STDIO_SCANF_CORE_CONVERTER_UTILS_H
103