tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

strerror.cc (2645B)


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