1/*
2 * Copyright 2014-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <folly/io/Cursor.h>
18
19#include <cstdio>
20
21#include <folly/ScopeGuard.h>
22
23namespace folly {
24namespace io {
25
26void Appender::printf(const char* fmt, ...) {
27 va_list ap;
28 va_start(ap, fmt);
29 vprintf(fmt, ap);
30 va_end(ap);
31}
32
33void Appender::vprintf(const char* fmt, va_list ap) {
34 // Make a copy of ap in case we need to retry.
35 // We use ap on the first attempt, so it always gets advanced
36 // passed the used arguments. We'll only use apCopy if we need to retry.
37 va_list apCopy;
38 va_copy(apCopy, ap);
39 SCOPE_EXIT {
40 va_end(apCopy);
41 };
42
43 // First try writing into our available data space.
44 int ret =
45 vsnprintf(reinterpret_cast<char*>(writableData()), length(), fmt, ap);
46 if (ret < 0) {
47 throw std::runtime_error("error formatting printf() data");
48 }
49 auto len = size_t(ret);
50 // vsnprintf() returns the number of characters that would be printed,
51 // not including the terminating nul.
52 if (len < length()) {
53 // All of the data was successfully written.
54 append(len);
55 return;
56 }
57
58 // There wasn't enough room for the data.
59 // Allocate more room, and then retry.
60 ensure(len + 1);
61 ret =
62 vsnprintf(reinterpret_cast<char*>(writableData()), length(), fmt, apCopy);
63 if (ret < 0) {
64 throw std::runtime_error("error formatting printf() data");
65 }
66 len = size_t(ret);
67 if (len >= length()) {
68 // This shouldn't ever happen.
69 throw std::runtime_error(
70 "unexpectedly out of buffer space on second "
71 "vsnprintf() attmept");
72 }
73 append(len);
74}
75} // namespace io
76} // namespace folly
77