Home | History | Annotate | Download | only in base
      1 // Copyright 2014 The Android Open Source Project
      2 //
      3 // This software is licensed under the terms of the GNU General Public
      4 // License version 2, as published by the Free Software Foundation, and
      5 // may be copied, distributed, and modified under those terms.
      6 //
      7 // This program is distributed in the hope that it will be useful,
      8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 // GNU General Public License for more details.
     11 
     12 #include "android/base/StringFormat.h"
     13 
     14 #include <stdio.h>
     15 
     16 namespace android {
     17 namespace base {
     18 
     19 String StringFormat(const char* format, ...) {
     20     va_list args;
     21     va_start(args, format);
     22     String result = StringFormatWithArgs(format, args);
     23     va_end(args);
     24     return result;
     25 }
     26 
     27 String StringFormatWithArgs(const char* format, va_list args) {
     28     String result;
     29     StringAppendFormatWithArgs(&result, format, args);
     30     return result;
     31 }
     32 
     33 void StringAppendFormat(String* string, const char* format, ...) {
     34     va_list args;
     35     va_start(args, format);
     36     StringAppendFormatWithArgs(string, format, args);
     37     va_end(args);
     38 }
     39 
     40 void StringAppendFormatWithArgs(String* string,
     41                                 const char* format,
     42                                 va_list args) {
     43     size_t cur_size = string->size();
     44     size_t extra = 0;
     45     for (;;) {
     46         va_list args2;
     47         va_copy(args2, args);
     48         int ret = vsnprintf(&(*string)[cur_size], extra, format, args2);
     49         va_end(args2);
     50 
     51         if (ret == 0) {
     52             // Nothing to do here.
     53             break;
     54         }
     55 
     56         if (ret > 0) {
     57             size_t ret_sz = static_cast<size_t>(ret);
     58             if (extra == 0) {
     59                 // First pass, resize the string and try again.
     60                 extra = ret_sz + 1;
     61                 string->resize(cur_size + extra);
     62                 continue;
     63             }
     64             if (ret_sz < extra) {
     65                 // Second pass or later, success!
     66                 string->resize(cur_size + ret_sz);
     67                 return;
     68             }
     69         }
     70 
     71         // NOTE: The MSVCRT.DLL implementation of snprintf() is broken and
     72         // will return -1 in case of truncation. This code path is taken
     73         // when this happens, or when |ret_sz| is equal or larger than
     74         // |extra|. Grow the buffer to allow for more room, then try again.
     75         extra += (extra >> 1) + 32;
     76         string->resize(cur_size + extra);
     77     }
     78 }
     79 
     80 
     81 }  // namespace base
     82 }  // namespace android
     83