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 19 String StringFormat(const char* format, ...) { 20 va_list args; 21 va_start(args, format); 22 String result = StringFormatWithArgs(format, args); 23 va_end(args); 24 return result; 25 } 26 27 String StringFormatWithArgs(const char* format, va_list args) { 28 String result; 29 StringAppendFormatWithArgs(&result, format, args); 30 return result; 31 } 32 33 void StringAppendFormat(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 40 void StringAppendFormatWithArgs(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 81 } // namespace base 82 } // namespace android 83