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