1 // Copyright 2014 The Android Open Source Project
2 //
3 // This software is licensed under the terms of the GNU General Public
4 // License version 2, as published by the Free Software Foundation, and
5 // may be copied, distributed, and modified under those terms.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11
12 #include "android/base/StringFormat.h"
13
14 #include <stdio.h>
15
16 namespace android {
17 namespace base {
18
StringFormatRaw(const char * format,...)19 std::string StringFormatRaw(const char* format, ...) {
20 va_list args;
21 va_start(args, format);
22 auto result = StringFormatWithArgs(format, args);
23 va_end(args);
24 return result;
25 }
26
StringFormatWithArgs(const char * format,va_list args)27 std::string StringFormatWithArgs(const char* format, va_list args) {
28 std::string result;
29 StringAppendFormatWithArgs(&result, format, args);
30 return result;
31 }
32
StringAppendFormatRaw(std::string * string,const char * format,...)33 void StringAppendFormatRaw(std::string* string, const char* format, ...) {
34 va_list args;
35 va_start(args, format);
36 StringAppendFormatWithArgs(string, format, args);
37 va_end(args);
38 }
39
StringAppendFormatWithArgs(std::string * string,const char * format,va_list args)40 void StringAppendFormatWithArgs(std::string* string,
41 const char* format,
42 va_list args) {
43 size_t cur_size = string->size();
44 size_t extra = 0;
45 for (;;) {
46 va_list args2;
47 va_copy(args2, args);
48 int ret = vsnprintf(&(*string)[cur_size], extra, format, args2);
49 va_end(args2);
50
51 if (ret == 0) {
52 // Nothing to do here.
53 break;
54 }
55
56 if (ret > 0) {
57 size_t ret_sz = static_cast<size_t>(ret);
58 if (extra == 0) {
59 // First pass, resize the string and try again.
60 extra = ret_sz + 1;
61 string->resize(cur_size + extra);
62 continue;
63 }
64 if (ret_sz < extra) {
65 // Second pass or later, success!
66 string->resize(cur_size + ret_sz);
67 return;
68 }
69 }
70
71 // NOTE: The MSVCRT.DLL implementation of snprintf() is broken and
72 // will return -1 in case of truncation. This code path is taken
73 // when this happens, or when |ret_sz| is equal or larger than
74 // |extra|. Grow the buffer to allow for more room, then try again.
75 extra += (extra >> 1) + 32;
76 string->resize(cur_size + extra);
77 }
78 }
79
80 } // namespace base
81 } // namespace android
82