blob: 164e3cf86ab8389d4ad9966266daa779e36f86fd [file] [log] [blame]
Austin Schuh1eb16d12015-09-06 17:21:56 -07001// Copyright (c) 2011, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29// ---
30//
31// Some generically useful utility routines that in google-land would
32// be their own projects. We make a shortened version here.
33
34#ifndef GFLAGS_UTIL_H_
35#define GFLAGS_UTIL_H_
36
37#include "config.h"
38
39#include <assert.h>
Austin Schuh1eb16d12015-09-06 17:21:56 -070040#ifdef HAVE_INTTYPES_H
41# include <inttypes.h>
42#endif
43#include <stdarg.h> // for va_*
44#include <stdlib.h>
45#include <stdio.h>
46#include <iostream>
47#include <string>
48#include <errno.h>
49#ifdef HAVE_SYS_STAT_H
50# include <sys/stat.h> // for mkdir
51#endif
52
53
54namespace GFLAGS_NAMESPACE {
55
56
57// This is used for unittests for death-testing. It is defined in gflags.cc.
58extern GFLAGS_DLL_DECL void (*gflags_exitfunc)(int);
59
60// Work properly if either strtoll or strtoq is on this system.
61#if defined(strtoll) || defined(HAVE_STRTOLL)
62# define strto64 strtoll
63# define strtou64 strtoull
64#elif defined(HAVE_STRTOQ)
65# define strto64 strtoq
66# define strtou64 strtouq
67// Neither strtoll nor strtoq are defined. I hope strtol works!
68#else
69# define strto64 strtol
70# define strtou64 strtoul
71#endif
72
73// If we have inttypes.h, it will have defined PRId32/etc for us.
74// If not, take our best guess.
75#ifndef PRId32
76# define PRId32 "d"
77#endif
78#ifndef PRId64
79# define PRId64 "lld"
80#endif
81#ifndef PRIu64
82# define PRIu64 "llu"
83#endif
84
85typedef signed char int8;
86typedef unsigned char uint8;
87
88// -- utility macros ---------------------------------------------------------
89
Austin Schuh8fec4f42018-10-29 21:52:32 -070090template <bool b> struct CompileAssert;
91template <> struct CompileAssert<true> {};
Austin Schuh1eb16d12015-09-06 17:21:56 -070092#define COMPILE_ASSERT(expr, msg) \
Austin Schuh8fec4f42018-10-29 21:52:32 -070093 enum { assert_##msg = sizeof(CompileAssert<bool(expr)>) }
Austin Schuh1eb16d12015-09-06 17:21:56 -070094
95// Returns the number of elements in an array.
96#define arraysize(arr) (sizeof(arr)/sizeof(*(arr)))
97
98
99// -- logging and testing ---------------------------------------------------
100
101// For now, we ignore the level for logging, and don't show *VLOG's at
102// all, except by hand-editing the lines below
103#define LOG(level) std::cerr
104#define VLOG(level) if (true) {} else std::cerr
105#define DVLOG(level) if (true) {} else std::cerr
106
107// CHECK dies with a fatal error if condition is not true. It is *not*
108// controlled by NDEBUG, so the check will be executed regardless of
109// compilation mode. Therefore, it is safe to do things like:
110// CHECK(fp->Write(x) == 4)
111// We allow stream-like objects after this for debugging, but they're ignored.
112#define EXPECT_TRUE(condition) \
113 if (true) { \
114 if (!(condition)) { \
115 fprintf(stderr, "Check failed: %s\n", #condition); \
116 exit(1); \
117 } \
118 } else std::cerr << ""
119
120#define EXPECT_OP(op, val1, val2) \
121 if (true) { \
122 if (!((val1) op (val2))) { \
123 fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
124 exit(1); \
125 } \
126 } else std::cerr << ""
127
128#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
129#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
130#define EXPECT_LE(val1, val2) EXPECT_OP(<=, val1, val2)
131#define EXPECT_LT(val1, val2) EXPECT_OP(< , val1, val2)
132#define EXPECT_GE(val1, val2) EXPECT_OP(>=, val1, val2)
133#define EXPECT_GT(val1, val2) EXPECT_OP(> , val1, val2)
134#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
135
136// C99 declares isnan and isinf should be macros, so the #ifdef test
137// should be reliable everywhere. Of course, it's not, but these
138// are testing pertty marginal functionality anyway, so it's ok to
139// not-run them even in situations they might, with effort, be made to work.
140#ifdef isnan // Some compilers, like sun's for Solaris 10, don't define this
141#define EXPECT_NAN(arg) \
142 do { \
143 if (!isnan(arg)) { \
144 fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
145 exit(1); \
146 } \
147 } while (0)
148#else
149#define EXPECT_NAN(arg)
150#endif
151
152#ifdef isinf // Some compilers, like sun's for Solaris 10, don't define this
153#define EXPECT_INF(arg) \
154 do { \
155 if (!isinf(arg)) { \
156 fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
157 exit(1); \
158 } \
159 } while (0)
160#else
161#define EXPECT_INF(arg)
162#endif
163
164#define EXPECT_DOUBLE_EQ(val1, val2) \
165 do { \
166 if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
167 fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
168 exit(1); \
169 } \
170 } while (0)
171
172#define EXPECT_STREQ(val1, val2) \
173 do { \
174 if (strcmp((val1), (val2)) != 0) { \
175 fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
176 exit(1); \
177 } \
178 } while (0)
179
180// Call this in a .cc file where you will later call RUN_ALL_TESTS in main().
181#define TEST_INIT \
182 static std::vector<void (*)()> g_testlist; /* the tests to run */ \
183 static int RUN_ALL_TESTS() { \
184 std::vector<void (*)()>::const_iterator it; \
185 for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { \
186 (*it)(); /* The test will error-exit if there's a problem. */ \
187 } \
188 fprintf(stderr, "\nPassed %d tests\n\nPASS\n", \
189 static_cast<int>(g_testlist.size())); \
190 return 0; \
191 }
192
193// Note that this macro uses a FlagSaver to keep tests isolated.
194#define TEST(a, b) \
195 struct Test_##a##_##b { \
196 Test_##a##_##b() { g_testlist.push_back(&Run); } \
197 static void Run() { \
198 FlagSaver fs; \
199 fprintf(stderr, "Running test %s/%s\n", #a, #b); \
200 RunTest(); \
201 } \
202 static void RunTest(); \
203 }; \
204 static Test_##a##_##b g_test_##a##_##b; \
205 void Test_##a##_##b::RunTest()
206
207// This is a dummy class that eases the google->opensource transition.
208namespace testing {
209class Test {};
210}
211
212// Call this in a .cc file where you will later call EXPECT_DEATH
213#define EXPECT_DEATH_INIT \
214 static bool g_called_exit; \
215 static void CalledExit(int) { g_called_exit = true; }
216
217#define EXPECT_DEATH(fn, msg) \
218 do { \
219 g_called_exit = false; \
220 gflags_exitfunc = &CalledExit; \
221 fn; \
222 gflags_exitfunc = &exit; /* set back to its default */ \
223 if (!g_called_exit) { \
224 fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
225 exit(1); \
226 } \
227 } while (0)
228
229#define GTEST_HAS_DEATH_TEST 1
230
231// -- path routines ----------------------------------------------------------
232
233// Tries to create the directory path as a temp-dir. If it fails,
234// changes path to some directory it *can* create.
235#if defined(__MINGW32__)
236#include <io.h>
237inline void MakeTmpdir(std::string* path) {
238 if (!path->empty()) {
239 path->append("/gflags_unittest_testdir");
240 int err = mkdir(path->c_str());
241 if (err == 0 || errno == EEXIST) return;
242 }
243 // I had trouble creating a directory in /tmp from mingw
244 *path = "./gflags_unittest";
245 mkdir(path->c_str());
246}
247#elif defined(_MSC_VER)
248#include <direct.h>
249inline void MakeTmpdir(std::string* path) {
250 if (!path->empty()) {
251 int err = _mkdir(path->c_str());
252 if (err == 0 || errno == EEXIST) return;
253 }
254 char tmppath_buffer[1024];
255 int tmppath_len = GetTempPathA(sizeof(tmppath_buffer), tmppath_buffer);
256 assert(tmppath_len > 0 && tmppath_len < sizeof(tmppath_buffer));
257 assert(tmppath_buffer[tmppath_len - 1] == '\\'); // API guarantees it
258 *path = std::string(tmppath_buffer) + "gflags_unittest";
259 _mkdir(path->c_str());
260}
261#else
262inline void MakeTmpdir(std::string* path) {
263 if (!path->empty()) {
264 int err = mkdir(path->c_str(), 0755);
265 if (err == 0 || errno == EEXIST) return;
266 }
267 mkdir("/tmp/gflags_unittest", 0755);
268}
269#endif
270
271// -- string routines --------------------------------------------------------
272
273inline void InternalStringPrintf(std::string* output, const char* format,
274 va_list ap) {
275 char space[128]; // try a small buffer and hope it fits
276
277 // It's possible for methods that use a va_list to invalidate
278 // the data in it upon use. The fix is to make a copy
279 // of the structure before using it and use that copy instead.
280 va_list backup_ap;
281 va_copy(backup_ap, ap);
282 int bytes_written = vsnprintf(space, sizeof(space), format, backup_ap);
283 va_end(backup_ap);
284
285 if ((bytes_written >= 0) && (static_cast<size_t>(bytes_written) < sizeof(space))) {
286 output->append(space, bytes_written);
287 return;
288 }
289
290 // Repeatedly increase buffer size until it fits.
291 int length = sizeof(space);
292 while (true) {
293 if (bytes_written < 0) {
294 // Older snprintf() behavior. :-( Just try doubling the buffer size
295 length *= 2;
296 } else {
297 // We need exactly "bytes_written+1" characters
298 length = bytes_written+1;
299 }
300 char* buf = new char[length];
301
302 // Restore the va_list before we use it again
303 va_copy(backup_ap, ap);
304 bytes_written = vsnprintf(buf, length, format, backup_ap);
305 va_end(backup_ap);
306
307 if ((bytes_written >= 0) && (bytes_written < length)) {
308 output->append(buf, bytes_written);
309 delete[] buf;
310 return;
311 }
312 delete[] buf;
313 }
314}
315
316// Clears output before writing to it.
317inline void SStringPrintf(std::string* output, const char* format, ...) {
318 va_list ap;
319 va_start(ap, format);
320 output->clear();
321 InternalStringPrintf(output, format, ap);
322 va_end(ap);
323}
324
325inline void StringAppendF(std::string* output, const char* format, ...) {
326 va_list ap;
327 va_start(ap, format);
328 InternalStringPrintf(output, format, ap);
329 va_end(ap);
330}
331
332inline std::string StringPrintf(const char* format, ...) {
333 va_list ap;
334 va_start(ap, format);
335 std::string output;
336 InternalStringPrintf(&output, format, ap);
337 va_end(ap);
338 return output;
339}
340
341inline bool SafeGetEnv(const char *varname, std::string &valstr)
342{
343#if defined(_MSC_VER) && _MSC_VER >= 1400
344 char *val;
345 size_t sz;
346 if (_dupenv_s(&val, &sz, varname) != 0 || !val) return false;
347 valstr = val;
348 free(val);
349#else
350 const char * const val = getenv(varname);
351 if (!val) return false;
352 valstr = val;
353#endif
354 return true;
355}
356
357inline int SafeFOpen(FILE **fp, const char* fname, const char *mode)
358{
359#if defined(_MSC_VER) && _MSC_VER >= 1400
360 return fopen_s(fp, fname, mode);
361#else
362 assert(fp != NULL);
363 *fp = fopen(fname, mode);
364 // errno only guaranteed to be set on failure
365 return ((*fp == NULL) ? errno : 0);
366#endif
367}
368
369
370} // namespace GFLAGS_NAMESPACE
371
372
373#endif // GFLAGS_UTIL_H_