parser.cc (4073B)
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/strings/internal/str_format/parser.h" 16 17 #include <assert.h> 18 #include <string.h> 19 #include <wchar.h> 20 #include <cctype> 21 #include <cstdint> 22 23 #include <algorithm> 24 #include <initializer_list> 25 #include <limits> 26 #include <ostream> 27 #include <string> 28 #include <unordered_set> 29 30 namespace absl { 31 ABSL_NAMESPACE_BEGIN 32 namespace str_format_internal { 33 34 // Define the array for non-constexpr uses. 35 constexpr ConvTag ConvTagHolder::value[256]; 36 37 ABSL_ATTRIBUTE_NOINLINE const char* ConsumeUnboundConversionNoInline( 38 const char* p, const char* end, UnboundConversion* conv, int* next_arg) { 39 return ConsumeUnboundConversion(p, end, conv, next_arg); 40 } 41 42 std::string LengthModToString(LengthMod v) { 43 switch (v) { 44 case LengthMod::h: 45 return "h"; 46 case LengthMod::hh: 47 return "hh"; 48 case LengthMod::l: 49 return "l"; 50 case LengthMod::ll: 51 return "ll"; 52 case LengthMod::L: 53 return "L"; 54 case LengthMod::j: 55 return "j"; 56 case LengthMod::z: 57 return "z"; 58 case LengthMod::t: 59 return "t"; 60 case LengthMod::q: 61 return "q"; 62 case LengthMod::none: 63 return ""; 64 } 65 return ""; 66 } 67 68 struct ParsedFormatBase::ParsedFormatConsumer { 69 explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat) 70 : parsed(parsedformat), data_pos(parsedformat->data_.get()) {} 71 72 bool Append(string_view s) { 73 if (s.empty()) return true; 74 75 size_t text_end = AppendText(s); 76 77 if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) { 78 // Let's extend the existing text run. 79 parsed->items_.back().text_end = text_end; 80 } else { 81 // Let's make a new text run. 82 parsed->items_.push_back({false, text_end, {}}); 83 } 84 return true; 85 } 86 87 bool ConvertOne(const UnboundConversion &conv, string_view s) { 88 size_t text_end = AppendText(s); 89 parsed->items_.push_back({true, text_end, conv}); 90 return true; 91 } 92 93 size_t AppendText(string_view s) { 94 memcpy(data_pos, s.data(), s.size()); 95 data_pos += s.size(); 96 return static_cast<size_t>(data_pos - parsed->data_.get()); 97 } 98 99 ParsedFormatBase *parsed; 100 char* data_pos; 101 }; 102 103 ParsedFormatBase::ParsedFormatBase( 104 string_view format, bool allow_ignored, 105 std::initializer_list<FormatConversionCharSet> convs) 106 : data_(format.empty() ? nullptr : new char[format.size()]) { 107 has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) || 108 !MatchesConversions(allow_ignored, convs); 109 } 110 111 bool ParsedFormatBase::MatchesConversions( 112 bool allow_ignored, 113 std::initializer_list<FormatConversionCharSet> convs) const { 114 std::unordered_set<int> used; 115 auto add_if_valid_conv = [&](int pos, char c) { 116 if (static_cast<size_t>(pos) > convs.size() || 117 !Contains(convs.begin()[pos - 1], c)) 118 return false; 119 used.insert(pos); 120 return true; 121 }; 122 for (const ConversionItem &item : items_) { 123 if (!item.is_conversion) continue; 124 auto &conv = item.conv; 125 if (conv.precision.is_from_arg() && 126 !add_if_valid_conv(conv.precision.get_from_arg(), '*')) 127 return false; 128 if (conv.width.is_from_arg() && 129 !add_if_valid_conv(conv.width.get_from_arg(), '*')) 130 return false; 131 if (!add_if_valid_conv(conv.arg_position, 132 FormatConversionCharToChar(conv.conv))) 133 return false; 134 } 135 return used.size() == convs.size() || allow_ignored; 136 } 137 138 } // namespace str_format_internal 139 ABSL_NAMESPACE_END 140 } // namespace absl