| 1 |
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
|---|
| 2 |
// Use of this source code is governed by a BSD-style license that can be |
|---|
| 3 |
// found in the LICENSE file. |
|---|
| 4 |
// |
|---|
| 5 |
// This file defines utility functions for working with strings. |
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
////////////////////////////////////////////////////////////////////// |
|---|
| 9 |
|
|---|
| 10 |
// WhisperSoft note: Picked from chromium/src/base/string_util.cc |
|---|
| 11 |
|
|---|
| 12 |
////////////////////////////////////////////////////////////////////// |
|---|
| 13 |
|
|---|
| 14 |
#include <stdio.h> |
|---|
| 15 |
|
|---|
| 16 |
#include "common/base/third-party/string_util.h" |
|---|
| 17 |
#include "common/base/errno.h" |
|---|
| 18 |
#include "common/base/log.h" |
|---|
| 19 |
|
|---|
| 20 |
namespace strutil { |
|---|
| 21 |
|
|---|
| 22 |
// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter |
|---|
| 23 |
// is the size of the buffer. These return the number of characters in the |
|---|
| 24 |
// formatted string excluding the NUL terminator. If the buffer is not |
|---|
| 25 |
// large enough to accommodate the formatted string without truncation, they |
|---|
| 26 |
// return the number of characters that would be in the fully-formatted string |
|---|
| 27 |
// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms). |
|---|
| 28 |
inline int vsnprintfT(char* buffer, |
|---|
| 29 |
size_t buf_size, |
|---|
| 30 |
const char* format, |
|---|
| 31 |
va_list argptr) { |
|---|
| 32 |
return ::vsnprintf(buffer, buf_size, format, argptr); |
|---|
| 33 |
} |
|---|
| 34 |
|
|---|
| 35 |
|
|---|
| 36 |
// Templatized backend for StringPrintF/StringAppendF. This does not finalize |
|---|
| 37 |
// the va_list, the caller is expected to do that. |
|---|
| 38 |
template <class char_type> |
|---|
| 39 |
static void StringAppendVT( |
|---|
| 40 |
std::basic_string<char_type, std::char_traits<char_type> >* dst, |
|---|
| 41 |
const char_type* format, |
|---|
| 42 |
va_list ap) { |
|---|
| 43 |
|
|---|
| 44 |
// First try with a small fixed size buffer. |
|---|
| 45 |
// This buffer size should be kept in sync with StringUtilTest.GrowBoundary |
|---|
| 46 |
// and StringUtilTest.StringPrintfBounds. |
|---|
| 47 |
char_type stack_buf[1024]; |
|---|
| 48 |
|
|---|
| 49 |
va_list backup_ap; |
|---|
| 50 |
::va_copy(backup_ap, ap); |
|---|
| 51 |
|
|---|
| 52 |
#if !defined(OS_WIN) |
|---|
| 53 |
errno = 0; |
|---|
| 54 |
#endif |
|---|
| 55 |
int result = vsnprintfT(stack_buf, NUMBEROF(stack_buf), format, backup_ap); |
|---|
| 56 |
va_end(backup_ap); |
|---|
| 57 |
|
|---|
| 58 |
if (result >= 0 && result < static_cast<int>(NUMBEROF(stack_buf))) { |
|---|
| 59 |
// It fit. |
|---|
| 60 |
dst->append(stack_buf, result); |
|---|
| 61 |
return; |
|---|
| 62 |
} |
|---|
| 63 |
|
|---|
| 64 |
// Repeatedly increase buffer size until it fits. |
|---|
| 65 |
int mem_length = NUMBEROF(stack_buf); |
|---|
| 66 |
while (true) { |
|---|
| 67 |
if (result < 0) { |
|---|
| 68 |
#if !defined(OS_WIN) |
|---|
| 69 |
// On Windows, vsnprintfT always returns the number of characters in a |
|---|
| 70 |
// fully-formatted string, so if we reach this point, something else is |
|---|
| 71 |
// wrong and no amount of buffer-doubling is going to fix it. |
|---|
| 72 |
if (errno != 0 && errno != EOVERFLOW) |
|---|
| 73 |
#endif |
|---|
| 74 |
{ |
|---|
| 75 |
// If an error other than overflow occurred, it's never going to work. |
|---|
| 76 |
DLOG_WARNING << "Unable to printf the requested string due to error."; |
|---|
| 77 |
return; |
|---|
| 78 |
} |
|---|
| 79 |
// Try doubling the buffer size. |
|---|
| 80 |
mem_length *= 2; |
|---|
| 81 |
} else { |
|---|
| 82 |
// We need exactly "result + 1" characters. |
|---|
| 83 |
mem_length = result + 1; |
|---|
| 84 |
} |
|---|
| 85 |
|
|---|
| 86 |
if (mem_length > 32 * 1024 * 1024) { |
|---|
| 87 |
// That should be plenty, don't try anything larger. This protects |
|---|
| 88 |
// against huge allocations when using vsnprintfT implementations that |
|---|
| 89 |
// return -1 for reasons other than overflow without setting errno. |
|---|
| 90 |
DLOG_WARNING << "Unable to printf the requested string due to size: " |
|---|
| 91 |
<< mem_length; |
|---|
| 92 |
return; |
|---|
| 93 |
} |
|---|
| 94 |
|
|---|
| 95 |
std::vector<char_type> mem_buf(mem_length); |
|---|
| 96 |
|
|---|
| 97 |
// Restore the va_list before we use it again. |
|---|
| 98 |
::va_copy(backup_ap, ap); |
|---|
| 99 |
|
|---|
| 100 |
result = vsnprintfT(&mem_buf[0], mem_length, format, ap); |
|---|
| 101 |
va_end(backup_ap); |
|---|
| 102 |
|
|---|
| 103 |
if ((result >= 0) && (result < mem_length)) { |
|---|
| 104 |
// It fit. |
|---|
| 105 |
dst->append(&mem_buf[0], result); |
|---|
| 106 |
return; |
|---|
| 107 |
} |
|---|
| 108 |
} |
|---|
| 109 |
} |
|---|
| 110 |
|
|---|
| 111 |
namespace { |
|---|
| 112 |
|
|---|
| 113 |
template <typename STR, typename INT, typename UINT, bool NEG> |
|---|
| 114 |
struct IntToStringT { |
|---|
| 115 |
|
|---|
| 116 |
// This is to avoid a compiler warning about unary minus on unsigned type. |
|---|
| 117 |
// For example, say you had the following code: |
|---|
| 118 |
// template <typename INT> |
|---|
| 119 |
// INT abs(INT value) { return value < 0 ? -value : value; } |
|---|
| 120 |
// Even though if INT is unsigned, it's impossible for value < 0, so the |
|---|
| 121 |
// unary minus will never be taken, the compiler will still generate a |
|---|
| 122 |
// warning. We do a little specialization dance... |
|---|
| 123 |
template <typename INT2, typename UINT2, bool NEG2> |
|---|
| 124 |
struct ToUnsignedT { }; |
|---|
| 125 |
|
|---|
| 126 |
template <typename INT2, typename UINT2> |
|---|
| 127 |
struct ToUnsignedT<INT2, UINT2, false> { |
|---|
| 128 |
static UINT2 ToUnsigned(INT2 value) { |
|---|
| 129 |
return static_cast<UINT2>(value); |
|---|
| 130 |
} |
|---|
| 131 |
}; |
|---|
| 132 |
|
|---|
| 133 |
template <typename INT2, typename UINT2> |
|---|
| 134 |
struct ToUnsignedT<INT2, UINT2, true> { |
|---|
| 135 |
static UINT2 ToUnsigned(INT2 value) { |
|---|
| 136 |
return static_cast<UINT2>(value < 0 ? -value : value); |
|---|
| 137 |
} |
|---|
| 138 |
}; |
|---|
| 139 |
|
|---|
| 140 |
static STR IntToString(INT value) { |
|---|
| 141 |
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. |
|---|
| 142 |
// So round up to allocate 3 output characters per byte, plus 1 for '-'. |
|---|
| 143 |
const int kOutputBufSize = 3 * sizeof(INT) + 1; |
|---|
| 144 |
|
|---|
| 145 |
// Allocate the whole string right away, we will right back to front, and |
|---|
| 146 |
// then return the substr of what we ended up using. |
|---|
| 147 |
STR outbuf(kOutputBufSize, 0); |
|---|
| 148 |
|
|---|
| 149 |
bool is_neg = value < 0; |
|---|
| 150 |
// Even though is_neg will never be true when INT is parameterized as |
|---|
| 151 |
// unsigned, even the presence of the unary operation causes a warning. |
|---|
| 152 |
UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value); |
|---|
| 153 |
|
|---|
| 154 |
for (typename STR::iterator it = outbuf.end();;) { |
|---|
| 155 |
--it; |
|---|
| 156 |
DCHECK(it != outbuf.begin()); |
|---|
| 157 |
*it = static_cast<typename STR::value_type>((res % 10) + '0'); |
|---|
| 158 |
res /= 10; |
|---|
| 159 |
|
|---|
| 160 |
// We're done.. |
|---|
| 161 |
if (res == 0) { |
|---|
| 162 |
if (is_neg) { |
|---|
| 163 |
--it; |
|---|
| 164 |
DCHECK(it != outbuf.begin()); |
|---|
| 165 |
*it = static_cast<typename STR::value_type>('-'); |
|---|
| 166 |
} |
|---|
| 167 |
return STR(it, outbuf.end()); |
|---|
| 168 |
} |
|---|
| 169 |
} |
|---|
| 170 |
// NOTREACHED(); |
|---|
| 171 |
return STR(); |
|---|
| 172 |
} |
|---|
| 173 |
}; |
|---|
| 174 |
|
|---|
| 175 |
} |
|---|
| 176 |
|
|---|
| 177 |
std::string IntToString(int value) { |
|---|
| 178 |
return IntToStringT<std::string, int, unsigned int, true>:: |
|---|
| 179 |
IntToString(value); |
|---|
| 180 |
} |
|---|
| 181 |
std::string UintToString(unsigned int value) { |
|---|
| 182 |
return IntToStringT<std::string, unsigned int, unsigned int, false>:: |
|---|
| 183 |
IntToString(value); |
|---|
| 184 |
} |
|---|
| 185 |
std::string Int64ToString(int64 value) { |
|---|
| 186 |
return IntToStringT<std::string, int64, uint64, true>:: |
|---|
| 187 |
IntToString(value); |
|---|
| 188 |
} |
|---|
| 189 |
std::string Uint64ToString(uint64 value) { |
|---|
| 190 |
return IntToStringT<std::string, uint64, uint64, false>:: |
|---|
| 191 |
IntToString(value); |
|---|
| 192 |
} |
|---|
| 193 |
|
|---|
| 194 |
inline void StringAppendV(std::string* dst, const char* format, va_list ap) { |
|---|
| 195 |
StringAppendVT<char>(dst, format, ap); |
|---|
| 196 |
} |
|---|
| 197 |
|
|---|
| 198 |
|
|---|
| 199 |
std::string StringPrintf(const char* format, ...) { |
|---|
| 200 |
va_list ap; |
|---|
| 201 |
va_start(ap, format); |
|---|
| 202 |
std::string result; |
|---|
| 203 |
StringAppendV(&result, format, ap); |
|---|
| 204 |
va_end(ap); |
|---|
| 205 |
return result; |
|---|
| 206 |
} |
|---|
| 207 |
|
|---|
| 208 |
const std::string& SStringPrintf(std::string* dst, const char* format, ...) { |
|---|
| 209 |
va_list ap; |
|---|
| 210 |
va_start(ap, format); |
|---|
| 211 |
dst->clear(); |
|---|
| 212 |
StringAppendV(dst, format, ap); |
|---|
| 213 |
va_end(ap); |
|---|
| 214 |
return *dst; |
|---|
| 215 |
} |
|---|
| 216 |
|
|---|
| 217 |
void StringAppendF(std::string* dst, const char* format, ...) { |
|---|
| 218 |
va_list ap; |
|---|
| 219 |
va_start(ap, format); |
|---|
| 220 |
StringAppendV(dst, format, ap); |
|---|
| 221 |
va_end(ap); |
|---|
| 222 |
} |
|---|
| 223 |
|
|---|
| 224 |
} |
|---|