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       if (errno != 0 && errno != EOVERFLOW)
     74 #endif
     75       {
     76         // If an error other than overflow occurred, it's never going to work.
     77         DLOG(WARNING) << "Unable to printf the requested string due to error.";
     78         return;
     79       }
     80       // Try doubling the buffer size.
     81       mem_length *= 2;
     82     } else {
     83       // We need exactly "result + 1" characters.
     84       mem_length = result + 1;
     85     }
     86 
     87     if (mem_length > 32 * 1024 * 1024) {
     88       // That should be plenty, don't try anything larger.  This protects
     89       // against huge allocations when using vsnprintfT implementations that
     90       // return -1 for reasons other than overflow without setting errno.
     91       DLOG(WARNING) << "Unable to printf the requested string due to size.";
     92       return;
     93     }
     94 
     95     std::vector<typename StringType::value_type> mem_buf(mem_length);
     96 
     97     // NOTE: You can only use a va_list once.  Since we're in a while loop, we
     98     // need to make a new copy each time so we don't use up the original.
     99     GG_VA_COPY(ap_copy, ap);
    100     result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
    101     va_end(ap_copy);
    102 
    103     if ((result >= 0) && (result < mem_length)) {
    104       // It fit.
    105       dst->append(&mem_buf[0], result);
    106       return;
    107     }
    108   }
    109 }
    110 
    111 }  // namespace
    112 
    113 std::string StringPrintf(const char* format, ...) {
    114   va_list ap;
    115   va_start(ap, format);
    116   std::string result;
    117   StringAppendV(&result, format, ap);
    118   va_end(ap);
    119   return result;
    120 }
    121 
    122 #if !defined(OS_ANDROID)
    123 std::wstring StringPrintf(const wchar_t* format, ...) {
    124   va_list ap;
    125   va_start(ap, format);
    126   std::wstring result;
    127   StringAppendV(&result, format, ap);
    128   va_end(ap);
    129   return result;
    130 }
    131 #endif
    132 
    133 std::string StringPrintV(const char* format, va_list ap) {
    134   std::string result;
    135   StringAppendV(&result, format, ap);
    136   return result;
    137 }
    138 
    139 const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
    140   va_list ap;
    141   va_start(ap, format);
    142   dst->clear();
    143   StringAppendV(dst, format, ap);
    144   va_end(ap);
    145   return *dst;
    146 }
    147 
    148 #if !defined(OS_ANDROID)
    149 const std::wstring& SStringPrintf(std::wstring* dst,
    150                                   const wchar_t* format, ...) {
    151   va_list ap;
    152   va_start(ap, format);
    153   dst->clear();
    154   StringAppendV(dst, format, ap);
    155   va_end(ap);
    156   return *dst;
    157 }
    158 #endif
    159 
    160 void StringAppendF(std::string* dst, const char* format, ...) {
    161   va_list ap;
    162   va_start(ap, format);
    163   StringAppendV(dst, format, ap);
    164   va_end(ap);
    165 }
    166 
    167 #if !defined(OS_ANDROID)
    168 void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
    169   va_list ap;
    170   va_start(ap, format);
    171   StringAppendV(dst, format, ap);
    172   va_end(ap);
    173 }
    174 #endif
    175 
    176 void StringAppendV(std::string* dst, const char* format, va_list ap) {
    177   StringAppendVT(dst, format, ap);
    178 }
    179 
    180 #if !defined(OS_ANDROID)
    181 void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
    182   StringAppendVT(dst, format, ap);
    183 }
    184 #endif
    185 
    186 }  // namespace base
    187