OLD | NEW |
---|---|
(Empty) | |
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 "mojo/edk/util/string_printf.h" | |
6 | |
7 #include <assert.h> | |
8 #include <errno.h> | |
9 #include <stdarg.h> | |
10 #include <stddef.h> | |
11 #include <stdio.h> | |
12 | |
13 #include <memory> | |
14 | |
15 namespace mojo { | |
16 namespace util { | |
17 namespace { | |
18 | |
19 void StringVAppendfHelper(std::string* dest, const char* format, va_list ap) { | |
20 // Size of the small stack buffer to use try first. This should be kept in | |
vardhan
2015/12/01 19:09:26
remove "try" (or remove "use"?)
viettrungluu
2015/12/01 22:24:55
Done.
| |
21 // sync with the numbers in StringPrintfTest.StringPrintf_Boundary. | |
22 constexpr size_t kStackBufferSize = 1024u; | |
23 | |
24 // First, try with a small buffer on the stack. | |
25 char stack_buf[kStackBufferSize]; | |
26 // Copy |ap| (which can only be used once), in case we need to retry. | |
27 va_list ap_copy; | |
28 va_copy(ap_copy, ap); | |
29 int result = vsnprintf(stack_buf, kStackBufferSize, format, ap_copy); | |
30 va_end(ap_copy); | |
31 if (result < 0) { | |
32 // As far as I can tell, we'd only get |EOVERFLOW| if the result is so large | |
33 // that it can't be represented by an |int| (in which case retrying would be | |
34 // futile), so Chromium's implementation is wrong. | |
35 return; | |
36 } | |
37 // |result| should be the number of characters we need, not including the | |
38 // terminating null. However, |vsnprintf()| always null-terminates! | |
39 size_t output_size = static_cast<size_t>(result); | |
40 // Check if the output fit into our stack buffer. This is "<" not "<=", since | |
41 // |vsnprintf()| will null-terminate. | |
42 if (output_size < kStackBufferSize) { | |
43 // It fit. | |
44 dest->append(stack_buf, static_cast<size_t>(result)); | |
45 return; | |
46 } | |
47 | |
48 // Since we have the required output size, we can just heap allocate that. | |
49 // (Add 1 because |vsnprintf()| will always null-terminate.) | |
50 size_t heap_buf_size = output_size + 1u; | |
51 std::unique_ptr<char[]> heap_buf(new char[heap_buf_size]); | |
52 result = vsnprintf(heap_buf.get(), heap_buf_size, format, ap); | |
53 if (result < 0 || static_cast<size_t>(result) > output_size) { | |
54 assert(false); | |
55 return; | |
56 } | |
57 assert(static_cast<size_t>(result) == output_size); | |
58 dest->append(heap_buf.get(), static_cast<size_t>(result)); | |
59 } | |
60 | |
61 } // namespace | |
62 | |
63 std::string StringPrintf(const char* format, ...) { | |
64 va_list ap; | |
65 va_start(ap, format); | |
66 std::string rv; | |
67 StringVAppendf(&rv, format, ap); | |
68 va_end(ap); | |
69 return rv; | |
70 } | |
71 | |
72 std::string StringVPrintf(const char* format, va_list ap) { | |
73 std::string rv; | |
74 StringVAppendf(&rv, format, ap); | |
75 return rv; | |
76 } | |
77 | |
78 void StringAppendf(std::string* dest, const char* format, ...) { | |
79 va_list ap; | |
80 va_start(ap, format); | |
81 StringVAppendf(dest, format, ap); | |
82 va_end(ap); | |
83 } | |
84 | |
85 void StringVAppendf(std::string* dest, const char* format, va_list ap) { | |
86 int old_errno = errno; | |
87 StringVAppendfHelper(dest, format, ap); | |
88 errno = old_errno; | |
89 } | |
90 | |
91 } // namespace util | |
92 } // namespace mojo | |
OLD | NEW |