xref: /aosp_15_r20/external/llvm-libc/src/stdio/printf_core/strerror_converter.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- Strerror Converter for printf ---------------------------*- 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_PRINTF_CORE_STRERROR_CONVERTER_H
10 #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRERROR_CONVERTER_H
11 
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"
18 
19 namespace LIBC_NAMESPACE_DECL {
20 namespace printf_core {
21 
convert_strerror(Writer * writer,const FormatSection & to_conv)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);
25 
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.
31 
32   // It's assumed that errno is passed in to_conv.conv_val_raw.
33 
34   // normal form
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);
42   } else {
43     // alt form
44 
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.
55 
56     auto errno_name = try_get_errno_name(error_num);
57     // if there's a name available, use it.
58     if (errno_name) {
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);
63     } else {
64       // else do an int conversion
65       new_conv.conv_name = 'd';
66       return convert_int(writer, new_conv);
67     }
68   }
69 }
70 
71 } // namespace printf_core
72 } // namespace LIBC_NAMESPACE_DECL
73 
74 #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_STRERROR_CONVERTER_H
75