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