1 | // Copyright 2002 and onwards Google Inc. |
2 | |
3 | #include <stdarg.h> // For va_list and related operations |
4 | #include <stdio.h> // MSVC requires this for _vsnprintf |
5 | #include <vector> |
6 | using std::vector; |
7 | |
8 | #include "base/stringprintf.h" |
9 | #include "base/logging.h" |
10 | |
11 | void StringAppendV(string* dst, const char* format, va_list ap) { |
12 | // First try with a small fixed size buffer |
13 | char space[1024]; |
14 | |
15 | // It's possible for methods that use a va_list to invalidate |
16 | // the data in it upon use. The fix is to make a copy |
17 | // of the structure before using it and use that copy instead. |
18 | va_list backup_ap; |
19 | va_copy(backup_ap, ap); |
20 | int result = vsnprintf(space, sizeof(space), format, backup_ap); |
21 | va_end(backup_ap); |
22 | |
23 | if ((result >= 0) && (result < sizeof(space))) { |
24 | // It fit |
25 | dst->append(space, result); |
26 | return; |
27 | } |
28 | |
29 | // Repeatedly increase buffer size until it fits |
30 | int length = sizeof(space); |
31 | while (true) { |
32 | if (result < 0) { |
33 | // Older behavior: just try doubling the buffer size |
34 | length *= 2; |
35 | } else { |
36 | // We need exactly "result+1" characters |
37 | length = result+1; |
38 | } |
39 | char* buf = new char[length]; |
40 | |
41 | // Restore the va_list before we use it again |
42 | va_copy(backup_ap, ap); |
43 | result = vsnprintf(buf, length, format, backup_ap); |
44 | va_end(backup_ap); |
45 | |
46 | if ((result >= 0) && (result < length)) { |
47 | // It fit |
48 | dst->append(buf, result); |
49 | delete[] buf; |
50 | return; |
51 | } |
52 | delete[] buf; |
53 | } |
54 | } |
55 | |
56 | string StringPrintf(const char* format, ...) { |
57 | va_list ap; |
58 | va_start(ap, format); |
59 | string result; |
60 | StringAppendV(&result, format, ap); |
61 | va_end(ap); |
62 | return result; |
63 | } |
64 | |
65 | const string& SStringPrintf(string* dst, const char* format, ...) { |
66 | va_list ap; |
67 | va_start(ap, format); |
68 | dst->clear(); |
69 | StringAppendV(dst, format, ap); |
70 | va_end(ap); |
71 | return *dst; |
72 | } |
73 | |
74 | void StringAppendF(string* dst, const char* format, ...) { |
75 | va_list ap; |
76 | va_start(ap, format); |
77 | StringAppendV(dst, format, ap); |
78 | va_end(ap); |
79 | } |
80 | |