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