1// 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> 40#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 90template <bool b> struct CompileAssert; 91template <> struct CompileAssert<true> {}; 92#define COMPILE_ASSERT(expr, msg) \ 93 enum { assert_##msg = sizeof(CompileAssert<bool(expr)>) } 94 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_ 374