xref: /aosp_15_r20/external/abseil-cpp/absl/base/internal/strerror.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2020 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker 
15*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/strerror.h"
16*9356374aSAndroid Build Coastguard Worker 
17*9356374aSAndroid Build Coastguard Worker #include <array>
18*9356374aSAndroid Build Coastguard Worker #include <cerrno>
19*9356374aSAndroid Build Coastguard Worker #include <cstddef>
20*9356374aSAndroid Build Coastguard Worker #include <cstdio>
21*9356374aSAndroid Build Coastguard Worker #include <cstring>
22*9356374aSAndroid Build Coastguard Worker #include <string>
23*9356374aSAndroid Build Coastguard Worker #include <type_traits>
24*9356374aSAndroid Build Coastguard Worker 
25*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/errno_saver.h"
26*9356374aSAndroid Build Coastguard Worker 
27*9356374aSAndroid Build Coastguard Worker namespace absl {
28*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
29*9356374aSAndroid Build Coastguard Worker namespace base_internal {
30*9356374aSAndroid Build Coastguard Worker namespace {
31*9356374aSAndroid Build Coastguard Worker 
StrErrorAdaptor(int errnum,char * buf,size_t buflen)32*9356374aSAndroid Build Coastguard Worker const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
33*9356374aSAndroid Build Coastguard Worker #if defined(_WIN32)
34*9356374aSAndroid Build Coastguard Worker   int rc = strerror_s(buf, buflen, errnum);
35*9356374aSAndroid Build Coastguard Worker   buf[buflen - 1] = '\0';  // guarantee NUL termination
36*9356374aSAndroid Build Coastguard Worker   if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0';
37*9356374aSAndroid Build Coastguard Worker   return buf;
38*9356374aSAndroid Build Coastguard Worker #else
39*9356374aSAndroid Build Coastguard Worker   // The type of `ret` is platform-specific; both of these branches must compile
40*9356374aSAndroid Build Coastguard Worker   // either way but only one will execute on any given platform:
41*9356374aSAndroid Build Coastguard Worker   auto ret = strerror_r(errnum, buf, buflen);
42*9356374aSAndroid Build Coastguard Worker   if (std::is_same<decltype(ret), int>::value) {
43*9356374aSAndroid Build Coastguard Worker     // XSI `strerror_r`; `ret` is `int`:
44*9356374aSAndroid Build Coastguard Worker     if (ret) *buf = '\0';
45*9356374aSAndroid Build Coastguard Worker     return buf;
46*9356374aSAndroid Build Coastguard Worker   } else {
47*9356374aSAndroid Build Coastguard Worker     // GNU `strerror_r`; `ret` is `char *`:
48*9356374aSAndroid Build Coastguard Worker     return reinterpret_cast<const char*>(ret);
49*9356374aSAndroid Build Coastguard Worker   }
50*9356374aSAndroid Build Coastguard Worker #endif
51*9356374aSAndroid Build Coastguard Worker }
52*9356374aSAndroid Build Coastguard Worker 
StrErrorInternal(int errnum)53*9356374aSAndroid Build Coastguard Worker std::string StrErrorInternal(int errnum) {
54*9356374aSAndroid Build Coastguard Worker   char buf[100];
55*9356374aSAndroid Build Coastguard Worker   const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
56*9356374aSAndroid Build Coastguard Worker   if (*str == '\0') {
57*9356374aSAndroid Build Coastguard Worker     snprintf(buf, sizeof buf, "Unknown error %d", errnum);
58*9356374aSAndroid Build Coastguard Worker     str = buf;
59*9356374aSAndroid Build Coastguard Worker   }
60*9356374aSAndroid Build Coastguard Worker   return str;
61*9356374aSAndroid Build Coastguard Worker }
62*9356374aSAndroid Build Coastguard Worker 
63*9356374aSAndroid Build Coastguard Worker // kSysNerr is the number of errors from a recent glibc. `StrError()` falls back
64*9356374aSAndroid Build Coastguard Worker // to `StrErrorAdaptor()` if the value is larger than this.
65*9356374aSAndroid Build Coastguard Worker constexpr int kSysNerr = 135;
66*9356374aSAndroid Build Coastguard Worker 
NewStrErrorTable()67*9356374aSAndroid Build Coastguard Worker std::array<std::string, kSysNerr>* NewStrErrorTable() {
68*9356374aSAndroid Build Coastguard Worker   auto* table = new std::array<std::string, kSysNerr>;
69*9356374aSAndroid Build Coastguard Worker   for (size_t i = 0; i < table->size(); ++i) {
70*9356374aSAndroid Build Coastguard Worker     (*table)[i] = StrErrorInternal(static_cast<int>(i));
71*9356374aSAndroid Build Coastguard Worker   }
72*9356374aSAndroid Build Coastguard Worker   return table;
73*9356374aSAndroid Build Coastguard Worker }
74*9356374aSAndroid Build Coastguard Worker 
75*9356374aSAndroid Build Coastguard Worker }  // namespace
76*9356374aSAndroid Build Coastguard Worker 
StrError(int errnum)77*9356374aSAndroid Build Coastguard Worker std::string StrError(int errnum) {
78*9356374aSAndroid Build Coastguard Worker   absl::base_internal::ErrnoSaver errno_saver;
79*9356374aSAndroid Build Coastguard Worker   static const auto* table = NewStrErrorTable();
80*9356374aSAndroid Build Coastguard Worker   if (errnum >= 0 && static_cast<size_t>(errnum) < table->size()) {
81*9356374aSAndroid Build Coastguard Worker     return (*table)[static_cast<size_t>(errnum)];
82*9356374aSAndroid Build Coastguard Worker   }
83*9356374aSAndroid Build Coastguard Worker   return StrErrorInternal(errnum);
84*9356374aSAndroid Build Coastguard Worker }
85*9356374aSAndroid Build Coastguard Worker 
86*9356374aSAndroid Build Coastguard Worker }  // namespace base_internal
87*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
88*9356374aSAndroid Build Coastguard Worker }  // namespace absl
89