/Users/deen/code/yugabyte-db/src/yb/gutil/strings/substitute.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2008 Google Inc. All rights reserved. |
2 | | // |
3 | | // The following only applies to changes made to this file as part of YugaByte development. |
4 | | // |
5 | | // Portions Copyright (c) YugaByte, Inc. |
6 | | // |
7 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
8 | | // in compliance with the License. You may obtain a copy of the License at |
9 | | // |
10 | | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | | // |
12 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
13 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
14 | | // or implied. See the License for the specific language governing permissions and limitations |
15 | | // under the License. |
16 | | // |
17 | | |
18 | | #include "yb/gutil/strings/substitute.h" |
19 | | |
20 | | #include <glog/logging.h> |
21 | | |
22 | | #include "yb/gutil/macros.h" |
23 | | #include "yb/gutil/stl_util.h" |
24 | | #include "yb/gutil/strings/ascii_ctype.h" |
25 | | #include "yb/gutil/strings/escaping.h" |
26 | | |
27 | | namespace strings { |
28 | | |
29 | | using internal::SubstituteArg; |
30 | | |
31 | | const SubstituteArg SubstituteArg::NoArg; |
32 | | |
33 | | // Returns the number of args in arg_array which were passed explicitly |
34 | | // to Substitute(). |
35 | 0 | static int CountSubstituteArgs(const SubstituteArg* const* args_array) { |
36 | 0 | int count = 0; |
37 | 0 | while (args_array[count] != &SubstituteArg::NoArg) { |
38 | 0 | ++count; |
39 | 0 | } |
40 | 0 | return count; |
41 | 0 | } |
42 | | |
43 | | namespace internal { |
44 | | int SubstitutedSize(GStringPiece format, |
45 | 339M | const SubstituteArg* const* args_array) { |
46 | 339M | int size = 0; |
47 | 4.63G | for (size_t i = 0; i < format.size(); i++4.29G ) { |
48 | 4.29G | if (format[i] == '$') { |
49 | 626M | if (i+1 >= format.size()) { |
50 | 0 | LOG(DFATAL) << "Invalid strings::Substitute() format string: \"" |
51 | 0 | << CEscape(format) << "\"."; |
52 | 0 | return 0; |
53 | 626M | } else if (626M ascii_isdigit(format[i+1])626M ) { |
54 | 626M | int index = format[i+1] - '0'; |
55 | 626M | if (args_array[index]->size() == -1) { |
56 | 0 | LOG(DFATAL) |
57 | 0 | << "strings::Substitute format string invalid: asked for \"$" |
58 | 0 | << index << "\", but only " << CountSubstituteArgs(args_array) |
59 | 0 | << " args were given. Full format string was: \"" |
60 | 0 | << CEscape(format) << "\"."; |
61 | 0 | return 0; |
62 | 0 | } |
63 | 626M | size += args_array[index]->size(); |
64 | 626M | ++i; // Skip next char. |
65 | 18.4E | } else if (format[i+1] == '$') { |
66 | 291 | ++size; |
67 | 291 | ++i; // Skip next char. |
68 | 18.4E | } else { |
69 | 18.4E | LOG(DFATAL) << "Invalid strings::Substitute() format string: \"" |
70 | 18.4E | << CEscape(format) << "\"."; |
71 | 18.4E | return 0; |
72 | 18.4E | } |
73 | 3.67G | } else { |
74 | 3.67G | ++size; |
75 | 3.67G | } |
76 | 4.29G | } |
77 | 339M | return size; |
78 | 339M | } |
79 | | |
80 | | char* SubstituteToBuffer(GStringPiece format, |
81 | | const SubstituteArg* const* args_array, |
82 | 339M | char* target) { |
83 | 339M | CHECK_NOTNULL(target); |
84 | 4.63G | for (size_t i = 0; i < format.size(); i++4.29G ) { |
85 | 4.29G | if (format[i] == '$') { |
86 | 626M | if (ascii_isdigit(format[i+1])626M ) { |
87 | 626M | const SubstituteArg* src = args_array[format[i+1] - '0']; |
88 | 626M | memcpy(target, src->data(), src->size()); |
89 | 626M | target += src->size(); |
90 | 626M | ++i; // Skip next char. |
91 | 18.4E | } else if (format[i+1] == '$') { |
92 | 291 | *target++ = '$'; |
93 | 291 | ++i; // Skip next char. |
94 | 291 | } |
95 | 3.67G | } else { |
96 | 3.67G | *target++ = format[i]; |
97 | 3.67G | } |
98 | 4.29G | } |
99 | 339M | return target; |
100 | 339M | } |
101 | | |
102 | | } // namespace internal |
103 | | |
104 | | void SubstituteAndAppend( |
105 | | string* output, GStringPiece format, |
106 | | const SubstituteArg& arg0, const SubstituteArg& arg1, |
107 | | const SubstituteArg& arg2, const SubstituteArg& arg3, |
108 | | const SubstituteArg& arg4, const SubstituteArg& arg5, |
109 | | const SubstituteArg& arg6, const SubstituteArg& arg7, |
110 | 236M | const SubstituteArg& arg8, const SubstituteArg& arg9) { |
111 | 236M | const SubstituteArg* const args_array[] = { |
112 | 236M | &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, nullptr |
113 | 236M | }; |
114 | | |
115 | | // Determine total size needed. |
116 | 236M | int size = SubstitutedSize(format, args_array); |
117 | 236M | if (size == 0) return0 ; |
118 | | |
119 | | // Build the string. |
120 | 236M | auto original_size = output->size(); |
121 | 236M | STLStringResizeUninitialized(output, original_size + size); |
122 | 236M | char* target = string_as_array(output) + original_size; |
123 | | |
124 | 236M | target = SubstituteToBuffer(format, args_array, target); |
125 | 236M | DCHECK_EQ(target - output->data(), output->size()); |
126 | 236M | } |
127 | | |
128 | 5.00M | SubstituteArg::SubstituteArg(const void* value) { |
129 | 5.00M | COMPILE_ASSERT(sizeof(scratch_) >= sizeof(value) * 2 + 2, |
130 | 5.00M | fix_sizeof_scratch_); |
131 | 5.00M | if (value == nullptr) { |
132 | 0 | text_ = "NULL"; |
133 | 0 | size_ = strlen(text_); |
134 | 5.00M | } else { |
135 | 5.00M | char* ptr = scratch_ + sizeof(scratch_); |
136 | 5.00M | uintptr_t num = reinterpret_cast<uintptr_t>(value); |
137 | 5.00M | static const char kHexDigits[] = "0123456789abcdef"; |
138 | 60.0M | do { |
139 | 60.0M | *--ptr = kHexDigits[num & 0xf]; |
140 | 60.0M | num >>= 4; |
141 | 60.0M | } while (num != 0); |
142 | 5.00M | *--ptr = 'x'; |
143 | 5.00M | *--ptr = '0'; |
144 | 5.00M | text_ = ptr; |
145 | 5.00M | size_ = scratch_ + sizeof(scratch_) - ptr; |
146 | 5.00M | } |
147 | 5.00M | } |
148 | | |
149 | | } // namespace strings |