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 54 namespace GFLAGS_NAMESPACE { 55 56 57 // This is used for unittests for death-testing. It is defined in gflags.cc. 58 extern 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 85 typedef signed char int8; 86 typedef unsigned char uint8; 87 88 // -- utility macros --------------------------------------------------------- 89 90 template <bool b> struct CompileAssert; 91 template <> 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. 208 namespace testing { 209 class 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> 237 inline 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> 249 inline 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 262 inline 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 273 inline 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. 317 inline 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 325 inline 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 332 inline 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 341 inline 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 357 inline 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