tor-browser

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

substitute.cc (5892B)


      1 // Copyright 2017 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/strings/substitute.h"
     16 
     17 #include <algorithm>
     18 #include <cassert>
     19 #include <cstddef>
     20 #include <cstdint>
     21 #include <limits>
     22 #include <string>
     23 
     24 #include "absl/base/config.h"
     25 #include "absl/base/internal/raw_logging.h"
     26 #include "absl/base/nullability.h"
     27 #include "absl/strings/ascii.h"
     28 #include "absl/strings/escaping.h"
     29 #include "absl/strings/internal/resize_uninitialized.h"
     30 #include "absl/strings/numbers.h"
     31 #include "absl/strings/str_cat.h"
     32 #include "absl/strings/string_view.h"
     33 
     34 namespace absl {
     35 ABSL_NAMESPACE_BEGIN
     36 namespace substitute_internal {
     37 
     38 void SubstituteAndAppendArray(
     39    absl::Nonnull<std::string*> output, absl::string_view format,
     40    absl::Nullable<const absl::string_view*> args_array, size_t num_args) {
     41  // Determine total size needed.
     42  size_t size = 0;
     43  for (size_t i = 0; i < format.size(); i++) {
     44    if (format[i] == '$') {
     45      if (i + 1 >= format.size()) {
     46 #ifndef NDEBUG
     47        ABSL_RAW_LOG(FATAL,
     48                     "Invalid absl::Substitute() format string: \"%s\".",
     49                     absl::CEscape(format).c_str());
     50 #endif
     51        return;
     52      } else if (absl::ascii_isdigit(
     53                     static_cast<unsigned char>(format[i + 1]))) {
     54        int index = format[i + 1] - '0';
     55        if (static_cast<size_t>(index) >= num_args) {
     56 #ifndef NDEBUG
     57          ABSL_RAW_LOG(
     58              FATAL,
     59              "Invalid absl::Substitute() format string: asked for \"$"
     60              "%d\", but only %d args were given.  Full format string was: "
     61              "\"%s\".",
     62              index, static_cast<int>(num_args), absl::CEscape(format).c_str());
     63 #endif
     64          return;
     65        }
     66        size += args_array[index].size();
     67        ++i;  // Skip next char.
     68      } else if (format[i + 1] == '$') {
     69        ++size;
     70        ++i;  // Skip next char.
     71      } else {
     72 #ifndef NDEBUG
     73        ABSL_RAW_LOG(FATAL,
     74                     "Invalid absl::Substitute() format string: \"%s\".",
     75                     absl::CEscape(format).c_str());
     76 #endif
     77        return;
     78      }
     79    } else {
     80      ++size;
     81    }
     82  }
     83 
     84  if (size == 0) return;
     85 
     86  // Build the string.
     87  size_t original_size = output->size();
     88  ABSL_INTERNAL_CHECK(
     89      size <= std::numeric_limits<size_t>::max() - original_size,
     90      "size_t overflow");
     91  strings_internal::STLStringResizeUninitializedAmortized(output,
     92                                                          original_size + size);
     93  char* target = &(*output)[original_size];
     94  for (size_t i = 0; i < format.size(); i++) {
     95    if (format[i] == '$') {
     96      if (absl::ascii_isdigit(static_cast<unsigned char>(format[i + 1]))) {
     97        const absl::string_view src = args_array[format[i + 1] - '0'];
     98        target = std::copy(src.begin(), src.end(), target);
     99        ++i;  // Skip next char.
    100      } else if (format[i + 1] == '$') {
    101        *target++ = '$';
    102        ++i;  // Skip next char.
    103      }
    104    } else {
    105      *target++ = format[i];
    106    }
    107  }
    108 
    109  assert(target == output->data() + output->size());
    110 }
    111 
    112 Arg::Arg(absl::Nullable<const void*> value) {
    113  static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
    114                "fix sizeof(scratch_)");
    115  if (value == nullptr) {
    116    piece_ = "NULL";
    117  } else {
    118    char* ptr = scratch_ + sizeof(scratch_);
    119    uintptr_t num = reinterpret_cast<uintptr_t>(value);
    120    do {
    121      *--ptr = absl::numbers_internal::kHexChar[num & 0xf];
    122      num >>= 4;
    123    } while (num != 0);
    124    *--ptr = 'x';
    125    *--ptr = '0';
    126    piece_ = absl::string_view(
    127        ptr, static_cast<size_t>(scratch_ + sizeof(scratch_) - ptr));
    128  }
    129 }
    130 
    131 // TODO(jorg): Don't duplicate so much code between here and str_cat.cc
    132 Arg::Arg(Hex hex) {
    133  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
    134  char* writer = end;
    135  uint64_t value = hex.value;
    136  do {
    137    *--writer = absl::numbers_internal::kHexChar[value & 0xF];
    138    value >>= 4;
    139  } while (value != 0);
    140 
    141  char* beg;
    142  if (end - writer < hex.width) {
    143    beg = end - hex.width;
    144    std::fill_n(beg, writer - beg, hex.fill);
    145  } else {
    146    beg = writer;
    147  }
    148 
    149  piece_ = absl::string_view(beg, static_cast<size_t>(end - beg));
    150 }
    151 
    152 // TODO(jorg): Don't duplicate so much code between here and str_cat.cc
    153 Arg::Arg(Dec dec) {
    154  assert(dec.width <= numbers_internal::kFastToBufferSize);
    155  char* const end = &scratch_[numbers_internal::kFastToBufferSize];
    156  char* const minfill = end - dec.width;
    157  char* writer = end;
    158  uint64_t value = dec.value;
    159  bool neg = dec.neg;
    160  while (value > 9) {
    161    *--writer = '0' + (value % 10);
    162    value /= 10;
    163  }
    164  *--writer = '0' + static_cast<char>(value);
    165  if (neg) *--writer = '-';
    166 
    167  ptrdiff_t fillers = writer - minfill;
    168  if (fillers > 0) {
    169    // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
    170    // But...: if the fill character is '0', then it's <+/-><fill><digits>
    171    bool add_sign_again = false;
    172    if (neg && dec.fill == '0') {  // If filling with '0',
    173      ++writer;                    // ignore the sign we just added
    174      add_sign_again = true;       // and re-add the sign later.
    175    }
    176    writer -= fillers;
    177    std::fill_n(writer, fillers, dec.fill);
    178    if (add_sign_again) *--writer = '-';
    179  }
    180 
    181  piece_ = absl::string_view(writer, static_cast<size_t>(end - writer));
    182 }
    183 
    184 }  // namespace substitute_internal
    185 ABSL_NAMESPACE_END
    186 }  // namespace absl