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