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