Home | History | Annotate | Download | only in base
      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 
     12 namespace base {
     13 
     14 namespace {
     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).
     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);
     27 }
     28 
     29 inline 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.
     38 template <class StringType>
     39 static 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 
    110 std::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 
    119 std::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 
    128 std::string StringPrintV(const char* format, va_list ap) {
    129   std::string result;
    130   StringAppendV(&result, format, ap);
    131   return result;
    132 }
    133 
    134 const 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 
    143 const 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 
    153 void 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 
    160 void 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 
    167 void StringAppendV(std::string* dst, const char* format, va_list ap) {
    168   StringAppendVT(dst, format, ap);
    169 }
    170 
    171 void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
    172   StringAppendVT(dst, format, ap);
    173 }
    174 
    175 }  // namespace base
    176