• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
StringFormatRaw(const char * format,...)19 std::string StringFormatRaw(const char* format, ...) {
20     va_list args;
21     va_start(args, format);
22     auto result = StringFormatWithArgs(format, args);
23     va_end(args);
24     return result;
25 }
26 
StringFormatWithArgs(const char * format,va_list args)27 std::string StringFormatWithArgs(const char* format, va_list args) {
28     std::string result;
29     StringAppendFormatWithArgs(&result, format, args);
30     return result;
31 }
32 
StringAppendFormatRaw(std::string * string,const char * format,...)33 void StringAppendFormatRaw(std::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 
StringAppendFormatWithArgs(std::string * string,const char * format,va_list args)40 void StringAppendFormatWithArgs(std::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 }  // namespace base
81 }  // namespace android
82