374 lines
14 KiB
C
374 lines
14 KiB
C
|
// Copyright (c) 2011, Google Inc.
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// Redistribution and use in source and binary forms, with or without
|
||
|
// modification, are permitted provided that the following conditions are
|
||
|
// met:
|
||
|
//
|
||
|
// * Redistributions of source code must retain the above copyright
|
||
|
// notice, this list of conditions and the following disclaimer.
|
||
|
// * Redistributions in binary form must reproduce the above
|
||
|
// copyright notice, this list of conditions and the following disclaimer
|
||
|
// in the documentation and/or other materials provided with the
|
||
|
// distribution.
|
||
|
// * Neither the name of Google Inc. nor the names of its
|
||
|
// contributors may be used to endorse or promote products derived from
|
||
|
// this software without specific prior written permission.
|
||
|
//
|
||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
// ---
|
||
|
//
|
||
|
// Some generically useful utility routines that in google-land would
|
||
|
// be their own projects. We make a shortened version here.
|
||
|
|
||
|
#ifndef GFLAGS_UTIL_H_
|
||
|
#define GFLAGS_UTIL_H_
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <assert.h>
|
||
|
#ifdef HAVE_INTTYPES_H
|
||
|
# include <inttypes.h>
|
||
|
#endif
|
||
|
#include <stdarg.h> // for va_*
|
||
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <iostream>
|
||
|
#include <string>
|
||
|
#include <errno.h>
|
||
|
#ifdef HAVE_SYS_STAT_H
|
||
|
# include <sys/stat.h> // for mkdir
|
||
|
#endif
|
||
|
|
||
|
|
||
|
namespace GFLAGS_NAMESPACE {
|
||
|
|
||
|
|
||
|
// This is used for unittests for death-testing. It is defined in gflags.cc.
|
||
|
extern GFLAGS_DLL_DECL void (*gflags_exitfunc)(int);
|
||
|
|
||
|
// Work properly if either strtoll or strtoq is on this system.
|
||
|
#if defined(strtoll) || defined(HAVE_STRTOLL)
|
||
|
# define strto64 strtoll
|
||
|
# define strtou64 strtoull
|
||
|
#elif defined(HAVE_STRTOQ)
|
||
|
# define strto64 strtoq
|
||
|
# define strtou64 strtouq
|
||
|
// Neither strtoll nor strtoq are defined. I hope strtol works!
|
||
|
#else
|
||
|
# define strto64 strtol
|
||
|
# define strtou64 strtoul
|
||
|
#endif
|
||
|
|
||
|
// If we have inttypes.h, it will have defined PRId32/etc for us.
|
||
|
// If not, take our best guess.
|
||
|
#ifndef PRId32
|
||
|
# define PRId32 "d"
|
||
|
#endif
|
||
|
#ifndef PRId64
|
||
|
# define PRId64 "lld"
|
||
|
#endif
|
||
|
#ifndef PRIu64
|
||
|
# define PRIu64 "llu"
|
||
|
#endif
|
||
|
|
||
|
typedef signed char int8;
|
||
|
typedef unsigned char uint8;
|
||
|
|
||
|
// -- utility macros ---------------------------------------------------------
|
||
|
|
||
|
template <bool b> struct CompileAssert;
|
||
|
template <> struct CompileAssert<true> {};
|
||
|
#define COMPILE_ASSERT(expr, msg) \
|
||
|
enum { assert_##msg = sizeof(CompileAssert<bool(expr)>) }
|
||
|
|
||
|
// Returns the number of elements in an array.
|
||
|
#define arraysize(arr) (sizeof(arr)/sizeof(*(arr)))
|
||
|
|
||
|
|
||
|
// -- logging and testing ---------------------------------------------------
|
||
|
|
||
|
// For now, we ignore the level for logging, and don't show *VLOG's at
|
||
|
// all, except by hand-editing the lines below
|
||
|
#define LOG(level) std::cerr
|
||
|
#define VLOG(level) if (true) {} else std::cerr
|
||
|
#define DVLOG(level) if (true) {} else std::cerr
|
||
|
|
||
|
// CHECK dies with a fatal error if condition is not true. It is *not*
|
||
|
// controlled by NDEBUG, so the check will be executed regardless of
|
||
|
// compilation mode. Therefore, it is safe to do things like:
|
||
|
// CHECK(fp->Write(x) == 4)
|
||
|
// We allow stream-like objects after this for debugging, but they're ignored.
|
||
|
#define EXPECT_TRUE(condition) \
|
||
|
if (true) { \
|
||
|
if (!(condition)) { \
|
||
|
fprintf(stderr, "Check failed: %s\n", #condition); \
|
||
|
exit(1); \
|
||
|
} \
|
||
|
} else std::cerr << ""
|
||
|
|
||
|
#define EXPECT_OP(op, val1, val2) \
|
||
|
if (true) { \
|
||
|
if (!((val1) op (val2))) { \
|
||
|
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
|
||
|
exit(1); \
|
||
|
} \
|
||
|
} else std::cerr << ""
|
||
|
|
||
|
#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
|
||
|
#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
|
||
|
#define EXPECT_LE(val1, val2) EXPECT_OP(<=, val1, val2)
|
||
|
#define EXPECT_LT(val1, val2) EXPECT_OP(< , val1, val2)
|
||
|
#define EXPECT_GE(val1, val2) EXPECT_OP(>=, val1, val2)
|
||
|
#define EXPECT_GT(val1, val2) EXPECT_OP(> , val1, val2)
|
||
|
#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
|
||
|
|
||
|
// C99 declares isnan and isinf should be macros, so the #ifdef test
|
||
|
// should be reliable everywhere. Of course, it's not, but these
|
||
|
// are testing pertty marginal functionality anyway, so it's ok to
|
||
|
// not-run them even in situations they might, with effort, be made to work.
|
||
|
#ifdef isnan // Some compilers, like sun's for Solaris 10, don't define this
|
||
|
#define EXPECT_NAN(arg) \
|
||
|
do { \
|
||
|
if (!isnan(arg)) { \
|
||
|
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
|
||
|
exit(1); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
#else
|
||
|
#define EXPECT_NAN(arg)
|
||
|
#endif
|
||
|
|
||
|
#ifdef isinf // Some compilers, like sun's for Solaris 10, don't define this
|
||
|
#define EXPECT_INF(arg) \
|
||
|
do { \
|
||
|
if (!isinf(arg)) { \
|
||
|
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
|
||
|
exit(1); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
#else
|
||
|
#define EXPECT_INF(arg)
|
||
|
#endif
|
||
|
|
||
|
#define EXPECT_DOUBLE_EQ(val1, val2) \
|
||
|
do { \
|
||
|
if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
|
||
|
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
|
||
|
exit(1); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
#define EXPECT_STREQ(val1, val2) \
|
||
|
do { \
|
||
|
if (strcmp((val1), (val2)) != 0) { \
|
||
|
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
|
||
|
exit(1); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
// Call this in a .cc file where you will later call RUN_ALL_TESTS in main().
|
||
|
#define TEST_INIT \
|
||
|
static std::vector<void (*)()> g_testlist; /* the tests to run */ \
|
||
|
static int RUN_ALL_TESTS() { \
|
||
|
std::vector<void (*)()>::const_iterator it; \
|
||
|
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { \
|
||
|
(*it)(); /* The test will error-exit if there's a problem. */ \
|
||
|
} \
|
||
|
fprintf(stderr, "\nPassed %d tests\n\nPASS\n", \
|
||
|
static_cast<int>(g_testlist.size())); \
|
||
|
return 0; \
|
||
|
}
|
||
|
|
||
|
// Note that this macro uses a FlagSaver to keep tests isolated.
|
||
|
#define TEST(a, b) \
|
||
|
struct Test_##a##_##b { \
|
||
|
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
||
|
static void Run() { \
|
||
|
FlagSaver fs; \
|
||
|
fprintf(stderr, "Running test %s/%s\n", #a, #b); \
|
||
|
RunTest(); \
|
||
|
} \
|
||
|
static void RunTest(); \
|
||
|
}; \
|
||
|
static Test_##a##_##b g_test_##a##_##b; \
|
||
|
void Test_##a##_##b::RunTest()
|
||
|
|
||
|
// This is a dummy class that eases the google->opensource transition.
|
||
|
namespace testing {
|
||
|
class Test {};
|
||
|
}
|
||
|
|
||
|
// Call this in a .cc file where you will later call EXPECT_DEATH
|
||
|
#define EXPECT_DEATH_INIT \
|
||
|
static bool g_called_exit; \
|
||
|
static void CalledExit(int) { g_called_exit = true; }
|
||
|
|
||
|
#define EXPECT_DEATH(fn, msg) \
|
||
|
do { \
|
||
|
g_called_exit = false; \
|
||
|
gflags_exitfunc = &CalledExit; \
|
||
|
fn; \
|
||
|
gflags_exitfunc = &exit; /* set back to its default */ \
|
||
|
if (!g_called_exit) { \
|
||
|
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
|
||
|
exit(1); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
#define GTEST_HAS_DEATH_TEST 1
|
||
|
|
||
|
// -- path routines ----------------------------------------------------------
|
||
|
|
||
|
// Tries to create the directory path as a temp-dir. If it fails,
|
||
|
// changes path to some directory it *can* create.
|
||
|
#if defined(__MINGW32__)
|
||
|
#include <io.h>
|
||
|
inline void MakeTmpdir(std::string* path) {
|
||
|
if (!path->empty()) {
|
||
|
path->append("/gflags_unittest_testdir");
|
||
|
int err = mkdir(path->c_str());
|
||
|
if (err == 0 || errno == EEXIST) return;
|
||
|
}
|
||
|
// I had trouble creating a directory in /tmp from mingw
|
||
|
*path = "./gflags_unittest";
|
||
|
mkdir(path->c_str());
|
||
|
}
|
||
|
#elif defined(_MSC_VER)
|
||
|
#include <direct.h>
|
||
|
inline void MakeTmpdir(std::string* path) {
|
||
|
if (!path->empty()) {
|
||
|
int err = _mkdir(path->c_str());
|
||
|
if (err == 0 || errno == EEXIST) return;
|
||
|
}
|
||
|
char tmppath_buffer[1024];
|
||
|
int tmppath_len = GetTempPathA(sizeof(tmppath_buffer), tmppath_buffer);
|
||
|
assert(tmppath_len > 0 && tmppath_len < sizeof(tmppath_buffer));
|
||
|
assert(tmppath_buffer[tmppath_len - 1] == '\\'); // API guarantees it
|
||
|
*path = std::string(tmppath_buffer) + "gflags_unittest";
|
||
|
_mkdir(path->c_str());
|
||
|
}
|
||
|
#else
|
||
|
inline void MakeTmpdir(std::string* path) {
|
||
|
if (!path->empty()) {
|
||
|
int err = mkdir(path->c_str(), 0755);
|
||
|
if (err == 0 || errno == EEXIST) return;
|
||
|
}
|
||
|
mkdir("/tmp/gflags_unittest", 0755);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// -- string routines --------------------------------------------------------
|
||
|
|
||
|
inline void InternalStringPrintf(std::string* output, const char* format,
|
||
|
va_list ap) {
|
||
|
char space[128]; // try a small buffer and hope it fits
|
||
|
|
||
|
// It's possible for methods that use a va_list to invalidate
|
||
|
// the data in it upon use. The fix is to make a copy
|
||
|
// of the structure before using it and use that copy instead.
|
||
|
va_list backup_ap;
|
||
|
va_copy(backup_ap, ap);
|
||
|
int bytes_written = vsnprintf(space, sizeof(space), format, backup_ap);
|
||
|
va_end(backup_ap);
|
||
|
|
||
|
if ((bytes_written >= 0) && (static_cast<size_t>(bytes_written) < sizeof(space))) {
|
||
|
output->append(space, bytes_written);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Repeatedly increase buffer size until it fits.
|
||
|
int length = sizeof(space);
|
||
|
while (true) {
|
||
|
if (bytes_written < 0) {
|
||
|
// Older snprintf() behavior. :-( Just try doubling the buffer size
|
||
|
length *= 2;
|
||
|
} else {
|
||
|
// We need exactly "bytes_written+1" characters
|
||
|
length = bytes_written+1;
|
||
|
}
|
||
|
char* buf = new char[length];
|
||
|
|
||
|
// Restore the va_list before we use it again
|
||
|
va_copy(backup_ap, ap);
|
||
|
bytes_written = vsnprintf(buf, length, format, backup_ap);
|
||
|
va_end(backup_ap);
|
||
|
|
||
|
if ((bytes_written >= 0) && (bytes_written < length)) {
|
||
|
output->append(buf, bytes_written);
|
||
|
delete[] buf;
|
||
|
return;
|
||
|
}
|
||
|
delete[] buf;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Clears output before writing to it.
|
||
|
inline void SStringPrintf(std::string* output, const char* format, ...) {
|
||
|
va_list ap;
|
||
|
va_start(ap, format);
|
||
|
output->clear();
|
||
|
InternalStringPrintf(output, format, ap);
|
||
|
va_end(ap);
|
||
|
}
|
||
|
|
||
|
inline void StringAppendF(std::string* output, const char* format, ...) {
|
||
|
va_list ap;
|
||
|
va_start(ap, format);
|
||
|
InternalStringPrintf(output, format, ap);
|
||
|
va_end(ap);
|
||
|
}
|
||
|
|
||
|
inline std::string StringPrintf(const char* format, ...) {
|
||
|
va_list ap;
|
||
|
va_start(ap, format);
|
||
|
std::string output;
|
||
|
InternalStringPrintf(&output, format, ap);
|
||
|
va_end(ap);
|
||
|
return output;
|
||
|
}
|
||
|
|
||
|
inline bool SafeGetEnv(const char *varname, std::string &valstr)
|
||
|
{
|
||
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||
|
char *val;
|
||
|
size_t sz;
|
||
|
if (_dupenv_s(&val, &sz, varname) != 0 || !val) return false;
|
||
|
valstr = val;
|
||
|
free(val);
|
||
|
#else
|
||
|
const char * const val = getenv(varname);
|
||
|
if (!val) return false;
|
||
|
valstr = val;
|
||
|
#endif
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
inline int SafeFOpen(FILE **fp, const char* fname, const char *mode)
|
||
|
{
|
||
|
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||
|
return fopen_s(fp, fname, mode);
|
||
|
#else
|
||
|
assert(fp != NULL);
|
||
|
*fp = fopen(fname, mode);
|
||
|
// errno only guaranteed to be set on failure
|
||
|
return ((*fp == NULL) ? errno : 0);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
} // namespace GFLAGS_NAMESPACE
|
||
|
|
||
|
|
||
|
#endif // GFLAGS_UTIL_H_
|