Speculative fix for the white/stale tab issue on Windows.
[chromium-blink-merge.git] / base / stringprintf.cc
blob79c6562a22bf292c1f2c48e60df86a008557e3ff
1 // Copyright (c) 2012 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.
5 #include "base/stringprintf.h"
7 #include <errno.h>
9 #include "base/string_util.h"
10 #include "base/utf_string_conversions.h"
12 namespace base {
14 namespace {
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).
22 inline 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);
29 #if !defined(OS_ANDROID)
30 inline int vsnprintfT(wchar_t* buffer,
31 size_t buf_size,
32 const wchar_t* format,
33 va_list argptr) {
34 return base::vswprintf(buffer, buf_size, format, argptr);
36 #endif
38 // Templatized backend for StringPrintF/StringAppendF. This does not finalize
39 // the va_list, the caller is expected to do that.
40 template <class StringType>
41 static void StringAppendVT(StringType* dst,
42 const typename StringType::value_type* format,
43 va_list ap) {
44 // First try with a small fixed size buffer.
45 // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
46 // and StringUtilTest.StringPrintfBounds.
47 typename StringType::value_type stack_buf[1024];
49 va_list ap_copy;
50 GG_VA_COPY(ap_copy, ap);
52 #if !defined(OS_WIN)
53 errno = 0;
54 #endif
55 int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
56 va_end(ap_copy);
58 if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
59 // It fit.
60 dst->append(stack_buf, result);
61 return;
64 // Repeatedly increase buffer size until it fits.
65 int mem_length = arraysize(stack_buf);
66 while (true) {
67 if (result < 0) {
68 #if !defined(OS_WIN)
69 // On Windows, vsnprintfT always returns the number of characters in a
70 // fully-formatted string, so if we reach this point, something else is
71 // wrong and no amount of buffer-doubling is going to fix it.
72 if (errno != 0 && errno != EOVERFLOW)
73 #endif
75 // If an error other than overflow occurred, it's never going to work.
76 DLOG(WARNING) << "Unable to printf the requested string due to error.";
77 return;
79 // Try doubling the buffer size.
80 mem_length *= 2;
81 } else {
82 // We need exactly "result + 1" characters.
83 mem_length = result + 1;
86 if (mem_length > 32 * 1024 * 1024) {
87 // That should be plenty, don't try anything larger. This protects
88 // against huge allocations when using vsnprintfT implementations that
89 // return -1 for reasons other than overflow without setting errno.
90 DLOG(WARNING) << "Unable to printf the requested string due to size.";
91 return;
94 std::vector<typename StringType::value_type> mem_buf(mem_length);
96 // NOTE: You can only use a va_list once. Since we're in a while loop, we
97 // need to make a new copy each time so we don't use up the original.
98 GG_VA_COPY(ap_copy, ap);
99 result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
100 va_end(ap_copy);
102 if ((result >= 0) && (result < mem_length)) {
103 // It fit.
104 dst->append(&mem_buf[0], result);
105 return;
110 } // namespace
112 std::string StringPrintf(const char* format, ...) {
113 va_list ap;
114 va_start(ap, format);
115 std::string result;
116 StringAppendV(&result, format, ap);
117 va_end(ap);
118 return result;
121 #if !defined(OS_ANDROID)
122 std::wstring StringPrintf(const wchar_t* format, ...) {
123 va_list ap;
124 va_start(ap, format);
125 std::wstring result;
126 StringAppendV(&result, format, ap);
127 va_end(ap);
128 return result;
130 #endif
132 std::string StringPrintV(const char* format, va_list ap) {
133 std::string result;
134 StringAppendV(&result, format, ap);
135 return result;
138 const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
139 va_list ap;
140 va_start(ap, format);
141 dst->clear();
142 StringAppendV(dst, format, ap);
143 va_end(ap);
144 return *dst;
147 #if !defined(OS_ANDROID)
148 const std::wstring& SStringPrintf(std::wstring* dst,
149 const wchar_t* format, ...) {
150 va_list ap;
151 va_start(ap, format);
152 dst->clear();
153 StringAppendV(dst, format, ap);
154 va_end(ap);
155 return *dst;
157 #endif
159 void StringAppendF(std::string* dst, const char* format, ...) {
160 va_list ap;
161 va_start(ap, format);
162 StringAppendV(dst, format, ap);
163 va_end(ap);
166 #if !defined(OS_ANDROID)
167 void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
168 va_list ap;
169 va_start(ap, format);
170 StringAppendV(dst, format, ap);
171 va_end(ap);
173 #endif
175 void StringAppendV(std::string* dst, const char* format, va_list ap) {
176 StringAppendVT(dst, format, ap);
179 #if !defined(OS_ANDROID)
180 void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
181 StringAppendVT(dst, format, ap);
183 #endif
185 } // namespace base