blob: b3b7474d8f864b07076b4a27347055ae0039e157 [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
2// Copyright 2015 Google Inc. All rights reserved.
3// http://ceres-solver.org/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors may be
14// used to endorse or promote products derived from this software without
15// specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27// POSSIBILITY OF SUCH DAMAGE.
28//
29// Author: Sanjay Ghemawat
30
31#include "ceres/stringprintf.h"
32
33#include <cerrno>
34#include <cstdarg> // For va_list and related operations
35#include <cstdio> // MSVC requires this for _vsnprintf
36#include <string>
37#include <vector>
38
39#include "ceres/internal/port.h"
40
41namespace ceres {
42namespace internal {
43
44using std::string;
45
46// va_copy() was defined in the C99 standard. However, it did not appear in the
47// C++ standard until C++11. This means that if Ceres is being compiled with a
48// strict pre-C++11 standard (e.g. -std=c++03), va_copy() will NOT be defined,
49// as we are using the C++ compiler (it would however be defined if we were
50// using the C compiler). Note however that both GCC & Clang will in fact
51// define va_copy() when compiling for C++ if the C++ standard is not explicitly
52// specified (i.e. no -std=c++<XX> arg), even though it should not strictly be
53// defined unless -std=c++11 (or greater) was passed.
54#if !defined(va_copy)
55#if defined (__GNUC__)
56// On GCC/Clang, if va_copy() is not defined (C++ standard < C++11 explicitly
57// specified), use the internal __va_copy() version, which should be present
58// in even very old GCC versions.
59#define va_copy(d, s) __va_copy(d, s)
60#else
61// Some older versions of MSVC do not have va_copy(), in which case define it.
62// Although this is required for older MSVC versions, it should also work for
63// other non-GCC/Clang compilers which also do not defined va_copy().
64#define va_copy(d, s) ((d) = (s))
65#endif // defined (__GNUC__)
66#endif // !defined(va_copy)
67
68void StringAppendV(string* dst, const char* format, va_list ap) {
69 // First try with a small fixed size buffer
70 char space[1024];
71
72 // It's possible for methods that use a va_list to invalidate
73 // the data in it upon use. The fix is to make a copy
74 // of the structure before using it and use that copy instead.
75 va_list backup_ap;
76 va_copy(backup_ap, ap);
77 int result = vsnprintf(space, sizeof(space), format, backup_ap);
78 va_end(backup_ap);
79
80 if (result < sizeof(space)) {
81 if (result >= 0) {
82 // Normal case -- everything fit.
83 dst->append(space, result);
84 return;
85 }
86
87#if defined (_MSC_VER)
88 // Error or MSVC running out of space. MSVC 8.0 and higher
89 // can be asked about space needed with the special idiom below:
90 va_copy(backup_ap, ap);
91 result = vsnprintf(NULL, 0, format, backup_ap);
92 va_end(backup_ap);
93#endif
94
95 if (result < 0) {
96 // Just an error.
97 return;
98 }
99 }
100
101 // Increase the buffer size to the size requested by vsnprintf,
102 // plus one for the closing \0.
103 int length = result+1;
104 char* buf = new char[length];
105
106 // Restore the va_list before we use it again
107 va_copy(backup_ap, ap);
108 result = vsnprintf(buf, length, format, backup_ap);
109 va_end(backup_ap);
110
111 if (result >= 0 && result < length) {
112 // It fit
113 dst->append(buf, result);
114 }
115 delete[] buf;
116}
117
118
119string StringPrintf(const char* format, ...) {
120 va_list ap;
121 va_start(ap, format);
122 string result;
123 StringAppendV(&result, format, ap);
124 va_end(ap);
125 return result;
126}
127
128const string& SStringPrintf(string* dst, const char* format, ...) {
129 va_list ap;
130 va_start(ap, format);
131 dst->clear();
132 StringAppendV(dst, format, ap);
133 va_end(ap);
134 return *dst;
135}
136
137void StringAppendF(string* dst, const char* format, ...) {
138 va_list ap;
139 va_start(ap, format);
140 StringAppendV(dst, format, ap);
141 va_end(ap);
142}
143
144} // namespace internal
145} // namespace ceres