1 // Copyright 2014 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "android/base/StringFormat.h"
16
17 #include <stdio.h>
18
19 namespace android {
20 namespace base {
21
StringFormatRaw(const char * format,...)22 std::string StringFormatRaw(const char* format, ...) {
23 va_list args;
24 va_start(args, format);
25 auto result = StringFormatWithArgs(format, args);
26 va_end(args);
27 return result;
28 }
29
StringFormatWithArgs(const char * format,va_list args)30 std::string StringFormatWithArgs(const char* format, va_list args) {
31 std::string result;
32 StringAppendFormatWithArgs(&result, format, args);
33 return result;
34 }
35
StringAppendFormatRaw(std::string * string,const char * format,...)36 void StringAppendFormatRaw(std::string* string, const char* format, ...) {
37 va_list args;
38 va_start(args, format);
39 StringAppendFormatWithArgs(string, format, args);
40 va_end(args);
41 }
42
StringAppendFormatWithArgs(std::string * string,const char * format,va_list args)43 void StringAppendFormatWithArgs(std::string* string,
44 const char* format,
45 va_list args) {
46 size_t cur_size = string->size();
47 size_t extra = 0;
48 for (;;) {
49 va_list args2;
50 va_copy(args2, args);
51 int ret = vsnprintf(&(*string)[cur_size], extra, format, args2);
52 va_end(args2);
53
54 if (ret == 0) {
55 // Nothing to do here.
56 break;
57 }
58
59 if (ret > 0) {
60 size_t ret_sz = static_cast<size_t>(ret);
61 if (extra == 0) {
62 // First pass, resize the string and try again.
63 extra = ret_sz + 1;
64 string->resize(cur_size + extra);
65 continue;
66 }
67 if (ret_sz < extra) {
68 // Second pass or later, success!
69 string->resize(cur_size + ret_sz);
70 return;
71 }
72 }
73
74 // NOTE: The MSVCRT.DLL implementation of snprintf() is broken and
75 // will return -1 in case of truncation. This code path is taken
76 // when this happens, or when |ret_sz| is equal or larger than
77 // |extra|. Grow the buffer to allow for more room, then try again.
78 extra += (extra >> 1) + 32;
79 string->resize(cur_size + extra);
80 }
81 }
82
83 } // namespace base
84 } // namespace android
85