1 // Copyright 2020 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 "aemu/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