ipc/chromium/src/base/string_util.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/string_util.h"
michael@0 6
michael@0 7 #include "build/build_config.h"
michael@0 8
michael@0 9 #include <ctype.h>
michael@0 10 #include <errno.h>
michael@0 11 #include <math.h>
michael@0 12 #include <stdarg.h>
michael@0 13 #include <stdio.h>
michael@0 14 #include <stdlib.h>
michael@0 15 #include <string.h>
michael@0 16 #include <time.h>
michael@0 17 #include <wchar.h>
michael@0 18 #include <wctype.h>
michael@0 19
michael@0 20 #include <algorithm>
michael@0 21 #include <vector>
michael@0 22
michael@0 23 #include "base/basictypes.h"
michael@0 24 #include "base/logging.h"
michael@0 25 #include "base/singleton.h"
michael@0 26
michael@0 27 namespace {
michael@0 28
michael@0 29 // Force the singleton used by Empty[W]String[16] to be a unique type. This
michael@0 30 // prevents other code that might accidentally use Singleton<string> from
michael@0 31 // getting our internal one.
michael@0 32 struct EmptyStrings {
michael@0 33 EmptyStrings() {}
michael@0 34 const std::string s;
michael@0 35 const std::wstring ws;
michael@0 36 const string16 s16;
michael@0 37 };
michael@0 38
michael@0 39 // Hack to convert any char-like type to its unsigned counterpart.
michael@0 40 // For example, it will convert char, signed char and unsigned char to unsigned
michael@0 41 // char.
michael@0 42 template<typename T>
michael@0 43 struct ToUnsigned {
michael@0 44 typedef T Unsigned;
michael@0 45 };
michael@0 46
michael@0 47 template<>
michael@0 48 struct ToUnsigned<char> {
michael@0 49 typedef unsigned char Unsigned;
michael@0 50 };
michael@0 51 template<>
michael@0 52 struct ToUnsigned<signed char> {
michael@0 53 typedef unsigned char Unsigned;
michael@0 54 };
michael@0 55 template<>
michael@0 56 struct ToUnsigned<wchar_t> {
michael@0 57 #if defined(WCHAR_T_IS_UTF16)
michael@0 58 typedef unsigned short Unsigned;
michael@0 59 #elif defined(WCHAR_T_IS_UTF32)
michael@0 60 typedef uint32_t Unsigned;
michael@0 61 #endif
michael@0 62 };
michael@0 63 template<>
michael@0 64 struct ToUnsigned<short> {
michael@0 65 typedef unsigned short Unsigned;
michael@0 66 };
michael@0 67
michael@0 68 // Generalized string-to-number conversion.
michael@0 69 //
michael@0 70 // StringToNumberTraits should provide:
michael@0 71 // - a typedef for string_type, the STL string type used as input.
michael@0 72 // - a typedef for value_type, the target numeric type.
michael@0 73 // - a static function, convert_func, which dispatches to an appropriate
michael@0 74 // strtol-like function and returns type value_type.
michael@0 75 // - a static function, valid_func, which validates |input| and returns a bool
michael@0 76 // indicating whether it is in proper form. This is used to check for
michael@0 77 // conditions that convert_func tolerates but should result in
michael@0 78 // StringToNumber returning false. For strtol-like funtions, valid_func
michael@0 79 // should check for leading whitespace.
michael@0 80 template<typename StringToNumberTraits>
michael@0 81 bool StringToNumber(const typename StringToNumberTraits::string_type& input,
michael@0 82 typename StringToNumberTraits::value_type* output) {
michael@0 83 typedef StringToNumberTraits traits;
michael@0 84
michael@0 85 errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows.
michael@0 86 typename traits::string_type::value_type* endptr = NULL;
michael@0 87 typename traits::value_type value = traits::convert_func(input.c_str(),
michael@0 88 &endptr);
michael@0 89 *output = value;
michael@0 90
michael@0 91 // Cases to return false:
michael@0 92 // - If errno is ERANGE, there was an overflow or underflow.
michael@0 93 // - If the input string is empty, there was nothing to parse.
michael@0 94 // - If endptr does not point to the end of the string, there are either
michael@0 95 // characters remaining in the string after a parsed number, or the string
michael@0 96 // does not begin with a parseable number. endptr is compared to the
michael@0 97 // expected end given the string's stated length to correctly catch cases
michael@0 98 // where the string contains embedded NUL characters.
michael@0 99 // - valid_func determines that the input is not in preferred form.
michael@0 100 return errno == 0 &&
michael@0 101 !input.empty() &&
michael@0 102 input.c_str() + input.length() == endptr &&
michael@0 103 traits::valid_func(input);
michael@0 104 }
michael@0 105
michael@0 106 class StringToLongTraits {
michael@0 107 public:
michael@0 108 typedef std::string string_type;
michael@0 109 typedef long value_type;
michael@0 110 static const int kBase = 10;
michael@0 111 static inline value_type convert_func(const string_type::value_type* str,
michael@0 112 string_type::value_type** endptr) {
michael@0 113 return strtol(str, endptr, kBase);
michael@0 114 }
michael@0 115 static inline bool valid_func(const string_type& str) {
michael@0 116 return !str.empty() && !isspace(str[0]);
michael@0 117 }
michael@0 118 };
michael@0 119
michael@0 120 class String16ToLongTraits {
michael@0 121 public:
michael@0 122 typedef string16 string_type;
michael@0 123 typedef long value_type;
michael@0 124 static const int kBase = 10;
michael@0 125 static inline value_type convert_func(const string_type::value_type* str,
michael@0 126 string_type::value_type** endptr) {
michael@0 127 #if defined(WCHAR_T_IS_UTF16)
michael@0 128 return wcstol(str, endptr, kBase);
michael@0 129 #elif defined(WCHAR_T_IS_UTF32)
michael@0 130 std::string ascii_string = UTF16ToASCII(string16(str));
michael@0 131 char* ascii_end = NULL;
michael@0 132 value_type ret = strtol(ascii_string.c_str(), &ascii_end, kBase);
michael@0 133 if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
michael@0 134 *endptr =
michael@0 135 const_cast<string_type::value_type*>(str) + ascii_string.length();
michael@0 136 }
michael@0 137 return ret;
michael@0 138 #endif
michael@0 139 }
michael@0 140 static inline bool valid_func(const string_type& str) {
michael@0 141 return !str.empty() && !iswspace(str[0]);
michael@0 142 }
michael@0 143 };
michael@0 144
michael@0 145 class StringToInt64Traits {
michael@0 146 public:
michael@0 147 typedef std::string string_type;
michael@0 148 typedef int64_t value_type;
michael@0 149 static const int kBase = 10;
michael@0 150 static inline value_type convert_func(const string_type::value_type* str,
michael@0 151 string_type::value_type** endptr) {
michael@0 152 #ifdef OS_WIN
michael@0 153 return _strtoi64(str, endptr, kBase);
michael@0 154 #else // assume OS_POSIX
michael@0 155 return strtoll(str, endptr, kBase);
michael@0 156 #endif
michael@0 157 }
michael@0 158 static inline bool valid_func(const string_type& str) {
michael@0 159 return !str.empty() && !isspace(str[0]);
michael@0 160 }
michael@0 161 };
michael@0 162
michael@0 163 class String16ToInt64Traits {
michael@0 164 public:
michael@0 165 typedef string16 string_type;
michael@0 166 typedef int64_t value_type;
michael@0 167 static const int kBase = 10;
michael@0 168 static inline value_type convert_func(const string_type::value_type* str,
michael@0 169 string_type::value_type** endptr) {
michael@0 170 #ifdef OS_WIN
michael@0 171 return _wcstoi64(str, endptr, kBase);
michael@0 172 #else // assume OS_POSIX
michael@0 173 std::string ascii_string = UTF16ToASCII(string16(str));
michael@0 174 char* ascii_end = NULL;
michael@0 175 value_type ret = strtoll(ascii_string.c_str(), &ascii_end, kBase);
michael@0 176 if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
michael@0 177 *endptr =
michael@0 178 const_cast<string_type::value_type*>(str) + ascii_string.length();
michael@0 179 }
michael@0 180 return ret;
michael@0 181 #endif
michael@0 182 }
michael@0 183 static inline bool valid_func(const string_type& str) {
michael@0 184 return !str.empty() && !iswspace(str[0]);
michael@0 185 }
michael@0 186 };
michael@0 187
michael@0 188 } // namespace
michael@0 189
michael@0 190
michael@0 191 namespace base {
michael@0 192
michael@0 193 bool IsWprintfFormatPortable(const wchar_t* format) {
michael@0 194 for (const wchar_t* position = format; *position != '\0'; ++position) {
michael@0 195
michael@0 196 if (*position == '%') {
michael@0 197 bool in_specification = true;
michael@0 198 bool modifier_l = false;
michael@0 199 while (in_specification) {
michael@0 200 // Eat up characters until reaching a known specifier.
michael@0 201 if (*++position == '\0') {
michael@0 202 // The format string ended in the middle of a specification. Call
michael@0 203 // it portable because no unportable specifications were found. The
michael@0 204 // string is equally broken on all platforms.
michael@0 205 return true;
michael@0 206 }
michael@0 207
michael@0 208 if (*position == 'l') {
michael@0 209 // 'l' is the only thing that can save the 's' and 'c' specifiers.
michael@0 210 modifier_l = true;
michael@0 211 } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
michael@0 212 *position == 'S' || *position == 'C' || *position == 'F' ||
michael@0 213 *position == 'D' || *position == 'O' || *position == 'U') {
michael@0 214 // Not portable.
michael@0 215 return false;
michael@0 216 }
michael@0 217
michael@0 218 if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
michael@0 219 // Portable, keep scanning the rest of the format string.
michael@0 220 in_specification = false;
michael@0 221 }
michael@0 222 }
michael@0 223 }
michael@0 224
michael@0 225 }
michael@0 226
michael@0 227 return true;
michael@0 228 }
michael@0 229
michael@0 230
michael@0 231 } // namespace base
michael@0 232
michael@0 233 static const wchar_t kWhitespaceWide[] = {
michael@0 234 0x0009, // <control-0009> to <control-000D>
michael@0 235 0x000A,
michael@0 236 0x000B,
michael@0 237 0x000C,
michael@0 238 0x000D,
michael@0 239 0x0020, // Space
michael@0 240 0x0085, // <control-0085>
michael@0 241 0x00A0, // No-Break Space
michael@0 242 0x1680, // Ogham Space Mark
michael@0 243 0x180E, // Mongolian Vowel Separator
michael@0 244 0x2000, // En Quad to Hair Space
michael@0 245 0x2001,
michael@0 246 0x2002,
michael@0 247 0x2003,
michael@0 248 0x2004,
michael@0 249 0x2005,
michael@0 250 0x2006,
michael@0 251 0x2007,
michael@0 252 0x2008,
michael@0 253 0x2009,
michael@0 254 0x200A,
michael@0 255 0x200C, // Zero Width Non-Joiner
michael@0 256 0x2028, // Line Separator
michael@0 257 0x2029, // Paragraph Separator
michael@0 258 0x202F, // Narrow No-Break Space
michael@0 259 0x205F, // Medium Mathematical Space
michael@0 260 0x3000, // Ideographic Space
michael@0 261 0
michael@0 262 };
michael@0 263 static const char kWhitespaceASCII[] = {
michael@0 264 0x09, // <control-0009> to <control-000D>
michael@0 265 0x0A,
michael@0 266 0x0B,
michael@0 267 0x0C,
michael@0 268 0x0D,
michael@0 269 0x20, // Space
michael@0 270 0
michael@0 271 };
michael@0 272
michael@0 273 template<typename STR>
michael@0 274 TrimPositions TrimStringT(const STR& input,
michael@0 275 const typename STR::value_type trim_chars[],
michael@0 276 TrimPositions positions,
michael@0 277 STR* output) {
michael@0 278 // Find the edges of leading/trailing whitespace as desired.
michael@0 279 const typename STR::size_type last_char = input.length() - 1;
michael@0 280 const typename STR::size_type first_good_char = (positions & TRIM_LEADING) ?
michael@0 281 input.find_first_not_of(trim_chars) : 0;
michael@0 282 const typename STR::size_type last_good_char = (positions & TRIM_TRAILING) ?
michael@0 283 input.find_last_not_of(trim_chars) : last_char;
michael@0 284
michael@0 285 // When the string was all whitespace, report that we stripped off whitespace
michael@0 286 // from whichever position the caller was interested in. For empty input, we
michael@0 287 // stripped no whitespace, but we still need to clear |output|.
michael@0 288 if (input.empty() ||
michael@0 289 (first_good_char == STR::npos) || (last_good_char == STR::npos)) {
michael@0 290 bool input_was_empty = input.empty(); // in case output == &input
michael@0 291 output->clear();
michael@0 292 return input_was_empty ? TRIM_NONE : positions;
michael@0 293 }
michael@0 294
michael@0 295 // Trim the whitespace.
michael@0 296 *output =
michael@0 297 input.substr(first_good_char, last_good_char - first_good_char + 1);
michael@0 298
michael@0 299 // Return where we trimmed from.
michael@0 300 return static_cast<TrimPositions>(
michael@0 301 ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) |
michael@0 302 ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
michael@0 303 }
michael@0 304
michael@0 305 TrimPositions TrimWhitespace(const std::wstring& input,
michael@0 306 TrimPositions positions,
michael@0 307 std::wstring* output) {
michael@0 308 return TrimStringT(input, kWhitespaceWide, positions, output);
michael@0 309 }
michael@0 310
michael@0 311 TrimPositions TrimWhitespaceASCII(const std::string& input,
michael@0 312 TrimPositions positions,
michael@0 313 std::string* output) {
michael@0 314 return TrimStringT(input, kWhitespaceASCII, positions, output);
michael@0 315 }
michael@0 316
michael@0 317 // This function is only for backward-compatibility.
michael@0 318 // To be removed when all callers are updated.
michael@0 319 TrimPositions TrimWhitespace(const std::string& input,
michael@0 320 TrimPositions positions,
michael@0 321 std::string* output) {
michael@0 322 return TrimWhitespaceASCII(input, positions, output);
michael@0 323 }
michael@0 324
michael@0 325 std::string WideToASCII(const std::wstring& wide) {
michael@0 326 DCHECK(IsStringASCII(wide));
michael@0 327 return std::string(wide.begin(), wide.end());
michael@0 328 }
michael@0 329
michael@0 330 std::wstring ASCIIToWide(const std::string& ascii) {
michael@0 331 DCHECK(IsStringASCII(ascii));
michael@0 332 return std::wstring(ascii.begin(), ascii.end());
michael@0 333 }
michael@0 334
michael@0 335 std::string UTF16ToASCII(const string16& utf16) {
michael@0 336 DCHECK(IsStringASCII(utf16));
michael@0 337 return std::string(utf16.begin(), utf16.end());
michael@0 338 }
michael@0 339
michael@0 340 string16 ASCIIToUTF16(const std::string& ascii) {
michael@0 341 DCHECK(IsStringASCII(ascii));
michael@0 342 return string16(ascii.begin(), ascii.end());
michael@0 343 }
michael@0 344
michael@0 345 template<class STR>
michael@0 346 static bool DoIsStringASCII(const STR& str) {
michael@0 347 for (size_t i = 0; i < str.length(); i++) {
michael@0 348 typename ToUnsigned<typename STR::value_type>::Unsigned c = str[i];
michael@0 349 if (c > 0x7F)
michael@0 350 return false;
michael@0 351 }
michael@0 352 return true;
michael@0 353 }
michael@0 354
michael@0 355 bool IsStringASCII(const std::wstring& str) {
michael@0 356 return DoIsStringASCII(str);
michael@0 357 }
michael@0 358
michael@0 359 #if !defined(WCHAR_T_IS_UTF16)
michael@0 360 bool IsStringASCII(const string16& str) {
michael@0 361 return DoIsStringASCII(str);
michael@0 362 }
michael@0 363 #endif
michael@0 364
michael@0 365 bool IsStringASCII(const std::string& str) {
michael@0 366 return DoIsStringASCII(str);
michael@0 367 }
michael@0 368
michael@0 369 // Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
michael@0 370 // is the size of the buffer. These return the number of characters in the
michael@0 371 // formatted string excluding the NUL terminator. If the buffer is not
michael@0 372 // large enough to accommodate the formatted string without truncation, they
michael@0 373 // return the number of characters that would be in the fully-formatted string
michael@0 374 // (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
michael@0 375 inline int vsnprintfT(char* buffer,
michael@0 376 size_t buf_size,
michael@0 377 const char* format,
michael@0 378 va_list argptr) {
michael@0 379 return base::vsnprintf(buffer, buf_size, format, argptr);
michael@0 380 }
michael@0 381
michael@0 382 inline int vsnprintfT(wchar_t* buffer,
michael@0 383 size_t buf_size,
michael@0 384 const wchar_t* format,
michael@0 385 va_list argptr) {
michael@0 386 return base::vswprintf(buffer, buf_size, format, argptr);
michael@0 387 }
michael@0 388
michael@0 389 // Templatized backend for StringPrintF/StringAppendF. This does not finalize
michael@0 390 // the va_list, the caller is expected to do that.
michael@0 391 template <class StringType>
michael@0 392 static void StringAppendVT(StringType* dst,
michael@0 393 const typename StringType::value_type* format,
michael@0 394 va_list ap) {
michael@0 395 // First try with a small fixed size buffer.
michael@0 396 // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
michael@0 397 // and StringUtilTest.StringPrintfBounds.
michael@0 398 typename StringType::value_type stack_buf[1024];
michael@0 399
michael@0 400 va_list backup_ap;
michael@0 401 base_va_copy(backup_ap, ap);
michael@0 402
michael@0 403 #if !defined(OS_WIN)
michael@0 404 errno = 0;
michael@0 405 #endif
michael@0 406 int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, backup_ap);
michael@0 407 va_end(backup_ap);
michael@0 408
michael@0 409 if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
michael@0 410 // It fit.
michael@0 411 dst->append(stack_buf, result);
michael@0 412 return;
michael@0 413 }
michael@0 414
michael@0 415 // Repeatedly increase buffer size until it fits.
michael@0 416 int mem_length = arraysize(stack_buf);
michael@0 417 while (true) {
michael@0 418 if (result < 0) {
michael@0 419 #if !defined(OS_WIN)
michael@0 420 // On Windows, vsnprintfT always returns the number of characters in a
michael@0 421 // fully-formatted string, so if we reach this point, something else is
michael@0 422 // wrong and no amount of buffer-doubling is going to fix it.
michael@0 423 if (errno != 0 && errno != EOVERFLOW)
michael@0 424 #endif
michael@0 425 {
michael@0 426 // If an error other than overflow occurred, it's never going to work.
michael@0 427 DLOG(WARNING) << "Unable to printf the requested string due to error.";
michael@0 428 return;
michael@0 429 }
michael@0 430 // Try doubling the buffer size.
michael@0 431 mem_length *= 2;
michael@0 432 } else {
michael@0 433 // We need exactly "result + 1" characters.
michael@0 434 mem_length = result + 1;
michael@0 435 }
michael@0 436
michael@0 437 if (mem_length > 32 * 1024 * 1024) {
michael@0 438 // That should be plenty, don't try anything larger. This protects
michael@0 439 // against huge allocations when using vsnprintfT implementations that
michael@0 440 // return -1 for reasons other than overflow without setting errno.
michael@0 441 DLOG(WARNING) << "Unable to printf the requested string due to size.";
michael@0 442 return;
michael@0 443 }
michael@0 444
michael@0 445 std::vector<typename StringType::value_type> mem_buf(mem_length);
michael@0 446
michael@0 447 // Restore the va_list before we use it again.
michael@0 448 base_va_copy(backup_ap, ap);
michael@0 449
michael@0 450 result = vsnprintfT(&mem_buf[0], mem_length, format, ap);
michael@0 451 va_end(backup_ap);
michael@0 452
michael@0 453 if ((result >= 0) && (result < mem_length)) {
michael@0 454 // It fit.
michael@0 455 dst->append(&mem_buf[0], result);
michael@0 456 return;
michael@0 457 }
michael@0 458 }
michael@0 459 }
michael@0 460
michael@0 461 namespace {
michael@0 462
michael@0 463 template <typename STR, typename INT, typename UINT, bool NEG>
michael@0 464 struct IntToStringT {
michael@0 465
michael@0 466 // This is to avoid a compiler warning about unary minus on unsigned type.
michael@0 467 // For example, say you had the following code:
michael@0 468 // template <typename INT>
michael@0 469 // INT abs(INT value) { return value < 0 ? -value : value; }
michael@0 470 // Even though if INT is unsigned, it's impossible for value < 0, so the
michael@0 471 // unary minus will never be taken, the compiler will still generate a
michael@0 472 // warning. We do a little specialization dance...
michael@0 473 template <typename INT2, typename UINT2, bool NEG2>
michael@0 474 struct ToUnsignedT { };
michael@0 475
michael@0 476 template <typename INT2, typename UINT2>
michael@0 477 struct ToUnsignedT<INT2, UINT2, false> {
michael@0 478 static UINT2 ToUnsigned(INT2 value) {
michael@0 479 return static_cast<UINT2>(value);
michael@0 480 }
michael@0 481 };
michael@0 482
michael@0 483 template <typename INT2, typename UINT2>
michael@0 484 struct ToUnsignedT<INT2, UINT2, true> {
michael@0 485 static UINT2 ToUnsigned(INT2 value) {
michael@0 486 return static_cast<UINT2>(value < 0 ? -value : value);
michael@0 487 }
michael@0 488 };
michael@0 489
michael@0 490 // This set of templates is very similar to the above templates, but
michael@0 491 // for testing whether an integer is negative.
michael@0 492 template <typename INT2, bool NEG2>
michael@0 493 struct TestNegT {};
michael@0 494 template <typename INT2>
michael@0 495 struct TestNegT<INT2, false> {
michael@0 496 static bool TestNeg(INT2 value) {
michael@0 497 // value is unsigned, and can never be negative.
michael@0 498 return false;
michael@0 499 }
michael@0 500 };
michael@0 501 template <typename INT2>
michael@0 502 struct TestNegT<INT2, true> {
michael@0 503 static bool TestNeg(INT2 value) {
michael@0 504 return value < 0;
michael@0 505 }
michael@0 506 };
michael@0 507
michael@0 508 static STR IntToString(INT value) {
michael@0 509 // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
michael@0 510 // So round up to allocate 3 output characters per byte, plus 1 for '-'.
michael@0 511 const int kOutputBufSize = 3 * sizeof(INT) + 1;
michael@0 512
michael@0 513 // Allocate the whole string right away, we will right back to front, and
michael@0 514 // then return the substr of what we ended up using.
michael@0 515 STR outbuf(kOutputBufSize, 0);
michael@0 516
michael@0 517 bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
michael@0 518 // Even though is_neg will never be true when INT is parameterized as
michael@0 519 // unsigned, even the presence of the unary operation causes a warning.
michael@0 520 UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
michael@0 521
michael@0 522 for (typename STR::iterator it = outbuf.end();;) {
michael@0 523 --it;
michael@0 524 DCHECK(it != outbuf.begin());
michael@0 525 *it = static_cast<typename STR::value_type>((res % 10) + '0');
michael@0 526 res /= 10;
michael@0 527
michael@0 528 // We're done..
michael@0 529 if (res == 0) {
michael@0 530 if (is_neg) {
michael@0 531 --it;
michael@0 532 DCHECK(it != outbuf.begin());
michael@0 533 *it = static_cast<typename STR::value_type>('-');
michael@0 534 }
michael@0 535 return STR(it, outbuf.end());
michael@0 536 }
michael@0 537 }
michael@0 538 NOTREACHED();
michael@0 539 return STR();
michael@0 540 }
michael@0 541 };
michael@0 542
michael@0 543 }
michael@0 544
michael@0 545 std::string IntToString(int value) {
michael@0 546 return IntToStringT<std::string, int, unsigned int, true>::
michael@0 547 IntToString(value);
michael@0 548 }
michael@0 549 std::wstring IntToWString(int value) {
michael@0 550 return IntToStringT<std::wstring, int, unsigned int, true>::
michael@0 551 IntToString(value);
michael@0 552 }
michael@0 553 std::string UintToString(unsigned int value) {
michael@0 554 return IntToStringT<std::string, unsigned int, unsigned int, false>::
michael@0 555 IntToString(value);
michael@0 556 }
michael@0 557 std::wstring UintToWString(unsigned int value) {
michael@0 558 return IntToStringT<std::wstring, unsigned int, unsigned int, false>::
michael@0 559 IntToString(value);
michael@0 560 }
michael@0 561 std::string Int64ToString(int64_t value) {
michael@0 562 return IntToStringT<std::string, int64_t, uint64_t, true>::
michael@0 563 IntToString(value);
michael@0 564 }
michael@0 565 std::wstring Int64ToWString(int64_t value) {
michael@0 566 return IntToStringT<std::wstring, int64_t, uint64_t, true>::
michael@0 567 IntToString(value);
michael@0 568 }
michael@0 569 std::string Uint64ToString(uint64_t value) {
michael@0 570 return IntToStringT<std::string, uint64_t, uint64_t, false>::
michael@0 571 IntToString(value);
michael@0 572 }
michael@0 573 std::wstring Uint64ToWString(uint64_t value) {
michael@0 574 return IntToStringT<std::wstring, uint64_t, uint64_t, false>::
michael@0 575 IntToString(value);
michael@0 576 }
michael@0 577
michael@0 578 // Lower-level routine that takes a va_list and appends to a specified
michael@0 579 // string. All other routines are just convenience wrappers around it.
michael@0 580 static void StringAppendV(std::string* dst, const char* format, va_list ap) {
michael@0 581 StringAppendVT(dst, format, ap);
michael@0 582 }
michael@0 583
michael@0 584 static void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
michael@0 585 StringAppendVT(dst, format, ap);
michael@0 586 }
michael@0 587
michael@0 588 std::string StringPrintf(const char* format, ...) {
michael@0 589 va_list ap;
michael@0 590 va_start(ap, format);
michael@0 591 std::string result;
michael@0 592 StringAppendV(&result, format, ap);
michael@0 593 va_end(ap);
michael@0 594 return result;
michael@0 595 }
michael@0 596
michael@0 597 std::wstring StringPrintf(const wchar_t* format, ...) {
michael@0 598 va_list ap;
michael@0 599 va_start(ap, format);
michael@0 600 std::wstring result;
michael@0 601 StringAppendV(&result, format, ap);
michael@0 602 va_end(ap);
michael@0 603 return result;
michael@0 604 }
michael@0 605
michael@0 606 const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
michael@0 607 va_list ap;
michael@0 608 va_start(ap, format);
michael@0 609 dst->clear();
michael@0 610 StringAppendV(dst, format, ap);
michael@0 611 va_end(ap);
michael@0 612 return *dst;
michael@0 613 }
michael@0 614
michael@0 615 const std::wstring& SStringPrintf(std::wstring* dst,
michael@0 616 const wchar_t* format, ...) {
michael@0 617 va_list ap;
michael@0 618 va_start(ap, format);
michael@0 619 dst->clear();
michael@0 620 StringAppendV(dst, format, ap);
michael@0 621 va_end(ap);
michael@0 622 return *dst;
michael@0 623 }
michael@0 624
michael@0 625 void StringAppendF(std::string* dst, const char* format, ...) {
michael@0 626 va_list ap;
michael@0 627 va_start(ap, format);
michael@0 628 StringAppendV(dst, format, ap);
michael@0 629 va_end(ap);
michael@0 630 }
michael@0 631
michael@0 632 void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
michael@0 633 va_list ap;
michael@0 634 va_start(ap, format);
michael@0 635 StringAppendV(dst, format, ap);
michael@0 636 va_end(ap);
michael@0 637 }
michael@0 638
michael@0 639 template<typename STR>
michael@0 640 static void SplitStringT(const STR& str,
michael@0 641 const typename STR::value_type s,
michael@0 642 bool trim_whitespace,
michael@0 643 std::vector<STR>* r) {
michael@0 644 size_t last = 0;
michael@0 645 size_t i;
michael@0 646 size_t c = str.size();
michael@0 647 for (i = 0; i <= c; ++i) {
michael@0 648 if (i == c || str[i] == s) {
michael@0 649 size_t len = i - last;
michael@0 650 STR tmp = str.substr(last, len);
michael@0 651 if (trim_whitespace) {
michael@0 652 STR t_tmp;
michael@0 653 TrimWhitespace(tmp, TRIM_ALL, &t_tmp);
michael@0 654 r->push_back(t_tmp);
michael@0 655 } else {
michael@0 656 r->push_back(tmp);
michael@0 657 }
michael@0 658 last = i + 1;
michael@0 659 }
michael@0 660 }
michael@0 661 }
michael@0 662
michael@0 663 void SplitString(const std::wstring& str,
michael@0 664 wchar_t s,
michael@0 665 std::vector<std::wstring>* r) {
michael@0 666 SplitStringT(str, s, true, r);
michael@0 667 }
michael@0 668
michael@0 669 void SplitString(const std::string& str,
michael@0 670 char s,
michael@0 671 std::vector<std::string>* r) {
michael@0 672 SplitStringT(str, s, true, r);
michael@0 673 }
michael@0 674
michael@0 675 // For the various *ToInt conversions, there are no *ToIntTraits classes to use
michael@0 676 // because there's no such thing as strtoi. Use *ToLongTraits through a cast
michael@0 677 // instead, requiring that long and int are compatible and equal-width. They
michael@0 678 // are on our target platforms.
michael@0 679
michael@0 680 // XXX Sigh.
michael@0 681
michael@0 682 #if !defined(ARCH_CPU_64_BITS)
michael@0 683 bool StringToInt(const std::string& input, int* output) {
michael@0 684 COMPILE_ASSERT(sizeof(int) == sizeof(long), cannot_strtol_to_int);
michael@0 685 return StringToNumber<StringToLongTraits>(input,
michael@0 686 reinterpret_cast<long*>(output));
michael@0 687 }
michael@0 688
michael@0 689 bool StringToInt(const string16& input, int* output) {
michael@0 690 COMPILE_ASSERT(sizeof(int) == sizeof(long), cannot_wcstol_to_int);
michael@0 691 return StringToNumber<String16ToLongTraits>(input,
michael@0 692 reinterpret_cast<long*>(output));
michael@0 693 }
michael@0 694
michael@0 695 #else
michael@0 696 bool StringToInt(const std::string& input, int* output) {
michael@0 697 long tmp;
michael@0 698 bool ok = StringToNumber<StringToLongTraits>(input, &tmp);
michael@0 699 if (!ok || tmp > kint32max) {
michael@0 700 return false;
michael@0 701 }
michael@0 702 *output = static_cast<int>(tmp);
michael@0 703 return true;
michael@0 704 }
michael@0 705
michael@0 706 bool StringToInt(const string16& input, int* output) {
michael@0 707 long tmp;
michael@0 708 bool ok = StringToNumber<String16ToLongTraits>(input, &tmp);
michael@0 709 if (!ok || tmp > kint32max) {
michael@0 710 return false;
michael@0 711 }
michael@0 712 *output = static_cast<int>(tmp);
michael@0 713 return true;
michael@0 714 }
michael@0 715 #endif // !defined(ARCH_CPU_64_BITS)
michael@0 716
michael@0 717 bool StringToInt64(const std::string& input, int64_t* output) {
michael@0 718 return StringToNumber<StringToInt64Traits>(input, output);
michael@0 719 }
michael@0 720
michael@0 721 bool StringToInt64(const string16& input, int64_t* output) {
michael@0 722 return StringToNumber<String16ToInt64Traits>(input, output);
michael@0 723 }
michael@0 724
michael@0 725 int StringToInt(const std::string& value) {
michael@0 726 int result;
michael@0 727 StringToInt(value, &result);
michael@0 728 return result;
michael@0 729 }
michael@0 730
michael@0 731 int StringToInt(const string16& value) {
michael@0 732 int result;
michael@0 733 StringToInt(value, &result);
michael@0 734 return result;
michael@0 735 }
michael@0 736
michael@0 737 int64_t StringToInt64(const std::string& value) {
michael@0 738 int64_t result;
michael@0 739 StringToInt64(value, &result);
michael@0 740 return result;
michael@0 741 }
michael@0 742
michael@0 743 int64_t StringToInt64(const string16& value) {
michael@0 744 int64_t result;
michael@0 745 StringToInt64(value, &result);
michael@0 746 return result;
michael@0 747 }
michael@0 748
michael@0 749 // The following code is compatible with the OpenBSD lcpy interface. See:
michael@0 750 // http://www.gratisoft.us/todd/papers/strlcpy.html
michael@0 751 // ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
michael@0 752
michael@0 753 namespace {
michael@0 754
michael@0 755 template <typename CHAR>
michael@0 756 size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
michael@0 757 for (size_t i = 0; i < dst_size; ++i) {
michael@0 758 if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
michael@0 759 return i;
michael@0 760 }
michael@0 761
michael@0 762 // We were left off at dst_size. We over copied 1 byte. Null terminate.
michael@0 763 if (dst_size != 0)
michael@0 764 dst[dst_size - 1] = 0;
michael@0 765
michael@0 766 // Count the rest of the |src|, and return it's length in characters.
michael@0 767 while (src[dst_size]) ++dst_size;
michael@0 768 return dst_size;
michael@0 769 }
michael@0 770
michael@0 771 } // namespace
michael@0 772
michael@0 773 size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
michael@0 774 return lcpyT<char>(dst, src, dst_size);
michael@0 775 }
michael@0 776 size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
michael@0 777 return lcpyT<wchar_t>(dst, src, dst_size);
michael@0 778 }

mercurial