1 //===-- Strerror Converter for printf ---------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRERROR_CONVERTER_H
10 #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRERROR_CONVERTER_H
12 #include "src/__support/StringUtil/error_to_string.h"
13 #include "src/__support/macros/config.h"
14 #include "src/stdio/printf_core/core_structs.h"
15 #include "src/stdio/printf_core/int_converter.h"
16 #include "src/stdio/printf_core/string_converter.h"
17 #include "src/stdio/printf_core/writer.h"
19 namespace LIBC_NAMESPACE_DECL
{
20 namespace printf_core
{
22 LIBC_INLINE
int convert_strerror(Writer
*writer
, const FormatSection
&to_conv
) {
23 FormatSection new_conv
= to_conv
;
24 const int error_num
= static_cast<int>(to_conv
.conv_val_raw
);
26 // The %m conversion takes no arguments passes the result of strerror(errno)
27 // to a string conversion (including all options). If the alternate form flag
28 // is set, then if errno is a valid error number the string of the errno macro
29 // is passed to a string conversion, else the integer value of errno is passed
30 // to an integer conversion.
32 // It's assumed that errno is passed in to_conv.conv_val_raw.
35 if ((to_conv
.flags
& FormatFlags::ALTERNATE_FORM
) == 0) {
36 char strerror_buff
[64];
37 auto strerror_result
= get_error_string(error_num
, strerror_buff
);
38 new_conv
.conv_val_ptr
=
39 reinterpret_cast<void *>(const_cast<char *>(strerror_result
.data()));
40 new_conv
.conv_name
= 's';
41 return convert_string(writer
, new_conv
);
45 // The handling of errno = 0 is in alt form weird. The rule for %m in alt
46 // form is "named macros print their name, else print errno as int." There
47 // isn't a specific name for errno = 0, but it does have an explicit meaning
48 // (success). Due to the way the string mappings work, it's easiest to just
49 // say that 0 is a valid macro with a string of "0". This works fine for
50 // most cases, but for precision and the int flags it changes the behavior.
51 // Given that this behavior is so incredibly deep in the weeds I doubt
52 // anyone would notice, I'm going to leave it as the simplest to implement
53 // (0 maps to "0"), which also happens to match what other libc
54 // implementations have done.
56 auto errno_name
= try_get_errno_name(error_num
);
57 // if there's a name available, use it.
59 new_conv
.conv_val_ptr
=
60 reinterpret_cast<void *>(const_cast<char *>(errno_name
->data()));
61 new_conv
.conv_name
= 's';
62 return convert_string(writer
, new_conv
);
64 // else do an int conversion
65 new_conv
.conv_name
= 'd';
66 return convert_int(writer
, new_conv
);
71 } // namespace printf_core
72 } // namespace LIBC_NAMESPACE_DECL
74 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRERROR_CONVERTER_H