1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/stringprintf.h" 6 7#include <errno.h> 8 9#include "base/string_util.h" 10#include "base/utf_string_conversions.h" 11 12namespace base { 13 14namespace { 15 16// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter 17// is the size of the buffer. These return the number of characters in the 18// formatted string excluding the NUL terminator. If the buffer is not 19// large enough to accommodate the formatted string without truncation, they 20// return the number of characters that would be in the fully-formatted string 21// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms). 22inline int vsnprintfT(char* buffer, 23 size_t buf_size, 24 const char* format, 25 va_list argptr) { 26 return base::vsnprintf(buffer, buf_size, format, argptr); 27} 28 29inline int vsnprintfT(wchar_t* buffer, 30 size_t buf_size, 31 const wchar_t* format, 32 va_list argptr) { 33 return base::vswprintf(buffer, buf_size, format, argptr); 34} 35 36// Templatized backend for StringPrintF/StringAppendF. This does not finalize 37// the va_list, the caller is expected to do that. 38template <class StringType> 39static void StringAppendVT(StringType* dst, 40 const typename StringType::value_type* format, 41 va_list ap) { 42 // First try with a small fixed size buffer. 43 // This buffer size should be kept in sync with StringUtilTest.GrowBoundary 44 // and StringUtilTest.StringPrintfBounds. 45 typename StringType::value_type stack_buf[1024]; 46 47 va_list ap_copy; 48 GG_VA_COPY(ap_copy, ap); 49 50#if !defined(OS_WIN) 51 errno = 0; 52#endif 53 int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy); 54 va_end(ap_copy); 55 56 if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) { 57 // It fit. 58 dst->append(stack_buf, result); 59 return; 60 } 61 62 // Repeatedly increase buffer size until it fits. 63 int mem_length = arraysize(stack_buf); 64 while (true) { 65 if (result < 0) { 66#if !defined(OS_WIN) 67 // On Windows, vsnprintfT always returns the number of characters in a 68 // fully-formatted string, so if we reach this point, something else is 69 // wrong and no amount of buffer-doubling is going to fix it. 70 if (errno != 0 && errno != EOVERFLOW) 71#endif 72 { 73 // If an error other than overflow occurred, it's never going to work. 74 DLOG(WARNING) << "Unable to printf the requested string due to error."; 75 return; 76 } 77 // Try doubling the buffer size. 78 mem_length *= 2; 79 } else { 80 // We need exactly "result + 1" characters. 81 mem_length = result + 1; 82 } 83 84 if (mem_length > 32 * 1024 * 1024) { 85 // That should be plenty, don't try anything larger. This protects 86 // against huge allocations when using vsnprintfT implementations that 87 // return -1 for reasons other than overflow without setting errno. 88 DLOG(WARNING) << "Unable to printf the requested string due to size."; 89 return; 90 } 91 92 std::vector<typename StringType::value_type> mem_buf(mem_length); 93 94 // NOTE: You can only use a va_list once. Since we're in a while loop, we 95 // need to make a new copy each time so we don't use up the original. 96 GG_VA_COPY(ap_copy, ap); 97 result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy); 98 va_end(ap_copy); 99 100 if ((result >= 0) && (result < mem_length)) { 101 // It fit. 102 dst->append(&mem_buf[0], result); 103 return; 104 } 105 } 106} 107 108} // namespace 109 110std::string StringPrintf(const char* format, ...) { 111 va_list ap; 112 va_start(ap, format); 113 std::string result; 114 StringAppendV(&result, format, ap); 115 va_end(ap); 116 return result; 117} 118 119std::wstring StringPrintf(const wchar_t* format, ...) { 120 va_list ap; 121 va_start(ap, format); 122 std::wstring result; 123 StringAppendV(&result, format, ap); 124 va_end(ap); 125 return result; 126} 127 128std::string StringPrintV(const char* format, va_list ap) { 129 std::string result; 130 StringAppendV(&result, format, ap); 131 return result; 132} 133 134const std::string& SStringPrintf(std::string* dst, const char* format, ...) { 135 va_list ap; 136 va_start(ap, format); 137 dst->clear(); 138 StringAppendV(dst, format, ap); 139 va_end(ap); 140 return *dst; 141} 142 143const std::wstring& SStringPrintf(std::wstring* dst, 144 const wchar_t* format, ...) { 145 va_list ap; 146 va_start(ap, format); 147 dst->clear(); 148 StringAppendV(dst, format, ap); 149 va_end(ap); 150 return *dst; 151} 152 153void StringAppendF(std::string* dst, const char* format, ...) { 154 va_list ap; 155 va_start(ap, format); 156 StringAppendV(dst, format, ap); 157 va_end(ap); 158} 159 160void StringAppendF(std::wstring* dst, const wchar_t* format, ...) { 161 va_list ap; 162 va_start(ap, format); 163 StringAppendV(dst, format, ap); 164 va_end(ap); 165} 166 167void StringAppendV(std::string* dst, const char* format, va_list ap) { 168 StringAppendVT(dst, format, ap); 169} 170 171void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) { 172 StringAppendVT(dst, format, ap); 173} 174 175} // namespace base 176