• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/ext/base/string_utils.h"
18 
19 #include <locale.h>
20 #include <stdarg.h>
21 #include <string.h>
22 
23 #include <algorithm>
24 
25 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
26 #include <xlocale.h>
27 #endif
28 
29 #include <cinttypes>
30 
31 #include "perfetto/base/compiler.h"
32 #include "perfetto/base/logging.h"
33 
34 namespace perfetto {
35 namespace base {
36 
37 // Locale-independant as possible version of strtod.
StrToD(const char * nptr,char ** endptr)38 double StrToD(const char* nptr, char** endptr) {
39 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
40     PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
41     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
42   static auto c_locale = newlocale(LC_ALL, "C", nullptr);
43   return strtod_l(nptr, endptr, c_locale);
44 #else
45   return strtod(nptr, endptr);
46 #endif
47 }
48 
StartsWith(const std::string & str,const std::string & prefix)49 bool StartsWith(const std::string& str, const std::string& prefix) {
50   return str.compare(0, prefix.length(), prefix) == 0;
51 }
52 
StartsWithAny(const std::string & str,const std::vector<std::string> & prefixes)53 bool StartsWithAny(const std::string& str,
54                    const std::vector<std::string>& prefixes) {
55   return std::any_of(
56       prefixes.begin(), prefixes.end(),
57       [&str](const std::string& prefix) { return StartsWith(str, prefix); });
58 }
59 
EndsWith(const std::string & str,const std::string & suffix)60 bool EndsWith(const std::string& str, const std::string& suffix) {
61   if (suffix.size() > str.size())
62     return false;
63   return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
64 }
65 
Contains(const std::string & haystack,const std::string & needle)66 bool Contains(const std::string& haystack, const std::string& needle) {
67   return haystack.find(needle) != std::string::npos;
68 }
69 
Contains(const std::string & haystack,const char needle)70 bool Contains(const std::string& haystack, const char needle) {
71   return haystack.find(needle) != std::string::npos;
72 }
73 
Find(const StringView & needle,const StringView & haystack)74 size_t Find(const StringView& needle, const StringView& haystack) {
75   if (needle.empty())
76     return 0;
77   if (needle.size() > haystack.size())
78     return std::string::npos;
79   for (size_t i = 0; i < haystack.size() - (needle.size() - 1); ++i) {
80     if (strncmp(haystack.data() + i, needle.data(), needle.size()) == 0)
81       return i;
82   }
83   return std::string::npos;
84 }
85 
CaseInsensitiveEqual(const std::string & first,const std::string & second)86 bool CaseInsensitiveEqual(const std::string& first, const std::string& second) {
87   return first.size() == second.size() &&
88          std::equal(
89              first.begin(), first.end(), second.begin(),
90              [](char a, char b) { return Lowercase(a) == Lowercase(b); });
91 }
92 
Join(const std::vector<std::string> & parts,const std::string & delim)93 std::string Join(const std::vector<std::string>& parts,
94                  const std::string& delim) {
95   std::string acc;
96   for (size_t i = 0; i < parts.size(); ++i) {
97     acc += parts[i];
98     if (i + 1 != parts.size()) {
99       acc += delim;
100     }
101   }
102   return acc;
103 }
104 
SplitString(const std::string & text,const std::string & delimiter)105 std::vector<std::string> SplitString(const std::string& text,
106                                      const std::string& delimiter) {
107   PERFETTO_CHECK(!delimiter.empty());
108 
109   std::vector<std::string> output;
110   size_t start = 0;
111   size_t next;
112   for (;;) {
113     next = std::min(text.find(delimiter, start), text.size());
114     if (next > start)
115       output.emplace_back(&text[start], next - start);
116     start = next + delimiter.size();
117     if (start >= text.size())
118       break;
119   }
120   return output;
121 }
122 
StripPrefix(const std::string & str,const std::string & prefix)123 std::string StripPrefix(const std::string& str, const std::string& prefix) {
124   return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
125 }
126 
StripSuffix(const std::string & str,const std::string & suffix)127 std::string StripSuffix(const std::string& str, const std::string& suffix) {
128   return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
129                                : str;
130 }
131 
ToUpper(const std::string & str)132 std::string ToUpper(const std::string& str) {
133   // Don't use toupper(), it depends on the locale.
134   std::string res(str);
135   auto end = res.end();
136   for (auto c = res.begin(); c != end; ++c)
137     *c = Uppercase(*c);
138   return res;
139 }
140 
ToLower(const std::string & str)141 std::string ToLower(const std::string& str) {
142   // Don't use tolower(), it depends on the locale.
143   std::string res(str);
144   auto end = res.end();
145   for (auto c = res.begin(); c != end; ++c)
146     *c = Lowercase(*c);
147   return res;
148 }
149 
ToHex(const char * data,size_t size)150 std::string ToHex(const char* data, size_t size) {
151   std::string hex(2 * size + 1, 'x');
152   for (size_t i = 0; i < size; ++i) {
153     // snprintf prints 3 characters, the two hex digits and a null byte. As we
154     // write left to right, we keep overwriting the nullbytes, except for the
155     // last call to snprintf.
156     snprintf(&(hex[2 * i]), 3, "%02hhx", data[i]);
157   }
158   // Remove the trailing nullbyte produced by the last snprintf.
159   hex.resize(2 * size);
160   return hex;
161 }
162 
IntToHexString(uint32_t number)163 std::string IntToHexString(uint32_t number) {
164   size_t max_size = 11;  // Max uint32 is 0xFFFFFFFF + 1 for null byte.
165   std::string buf;
166   buf.resize(max_size);
167   size_t final_len = SprintfTrunc(&buf[0], max_size, "0x%02x", number);
168   buf.resize(static_cast<size_t>(final_len));  // Cuts off the final null byte.
169   return buf;
170 }
171 
Uint64ToHexString(uint64_t number)172 std::string Uint64ToHexString(uint64_t number) {
173   return "0x" + Uint64ToHexStringNoPrefix(number);
174 }
175 
Uint64ToHexStringNoPrefix(uint64_t number)176 std::string Uint64ToHexStringNoPrefix(uint64_t number) {
177   size_t max_size = 17;  // Max uint64 is FFFFFFFFFFFFFFFF + 1 for null byte.
178   std::string buf;
179   buf.resize(max_size);
180   size_t final_len = SprintfTrunc(&buf[0], max_size, "%" PRIx64 "", number);
181   buf.resize(static_cast<size_t>(final_len));  // Cuts off the final null byte.
182   return buf;
183 }
184 
StripChars(const std::string & str,const std::string & chars,char replacement)185 std::string StripChars(const std::string& str,
186                        const std::string& chars,
187                        char replacement) {
188   std::string res(str);
189   const char* start = res.c_str();
190   const char* remove = chars.c_str();
191   for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
192     res[static_cast<uintptr_t>(c - start)] = replacement;
193   return res;
194 }
195 
ReplaceAll(std::string str,const std::string & to_replace,const std::string & replacement)196 std::string ReplaceAll(std::string str,
197                        const std::string& to_replace,
198                        const std::string& replacement) {
199   PERFETTO_CHECK(!to_replace.empty());
200   size_t pos = 0;
201   while ((pos = str.find(to_replace, pos)) != std::string::npos) {
202     str.replace(pos, to_replace.length(), replacement);
203     pos += replacement.length();
204   }
205   return str;
206 }
207 
SprintfTrunc(char * dst,size_t dst_size,const char * fmt,...)208 size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...) {
209   if (PERFETTO_UNLIKELY(dst_size) == 0)
210     return 0;
211 
212   va_list args;
213   va_start(args, fmt);
214   int src_size = vsnprintf(dst, dst_size, fmt, args);
215   va_end(args);
216 
217   if (PERFETTO_UNLIKELY(src_size) <= 0) {
218     dst[0] = '\0';
219     return 0;
220   }
221 
222   size_t res;
223   if (PERFETTO_LIKELY(src_size < static_cast<int>(dst_size))) {
224     // Most common case.
225     res = static_cast<size_t>(src_size);
226   } else {
227     // Truncation case.
228     res = dst_size - 1;
229   }
230 
231   PERFETTO_DCHECK(res < dst_size);
232   PERFETTO_DCHECK(dst[res] == '\0');
233   return res;
234 }
235 
236 }  // namespace base
237 }  // namespace perfetto
238