xref: /aosp_15_r20/external/libchrome-gestures/src/string_util.cc (revision aed3e5085e770be5b69ce25295ecf6ddf906af95)
1*aed3e508SAndroid Build Coastguard Worker // Copyright 2014 The ChromiumOS Authors
2*aed3e508SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*aed3e508SAndroid Build Coastguard Worker // found in the LICENSE file.
4*aed3e508SAndroid Build Coastguard Worker 
5*aed3e508SAndroid Build Coastguard Worker #include "include/string_util.h"
6*aed3e508SAndroid Build Coastguard Worker 
7*aed3e508SAndroid Build Coastguard Worker #include <errno.h>
8*aed3e508SAndroid Build Coastguard Worker #include <stdarg.h>
9*aed3e508SAndroid Build Coastguard Worker #include <stdio.h>
10*aed3e508SAndroid Build Coastguard Worker #include <strings.h>
11*aed3e508SAndroid Build Coastguard Worker 
12*aed3e508SAndroid Build Coastguard Worker #include "include/macros.h"
13*aed3e508SAndroid Build Coastguard Worker 
14*aed3e508SAndroid Build Coastguard Worker namespace gestures {
15*aed3e508SAndroid Build Coastguard Worker 
16*aed3e508SAndroid Build Coastguard Worker namespace {
17*aed3e508SAndroid Build Coastguard Worker 
18*aed3e508SAndroid Build Coastguard Worker const char kWhitespaceASCII[] = {
19*aed3e508SAndroid Build Coastguard Worker   0x09,    // CHARACTER TABULATION
20*aed3e508SAndroid Build Coastguard Worker   0x0A,    // LINE FEED (LF)
21*aed3e508SAndroid Build Coastguard Worker   0x0B,    // LINE TABULATION
22*aed3e508SAndroid Build Coastguard Worker   0x0C,    // FORM FEED (FF)
23*aed3e508SAndroid Build Coastguard Worker   0x0D,    // CARRIAGE RETURN (CR)
24*aed3e508SAndroid Build Coastguard Worker   0x20,    // SPACE
25*aed3e508SAndroid Build Coastguard Worker   0
26*aed3e508SAndroid Build Coastguard Worker };
27*aed3e508SAndroid Build Coastguard Worker 
28*aed3e508SAndroid Build Coastguard Worker // Backend for StringPrintF/StringAppendF. This does not finalize
29*aed3e508SAndroid Build Coastguard Worker // the va_list, the caller is expected to do that.
30*aed3e508SAndroid Build Coastguard Worker PRINTF_FORMAT(2, 0)
StringAppendVT(std::string * dst,const char * format,va_list ap)31*aed3e508SAndroid Build Coastguard Worker static void StringAppendVT(std::string* dst,
32*aed3e508SAndroid Build Coastguard Worker                            const char* format,
33*aed3e508SAndroid Build Coastguard Worker                            va_list ap) {
34*aed3e508SAndroid Build Coastguard Worker   // First try with a small fixed size buffer.
35*aed3e508SAndroid Build Coastguard Worker   // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
36*aed3e508SAndroid Build Coastguard Worker   // and StringUtilTest.StringPrintfBounds.
37*aed3e508SAndroid Build Coastguard Worker   char stack_buf[1024];
38*aed3e508SAndroid Build Coastguard Worker 
39*aed3e508SAndroid Build Coastguard Worker   va_list ap_copy;
40*aed3e508SAndroid Build Coastguard Worker   va_copy(ap_copy, ap);
41*aed3e508SAndroid Build Coastguard Worker 
42*aed3e508SAndroid Build Coastguard Worker   errno = 0;
43*aed3e508SAndroid Build Coastguard Worker   int result = vsnprintf(stack_buf, arraysize(stack_buf), format, ap_copy);
44*aed3e508SAndroid Build Coastguard Worker   va_end(ap_copy);
45*aed3e508SAndroid Build Coastguard Worker 
46*aed3e508SAndroid Build Coastguard Worker   if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
47*aed3e508SAndroid Build Coastguard Worker     // It fit.
48*aed3e508SAndroid Build Coastguard Worker     dst->append(stack_buf, result);
49*aed3e508SAndroid Build Coastguard Worker     return;
50*aed3e508SAndroid Build Coastguard Worker   }
51*aed3e508SAndroid Build Coastguard Worker 
52*aed3e508SAndroid Build Coastguard Worker   // Repeatedly increase buffer size until it fits.
53*aed3e508SAndroid Build Coastguard Worker   int mem_length = arraysize(stack_buf);
54*aed3e508SAndroid Build Coastguard Worker   while (true) {
55*aed3e508SAndroid Build Coastguard Worker     if (result < 0) {
56*aed3e508SAndroid Build Coastguard Worker       if (errno != 0 && errno != EOVERFLOW)
57*aed3e508SAndroid Build Coastguard Worker         return;
58*aed3e508SAndroid Build Coastguard Worker       // Try doubling the buffer size.
59*aed3e508SAndroid Build Coastguard Worker       mem_length *= 2;
60*aed3e508SAndroid Build Coastguard Worker     } else {
61*aed3e508SAndroid Build Coastguard Worker       // We need exactly "result + 1" characters.
62*aed3e508SAndroid Build Coastguard Worker       mem_length = result + 1;
63*aed3e508SAndroid Build Coastguard Worker     }
64*aed3e508SAndroid Build Coastguard Worker 
65*aed3e508SAndroid Build Coastguard Worker     if (mem_length > 32 * 1024 * 1024) {
66*aed3e508SAndroid Build Coastguard Worker       // That should be plenty, don't try anything larger.  This protects
67*aed3e508SAndroid Build Coastguard Worker       // against huge allocations when using vsnprintfT implementations that
68*aed3e508SAndroid Build Coastguard Worker       // return -1 for reasons other than overflow without setting errno.
69*aed3e508SAndroid Build Coastguard Worker       return;
70*aed3e508SAndroid Build Coastguard Worker     }
71*aed3e508SAndroid Build Coastguard Worker 
72*aed3e508SAndroid Build Coastguard Worker     std::vector<char> mem_buf(mem_length);
73*aed3e508SAndroid Build Coastguard Worker 
74*aed3e508SAndroid Build Coastguard Worker     // NOTE: You can only use a va_list once.  Since we're in a while loop, we
75*aed3e508SAndroid Build Coastguard Worker     // need to make a new copy each time so we don't use up the original.
76*aed3e508SAndroid Build Coastguard Worker     va_copy(ap_copy, ap);
77*aed3e508SAndroid Build Coastguard Worker     result = vsnprintf(&mem_buf[0], mem_length, format, ap_copy);
78*aed3e508SAndroid Build Coastguard Worker     va_end(ap_copy);
79*aed3e508SAndroid Build Coastguard Worker 
80*aed3e508SAndroid Build Coastguard Worker     if ((result >= 0) && (result < mem_length)) {
81*aed3e508SAndroid Build Coastguard Worker       // It fit.
82*aed3e508SAndroid Build Coastguard Worker       dst->append(&mem_buf[0], result);
83*aed3e508SAndroid Build Coastguard Worker       return;
84*aed3e508SAndroid Build Coastguard Worker     }
85*aed3e508SAndroid Build Coastguard Worker   }
86*aed3e508SAndroid Build Coastguard Worker }
87*aed3e508SAndroid Build Coastguard Worker 
88*aed3e508SAndroid Build Coastguard Worker template<typename STR>
TrimStringT(const STR & input,const typename STR::value_type trim_chars[])89*aed3e508SAndroid Build Coastguard Worker STR TrimStringT(const STR& input, const typename STR::value_type trim_chars[]) {
90*aed3e508SAndroid Build Coastguard Worker   if (input.empty()) {
91*aed3e508SAndroid Build Coastguard Worker     return "";
92*aed3e508SAndroid Build Coastguard Worker   }
93*aed3e508SAndroid Build Coastguard Worker 
94*aed3e508SAndroid Build Coastguard Worker   // Find the edges of leading/trailing whitespace.
95*aed3e508SAndroid Build Coastguard Worker   const typename STR::size_type first_good_char =
96*aed3e508SAndroid Build Coastguard Worker       input.find_first_not_of(trim_chars);
97*aed3e508SAndroid Build Coastguard Worker   const typename STR::size_type last_good_char =
98*aed3e508SAndroid Build Coastguard Worker       input.find_last_not_of(trim_chars);
99*aed3e508SAndroid Build Coastguard Worker 
100*aed3e508SAndroid Build Coastguard Worker   if (first_good_char == STR::npos || last_good_char == STR::npos) {
101*aed3e508SAndroid Build Coastguard Worker     return "";
102*aed3e508SAndroid Build Coastguard Worker   }
103*aed3e508SAndroid Build Coastguard Worker 
104*aed3e508SAndroid Build Coastguard Worker   // Trim the whitespace.
105*aed3e508SAndroid Build Coastguard Worker   return input.substr(first_good_char, last_good_char - first_good_char + 1);
106*aed3e508SAndroid Build Coastguard Worker }
107*aed3e508SAndroid Build Coastguard Worker 
108*aed3e508SAndroid Build Coastguard Worker }  // namespace
109*aed3e508SAndroid Build Coastguard Worker 
StringAppendV(std::string * dst,const char * format,va_list ap)110*aed3e508SAndroid Build Coastguard Worker void StringAppendV(std::string* dst, const char* format, va_list ap) {
111*aed3e508SAndroid Build Coastguard Worker   StringAppendVT(dst, format, ap);
112*aed3e508SAndroid Build Coastguard Worker }
113*aed3e508SAndroid Build Coastguard Worker 
StringPrintf(const char * format,...)114*aed3e508SAndroid Build Coastguard Worker std::string StringPrintf(const char* format, ...) {
115*aed3e508SAndroid Build Coastguard Worker   va_list ap;
116*aed3e508SAndroid Build Coastguard Worker   va_start(ap, format);
117*aed3e508SAndroid Build Coastguard Worker   std::string result;
118*aed3e508SAndroid Build Coastguard Worker   StringAppendV(&result, format, ap);
119*aed3e508SAndroid Build Coastguard Worker   va_end(ap);
120*aed3e508SAndroid Build Coastguard Worker   return result;
121*aed3e508SAndroid Build Coastguard Worker }
122*aed3e508SAndroid Build Coastguard Worker 
TrimWhitespaceASCII(const std::string & input)123*aed3e508SAndroid Build Coastguard Worker std::string TrimWhitespaceASCII(const std::string& input) {
124*aed3e508SAndroid Build Coastguard Worker   return TrimStringT(input, kWhitespaceASCII);
125*aed3e508SAndroid Build Coastguard Worker }
126*aed3e508SAndroid Build Coastguard Worker 
127*aed3e508SAndroid Build Coastguard Worker }  // namespace gestures
128