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