pax_global_header00006660000000000000000000000064125043072350014513gustar00rootroot0000000000000052 comment=1a02f2851ee3d48d32d2c8f4d8f390a0bc25565c gflags-2.1.2/000077500000000000000000000000001250430723500127605ustar00rootroot00000000000000gflags-2.1.2/.gitattributes000066400000000000000000000001611250430723500156510ustar00rootroot00000000000000# treat all files in this repository as text files # and normalize them to LF line endings when committed * text gflags-2.1.2/.gitignore000066400000000000000000000004231250430723500147470ustar00rootroot00000000000000.DS_Store CMakeCache.txt DartConfiguration.tcl Makefile CMakeFiles/ /Testing/ /include/gflags/config.h /include/gflags/gflags_completions.h /include/gflags/gflags_declare.h /include/gflags/gflags.h /lib/ /test/gflags_unittest_main.cc /test/gflags_unittest-main.cc /packages/ gflags-2.1.2/AUTHORS.txt000066400000000000000000000000401250430723500146400ustar00rootroot00000000000000google-gflags@googlegroups.com gflags-2.1.2/CMakeLists.txt000066400000000000000000000465761250430723500155420ustar00rootroot00000000000000cmake_minimum_required (VERSION 2.8.4 FATAL_ERROR) if (POLICY CMP0042) cmake_policy (SET CMP0042 NEW) endif () # ---------------------------------------------------------------------------- # includes set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include (utils) # ---------------------------------------------------------------------------- # package information set (PACKAGE_NAME "gflags") set (PACKAGE_VERSION "2.1.2") set (PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set (PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set (PACKAGE_BUGREPORT "https://github.com/schuhschuh/gflags/issues") project (${PACKAGE_NAME} CXX) if (CMAKE_VERSION VERSION_LESS 100) # C language still needed because the following required CMake modules # (or their dependencies, respectively) are not correctly handling # the case where only CXX is enabled. # - CheckTypeSize.cmake (fixed in CMake 3.1, cf. http://www.cmake.org/Bug/view.php?id=14056) # - FindThreads.cmake (--> CheckIncludeFiles.cmake <--) enable_language (C) endif () version_numbers ( ${PACKAGE_VERSION} PACKAGE_VERSION_MAJOR PACKAGE_VERSION_MINOR PACKAGE_VERSION_PATCH ) set (PACKAGE_SOVERSION "${PACKAGE_VERSION_MAJOR}") # ---------------------------------------------------------------------------- # options if (NOT GFLAGS_NAMESPACE) # maintain binary backwards compatibility with gflags library version <= 2.0, # but at the same time enable the use of the preferred new "gflags" namespace set (GFLAGS_NAMESPACE "google;${PACKAGE_NAME}" CACHE STRING "Name(s) of library namespace (separate multiple options by semicolon)") mark_as_advanced (GFLAGS_NAMESPACE) endif () set (GFLAGS_NAMESPACE_SECONDARY "${GFLAGS_NAMESPACE}") list (REMOVE_DUPLICATES GFLAGS_NAMESPACE_SECONDARY) if (NOT GFLAGS_NAMESPACE_SECONDARY) message (FATAL_ERROR "GFLAGS_NAMESPACE must be set to one (or more) valid C++ namespace identifier(s separated by semicolon \";\").") endif () foreach (ns IN LISTS GFLAGS_NAMESPACE_SECONDARY) if (NOT ns MATCHES "^[a-zA-Z][a-zA-Z0-9_]*$") message (FATAL_ERROR "GFLAGS_NAMESPACE contains invalid namespace identifier: ${ns}") endif () endforeach () list (GET GFLAGS_NAMESPACE_SECONDARY 0 GFLAGS_NAMESPACE) list (REMOVE_AT GFLAGS_NAMESPACE_SECONDARY 0) option (BUILD_SHARED_LIBS "Request build of shared libraries." OFF) option (BUILD_STATIC_LIBS "Request build of static libraries (default if BUILD_SHARED_LIBS is OFF)." OFF) option (BUILD_gflags_LIB "Request build of the multi-threaded gflags library." ON) option (BUILD_gflags_nothreads_LIB "Request build of the single-threaded gflags library." ON) option (BUILD_PACKAGING "Enable build of distribution packages using CPack." OFF) option (BUILD_TESTING "Enable build of the unit tests and their execution using CTest." OFF) option (BUILD_NC_TESTS "Request addition of negative compilation tests." OFF) option (INSTALL_HEADERS "Request packaging of headers and other development files." ON) mark_as_advanced (CLEAR CMAKE_INSTALL_PREFIX) mark_as_advanced (CMAKE_CONFIGURATION_TYPES BUILD_STATIC_LIBS BUILD_NC_TESTS INSTALL_HEADERS) if (APPLE) mark_as_advanced(CMAKE_OSX_ARCHITECTURES CMAKE_OSX_DEPLOYMENT_TARGET CMAKE_OSX_SYSROOT) endif () if (NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS) set (BUILD_STATIC_LIBS ON) endif () if (NOT BUILD_gflags_LIB AND NOT BUILD_gflags_nothreads_LIB) message (FATAL_ERROR "At least one of BUILD_gflags_LIB and BUILD_gflags_nothreads_LIB must be ON.") endif () if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CXX_FLAGS) set_property (CACHE CMAKE_BUILD_TYPE PROPERTY VALUE Release) endif () if (NOT GFLAGS_INCLUDE_DIR) set (GFLAGS_INCLUDE_DIR "${PACKAGE_NAME}" CACHE STRING "Name of include directory of installed header files") mark_as_advanced (GFLAGS_INCLUDE_DIR) else () if (IS_ABSOLUTE GFLAGS_INCLUDE_DIR) message (FATAL_ERROR "GFLAGS_INCLUDE_DIR must be a path relative to CMAKE_INSTALL_PREFIX/include") endif () if (GFLAGS_INCLUDE_DIR MATCHES "^\\.\\.[/\\]") message (FATAL_ERROR "GFLAGS_INCLUDE_DIR must not start with parent directory reference (../)") endif () endif () # ---------------------------------------------------------------------------- # system checks include (CheckTypeSize) include (CheckIncludeFileCXX) include (CheckCXXSymbolExists) if (WIN32 AND NOT CYGWIN) set (OS_WINDOWS 1) else () set (OS_WINDOWS 0) endif () if (MSVC) set (HAVE_SYS_TYPES_H 1) set (HAVE_STDINT_H 1) set (HAVE_STDDEF_H 1) # used by CheckTypeSize module set (HAVE_INTTYPES_H 0) set (HAVE_UNISTD_H 0) set (HAVE_SYS_STAT_H 1) set (HAVE_SHLWAPI_H 1) else () foreach (fname IN ITEMS unistd stdint inttypes sys/types sys/stat fnmatch) string (TOUPPER "${fname}" FNAME) string (REPLACE "/" "_" FNAME "${FNAME}") if (NOT HAVE_${FNAME}_H) check_include_file_cxx ("${fname}.h" HAVE_${FNAME}_H) endif () endforeach () # the following are used in #if directives not #ifdef bool_to_int (HAVE_STDINT_H) bool_to_int (HAVE_SYS_TYPES_H) bool_to_int (HAVE_INTTYPES_H) if (NOT HAVE_FNMATCH_H AND OS_WINDOWS) check_include_file_cxx ("shlwapi.h" HAVE_SHLWAPI_H) endif () endif () set (GFLAGS_INTTYPES_FORMAT "" CACHE STRING "Format of integer types: \"C99\" (uint32_t), \"BSD\" (u_int32_t), \"VC7\" (__int32)") set_property (CACHE GFLAGS_INTTYPES_FORMAT PROPERTY STRINGS "C99;BSD;VC7") mark_as_advanced (GFLAGS_INTTYPES_FORMAT) if (NOT GFLAGS_INTTYPES_FORMAT) set (TYPES uint32_t u_int32_t) if (MSVC) list (INSERT TYPES 0 __int32) endif () foreach (type IN LISTS TYPES) check_type_size (${type} ${type} LANGUAGE CXX) if (HAVE_${type}) break () endif () endforeach () if (HAVE_uint32_t) set_property (CACHE GFLAGS_INTTYPES_FORMAT PROPERTY VALUE C99) elseif (HAVE_u_int32_t) set_property (CACHE GFLAGS_INTTYPES_FORMAT PROPERTY VALUE BSD) elseif (HAVE___int32) set_property (CACHE GFLAGS_INTTYPES_FORMAT PROPERTY VALUE VC7) else () mark_as_advanced (CLEAR GFLAGS_INTTYPES_FORMAT) message (FATAL_ERROR "Do not know how to define a 32-bit integer quantity on your system!" " Neither uint32_t, u_int32_t, nor __int32 seem to be available." " Set GFLAGS_INTTYPES_FORMAT to either C99, BSD, or VC7 and try again.") endif () endif () # use of special characters in strings to circumvent bug #0008226 if ("^${GFLAGS_INTTYPES_FORMAT}$" STREQUAL "^WIN$") set_property (CACHE GFLAGS_INTTYPES_FORMAT PROPERTY VALUE VC7) endif () if (NOT GFLAGS_INTTYPES_FORMAT MATCHES "^(C99|BSD|VC7)$") message (FATAL_ERROR "Invalid value for GFLAGS_INTTYPES_FORMAT! Choose one of \"C99\", \"BSD\", or \"VC7\"") endif () set (GFLAGS_INTTYPES_FORMAT_C99 0) set (GFLAGS_INTTYPES_FORMAT_BSD 0) set (GFLAGS_INTTYPES_FORMAT_VC7 0) set ("GFLAGS_INTTYPES_FORMAT_${GFLAGS_INTTYPES_FORMAT}" 1) if (MSVC) set (HAVE_strtoll 0) set (HAVE_strtoq 0) else () check_cxx_symbol_exists (strtoll stdlib.h HAVE_STRTOLL) if (NOT HAVE_STRTOLL) check_cxx_symbol_exists (strtoq stdlib.h HAVE_STRTOQ) endif () endif () set (CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package (Threads) if (Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) set (HAVE_PTHREAD 1) check_type_size (pthread_rwlock_t RWLOCK LANGUAGE CXX) else () set (HAVE_PTHREAD 0) endif () if (UNIX AND NOT HAVE_PTHREAD AND BUILD_gflags_LIB) if (CMAKE_HAVE_PTHREAD_H) set (what "library") else () set (what ".h file") endif () message (FATAL_ERROR "Could not find pthread${what}. Check the log file" "\n\t${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log" "\nor disable the build of the multi-threaded gflags library (BUILD_gflags_LIB=OFF).") endif () # ---------------------------------------------------------------------------- # source files - excluding root subdirectory and/or .in suffix set (PUBLIC_HDRS "gflags.h" "gflags_declare.h" "gflags_completions.h" ) if (GFLAGS_NAMESPACE_SECONDARY) set (INCLUDE_GFLAGS_NS_H "// Import gflags library symbols into alternative/deprecated namespace(s)") foreach (ns IN LISTS GFLAGS_NAMESPACE_SECONDARY) string (TOUPPER "${ns}" NS) set (gflags_ns_h "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/gflags_${ns}.h") configure_file ("${PROJECT_SOURCE_DIR}/src/gflags_ns.h.in" "${gflags_ns_h}" @ONLY) list (APPEND PUBLIC_HDRS "${gflags_ns_h}") set (INCLUDE_GFLAGS_NS_H "${INCLUDE_GFLAGS_NS_H}\n#include \"gflags_${ns}.h\"") endforeach () else () set (INCLUDE_GFLAGS_NS_H) endif () set (PRIVATE_HDRS "config.h" "util.h" "mutex.h" ) set (GFLAGS_SRCS "gflags.cc" "gflags_reporting.cc" "gflags_completions.cc" ) if (OS_WINDOWS) list (APPEND PRIVATE_HDRS "windows_port.h") list (APPEND GFLAGS_SRCS "windows_port.cc") endif () # ---------------------------------------------------------------------------- # configure source files if (CMAKE_COMPILER_IS_GNUCXX) set (GFLAGS_ATTRIBUTE_UNUSED "__attribute((unused))") else () set (GFLAGS_ATTRIBUTE_UNUSED) endif () # whenever we build a shared library (DLL on Windows), configure the public # headers of the API for use of this library rather than the optionally # also build statically linked library; users can override GFLAGS_DLL_DECL if (BUILD_SHARED_LIBS) set (GFLAGS_IS_A_DLL 1) else () set (GFLAGS_IS_A_DLL 0) endif () configure_headers (PUBLIC_HDRS ${PUBLIC_HDRS}) configure_sources (PRIVATE_HDRS ${PRIVATE_HDRS}) configure_sources (GFLAGS_SRCS ${GFLAGS_SRCS}) include_directories ("${PROJECT_SOURCE_DIR}/src") include_directories ("${PROJECT_BINARY_DIR}/include") include_directories ("${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}") # ---------------------------------------------------------------------------- # output directories set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "bin") set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "lib") set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "lib") # ---------------------------------------------------------------------------- # add library targets set (TARGETS) # static vs. shared foreach (TYPE IN ITEMS STATIC SHARED) if (BUILD_${TYPE}_LIBS) # whether or not targets are a DLL if (OS_WINDOWS AND "^${TYPE}$" STREQUAL "^SHARED$") set (GFLAGS_IS_A_DLL 1) else () set (GFLAGS_IS_A_DLL 0) endif () string (TOLOWER "${TYPE}" type) # multi-threaded vs. single-threaded foreach (opts IN ITEMS "" _nothreads) if (BUILD_gflags${opts}_LIB) add_library (gflags${opts}-${type} ${TYPE} ${GFLAGS_SRCS} ${PRIVATE_HDRS} ${PUBLIC_HDRS}) if (opts MATCHES "nothreads") set (defines "GFLAGS_IS_A_DLL=${GFLAGS_IS_A_DLL};NOTHREADS") else () set (defines "GFLAGS_IS_A_DLL=${GFLAGS_IS_A_DLL}") if (CMAKE_USE_PTHREADS_INIT) target_link_libraries (gflags${opts}-${type} ${CMAKE_THREAD_LIBS_INIT}) endif () endif () set_target_properties ( gflags${opts}-${type} PROPERTIES COMPILE_DEFINITIONS "${defines}" OUTPUT_NAME "gflags${opts}" VERSION "${PACKAGE_VERSION}" SOVERSION "${PACKAGE_SOVERSION}" ) if (HAVE_SHLWAPI_H) target_link_libraries (gflags${opts}-${type} shlwapi.lib) endif () if (NOT TARGET gflags${opts}) add_custom_target (gflags${opts}) endif () add_dependencies (gflags${opts} gflags${opts}-${type}) list (APPEND TARGETS gflags${opts}-${type}) endif () endforeach () endif () endforeach () # ---------------------------------------------------------------------------- # installation if (OS_WINDOWS) set (RUNTIME_INSTALL_DIR Bin) set (LIBRARY_INSTALL_DIR Lib) set (INCLUDE_INSTALL_DIR Include) set (CONFIG_INSTALL_DIR CMake) else () set (RUNTIME_INSTALL_DIR bin) # The LIB_INSTALL_DIR and LIB_SUFFIX variables are used by the Fedora # package maintainers. Also package maintainers of other distribution # packages need to be able to specify the name of the library directory. if (NOT LIB_INSTALL_DIR) set (LIB_INSTALL_DIR "lib${LIB_SUFFIX}") endif () set (LIBRARY_INSTALL_DIR "${LIB_INSTALL_DIR}" CACHE PATH "Directory of installed libraries, e.g., \"lib64\"" ) mark_as_advanced (LIBRARY_INSTALL_DIR) set (INCLUDE_INSTALL_DIR include) set (CONFIG_INSTALL_DIR ${LIBRARY_INSTALL_DIR}/cmake/${PACKAGE_NAME}) endif () file (RELATIVE_PATH INSTALL_PREFIX_REL2CONFIG_DIR "${CMAKE_INSTALL_PREFIX}/${CONFIG_INSTALL_DIR}" "${CMAKE_INSTALL_PREFIX}") configure_file (cmake/config.cmake.in "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-config-install.cmake" @ONLY) configure_file (cmake/version.cmake.in "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake" @ONLY) install (TARGETS ${TARGETS} DESTINATION ${LIBRARY_INSTALL_DIR} EXPORT gflags-lib) if (INSTALL_HEADERS) install (FILES ${PUBLIC_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/${GFLAGS_INCLUDE_DIR}) install ( FILES "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-config-install.cmake" RENAME ${PACKAGE_NAME}-config.cmake DESTINATION ${CONFIG_INSTALL_DIR} ) install ( FILES "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake" DESTINATION ${CONFIG_INSTALL_DIR} ) install (EXPORT gflags-lib DESTINATION ${CONFIG_INSTALL_DIR} FILE ${PACKAGE_NAME}-export.cmake) if (UNIX) install (PROGRAMS src/gflags_completions.sh DESTINATION ${RUNTIME_INSTALL_DIR}) endif () endif () # ---------------------------------------------------------------------------- # support direct use of build tree set (INSTALL_PREFIX_REL2CONFIG_DIR .) export (TARGETS ${TARGETS} FILE "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-export.cmake") export (PACKAGE gflags) configure_file (cmake/config.cmake.in "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-config.cmake" @ONLY) # ---------------------------------------------------------------------------- # testing - MUST follow the generation of the build tree config file if (BUILD_TESTING) include (CTest) enable_testing () add_subdirectory (test) endif () # ---------------------------------------------------------------------------- # packaging if (BUILD_PACKAGING) if (NOT BUILD_SHARED_LIBS AND NOT INSTALL_HEADERS) message (WARNING "Package will contain static libraries without headers!" "\nRecommended options for generation of runtime package:" "\n BUILD_SHARED_LIBS=ON" "\n BUILD_STATIC_LIBS=OFF" "\n INSTALL_HEADERS=OFF" "\nRecommended options for generation of development package:" "\n BUILD_SHARED_LIBS=ON" "\n BUILD_STATIC_LIBS=ON" "\n INSTALL_HEADERS=ON") endif () # default package generators if (APPLE) set (PACKAGE_GENERATOR "PackageMaker") set (PACKAGE_SOURCE_GENERATOR "TGZ;ZIP") elseif (UNIX) set (PACKAGE_GENERATOR "DEB;RPM") set (PACKAGE_SOURCE_GENERATOR "TGZ;ZIP") else () set (PACKAGE_GENERATOR "ZIP") set (PACKAGE_SOURCE_GENERATOR "ZIP") endif () # used package generators set (CPACK_GENERATOR "${PACKAGE_GENERATOR}" CACHE STRING "List of binary package generators (CPack).") set (CPACK_SOURCE_GENERATOR "${PACKAGE_SOURCE_GENERATOR}" CACHE STRING "List of source package generators (CPack).") mark_as_advanced (CPACK_GENERATOR CPACK_SOURCE_GENERATOR) # some package generators (e.g., PackageMaker) do not allow .md extension configure_file ("${CMAKE_CURRENT_LIST_DIR}/README.md" "${CMAKE_CURRENT_BINARY_DIR}/README.txt" COPYONLY) # common package information set (CPACK_PACKAGE_VENDOR "Andreas Schuh") set (CPACK_PACKAGE_CONTACT "google-gflags@googlegroups.com") set (CPACK_PACKAGE_NAME "${PACKAGE_NAME}") set (CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}") set (CPACK_PACKAGE_VERSION_MAJOR "${PACKAGE_VERSION_MAJOR}") set (CPACK_PACKAGE_VERSION_MINOR "${PACKAGE_VERSION_MINOR}") set (CPACK_PACKAGE_VERSION_PATCH "${PACKAGE_VERSION_PATCH}") set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "A commandline flags library that allows for distributed flags.") set (CPACK_RESOURCE_FILE_WELCOME "${CMAKE_CURRENT_BINARY_DIR}/README.txt") set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_LIST_DIR}/COPYING.txt") set (CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_BINARY_DIR}/README.txt") set (CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") set (CPACK_OUTPUT_FILE_PREFIX packages) set (CPACK_PACKAGE_RELOCATABLE TRUE) set (CPACK_MONOLITHIC_INSTALL TRUE) # RPM package information -- used in cmake/package.cmake.in also for DEB set (CPACK_RPM_PACKAGE_GROUP "Development/Libraries") set (CPACK_RPM_PACKAGE_LICENSE "BSD") set (CPACK_RPM_PACKAGE_URL "http://schuhschuh.github.com/gflags") set (CPACK_RPM_CHANGELOG_FILE "${CMAKE_CURRENT_LIST_DIR}/ChangeLog.txt") if (INSTALL_HEADERS) set (CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_LIST_DIR}/doc/index.html") else () set (CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_LIST_DIR}/cmake/README_runtime.txt") endif () # system/architecture if (WINDOWS) if (CMAKE_CL_64) set (CPACK_SYSTEM_NAME "win64") else () set (CPACK_SYSTEM_NAME "win32") endif () set (CPACK_PACKAGE_ARCHITECTURE) elseif (APPLE) set (CPACK_PACKAGE_ARCHITECTURE darwin) else () string (TOLOWER "${CMAKE_SYSTEM_NAME}" CPACK_SYSTEM_NAME) if (CMAKE_CXX_FLAGS MATCHES "-m32") set (CPACK_PACKAGE_ARCHITECTURE i386) else () execute_process ( COMMAND dpkg --print-architecture RESULT_VARIABLE RV OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE ) if (RV EQUAL 0) string (STRIP "${CPACK_PACKAGE_ARCHITECTURE}" CPACK_PACKAGE_ARCHITECTURE) else () execute_process (COMMAND uname -m OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE) if (CPACK_PACKAGE_ARCHITECTURE MATCHES "x86_64") set (CPACK_PACKAGE_ARCHITECTURE amd64) else () set (CPACK_PACKAGE_ARCHITECTURE i386) endif () endif () endif () endif () # source package settings set (CPACK_SOURCE_TOPLEVEL_TAG "source") set (CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") set (CPACK_SOURCE_IGNORE_FILES "/\\\\.git/;\\\\.swp$;\\\\.#;/#;\\\\.*~;cscope\\\\.*;/[Bb]uild[.+-_a-zA-Z0-9]*/") # default binary package settings set (CPACK_INCLUDE_TOPLEVEL_DIRECTORY TRUE) set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_SYSTEM_NAME}") if (CPACK_PACKAGE_ARCHITECTURE) set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPACK_PACKAGE_ARCHITECTURE}") endif () # generator specific configuration file # # allow package maintainers to use their own configuration file # $ cmake -DCPACK_PROJECT_CONFIG_FILE:FILE=/path/to/package/config if (NOT CPACK_PROJECT_CONFIG_FILE) configure_file ( "${CMAKE_CURRENT_LIST_DIR}/cmake/package.cmake.in" "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-package.cmake" @ONLY ) set (CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/${PACKAGE_NAME}-package.cmake") endif () include (CPack) endif () # BUILD_PACKAGING gflags-2.1.2/COPYING.txt000066400000000000000000000027071250430723500146370ustar00rootroot00000000000000Copyright (c) 2006, 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. gflags-2.1.2/ChangeLog.txt000066400000000000000000000227671250430723500153660ustar00rootroot00000000000000* Tue Mar 24 2014 - Andreas Schuh - gflags: version 2.1.2 - Moved project to GitHub - Added GFLAGS_NAMESPACE definition to gflags_declare.h - Fixed issue 94: Keep "google" as primary namespace and import symbols into "gflags" namespace - Fixed issue 96: Fix binary ABI compatibility with gflags 2.0 using "google" as primary namespace - Fixed issue 97/101: Removed (patched) CMake modules and enabled C language instead - Fixed issue 103: Set CMake policy CMP0042 to silence warning regarding MACOS_RPATH setting * Sun Mar 20 2014 - Andreas Schuh - gflags: version 2.1.1 - Fixed issue 77: GFLAGS_IS_A_DLL expands to empty string in gflags_declare.h - Fixed issue 79: GFLAGS_NAMESPACE not expanded to actual namespace in gflags_declare.h - Fixed issue 80: Allow include path to differ from GFLAGS_NAMESPACE * Thu Mar 20 2014 - Andreas Schuh - gflags: version 2.1.0 - Build system configuration using CMake instead of autotools - CPack packaging support for Debian/Ubuntu, Red Hat, and Mac OS X - Fixed issue 54: Fix "invalid suffix on literal" (C++11) - Fixed issue 57: Use _strdup instead of strdup on Windows - Fixed issue 62: Change all preprocessor include guards to start with GFLAGS_ - Fixed issue 64: Add DEFINE_validator macro - Fixed issue 73: Warnings in Visual Studio 2010 and unable to compile unit test * Wed Jan 25 2012 - Google Inc. - gflags: version 2.0 - Changed the 'official' gflags email in setup.py/etc - Renamed google-gflags.sln to gflags.sln - Changed copyright text to reflect Google's relinquished ownership * Tue Dec 20 2011 - Google Inc. - google-gflags: version 1.7 - Add CommandLineFlagInfo::flag_ptr pointing to current storage (musji) - PORTING: flush after writing to stderr, needed on cygwin - PORTING: Clean up the GFLAGS_DLL_DECL stuff better - Fix a bug in StringPrintf() that affected large strings (csilvers) - Die at configure-time when g++ isn't installed * Fri Jul 29 2011 - Google Inc. - google-gflags: version 1.6 - BUGFIX: Fix a bug where we were leaving out a required $(top_srcdir) - Fix definition of clstring (jyrki) - Split up flag declares into its own file (jyrki) - Add --version support (csilvers) - Update the README for gflags with static libs - Update acx_pthread.m4 for nostdlib - Change ReparseCommandLineFlags to return void (csilvers) - Some doc typofixes and example augmentation (various) * Mon Jan 24 2011 - Google Inc. - google-gflags: version 1.5 - Better reporting of current vs default value (handler) - Add API for cleaning up of memory at program-exit (jmarantz) - Fix macros to work inside namespaces (csilvers) - Use our own string typedef in case string is redefined (csilvers) - Updated to autoconf 2.65 * Wed Oct 13 2010 - Google Inc. - google-gflags: version 1.4 - Add a check to prevent passing 0 to DEFINE_string (jorg) - Reduce compile (.o) size (jyrki) - Some small changes to quiet debug compiles (alexk) - PORTING: better support static linking on windows (csilvers) - DOCUMENTATION: change default values, use validators, etc. - Update the NEWS file to be non-empty - Add pkg-config (.pc) files for libgflags and libgflags_nothreads * Mon Jan 4 2010 - Google Inc. - google-gflags: version 1.3 - PORTABILITY: can now build and run tests under MSVC (csilvers) - Remove the python gflags code, which is now its own package (tansell) - Clarify that "last flag wins" in the docs (csilvers) - Comment danger of using GetAllFlags in validators (wojtekm) - PORTABILITY: Some fixes necessary for c++0x (mboerger) - Makefile fix: $(srcdir) -> $(top_srcdir) in one place (csilvres) - INSTALL: autotools to autoconf v2.64 + automake v1.11 (csilvers) * Thu Sep 10 2009 - Google Inc. - google-gflags: version 1.2 - PORTABILITY: can now build and run tests under mingw (csilvers) - Using a string arg for a bool flag is a compile-time error (rbayardo) - Add --helpxml to gflags.py (salcianu) - Protect against a hypothetical global d'tor mutex problem (csilvers) - BUGFIX: can now define a flag after 'using namespace google' (hamaji) * Tue Apr 14 2009 - Google Inc. - google-gflags: version 1.1 - Add both foo and nofoo for boolean flags, with --undefok (andychu) - Better document how validators work (wojtekm) - Improve binary-detection for bash-completion (mtamsky) - Python: Add a concept of "key flags", used with --help (salcianu) - Python: Robustify flag_values (salcianu) - Python: Add a new DEFINE_bool alias (keir, andrewliu) - Python: Do module introspection based on module name (dsturtevant) - Fix autoconf a bit better, especially on windows and solaris (ajenjo) - BUG FIX: gflags_nothreads was linking against the wrong lib (ajenjo) - BUG FIX: threads-detection failed on FreeBSD; replace it (ajenjo) - PORTABILITY: Quiet an internal compiler error with SUSE 10 (csilvers) - PORTABILITY: Update deb.sh for more recenty debuilds (csilvers) - PORTABILITY: #include more headers to satify new gcc's (csilvers) - INSTALL: Updated to autoconf 2.61 and libtool 1.5.26 (csilvers) * Fri Oct 3 2008 - Google Inc. - google-gflags: version 1.0 - Add a missing newline to an error string (bcmills) - (otherwise exactly the same as gflags 1.0rc2) * Thu Sep 18 2008 - Google Inc. - google-gflags: version 1.0rc2 - Report current flag values in --helpxml (hdn) - Fix compilation troubles with gcc 4.3.3 (simonb) - BUG FIX: I was missing a std:: in DECLARE_string (csilvers) - BUG FIX: Clarify in docs how to specify --bool flags (csilvers) - BUG FIX: Fix --helpshort for source files not in a subdir (csilvers) - BUG FIX: Fix python unittest for 64-bit builds (bcmills) * Tue Aug 19 2008 - Google Inc. - google-gflags: version 1.0rc1 - Move #include files from google/ to gflags/ (csilvers) - Small optimizations to reduce binary (library) size (jyrki) - BUGFIX: forgot a std:: in one of the .h files (csilvers) - Speed up locking by making sure calls are inlined (ajenjo) - 64-BIT COMPATIBILITY: Use %PRId64 instead of %lld (csilvers) - PORTABILITY: fix Makefile to work with Cygwin (ajenjo) - PORTABILITY: fix code to compile under Visual Studio (ajenjo) - PORTABILITY: fix code to compile under Solaris 10 with CC (csilvers) * Mon Jul 21 2008 - Google Inc. - google-gflags: version 0.9 - Add the ability to validate a command-line flag (csilvers) - Add completion support for commandline flags in bash (daven) - Add -W compile flags to Makefile, when using gcc (csilvers) - Allow helpstring to be NULL (cristianoc) - Improved documentation of classes in the .cc file (csilvers) - Fix python bug with AppendFlagValues + shortnames (jjtswan) - Use bool instead of int for boolean flags in gflags.py (bcmills) - Simplify the way we declare flags, now more foolproof (csilvers) - Better error messages when bool flags collide (colohan) - Only evaluate DEFINE_foo macro args once (csilvers) * Wed Mar 26 2008 - Google Inc. - google-gflags: version 0.8 - Export DescribeOneFlag() in the API - Add support for automatic line wrapping at 80 cols for gflags.py - Bugfix: do not treat an isolated "-" the same as an isolated "--" - Update rpm spec to point to Google Code rather than sourceforge (!) - Improve documentation (including documenting thread-safety) - Improve #include hygiene - Improve testing * Thu Oct 18 2007 - Google Inc. - google-gflags: version 0.7 - Deal even more correctly with libpthread not linked in (csilvers) - Add STRIP_LOG, an improved DO_NOT_SHOW_COMMANDLINE_HELP (sioffe) - Be more accurate printing default flag values in --help (dsturtevant) - Reduce .o file size a bit by using shorter namespace names (jeff) - Use relative install path, so 'setup.py --home' works (csilvers) - Notice when a boolean flag has a non-boolean default (bnmouli) - Broaden --helpshort to match foo-main.cc and foo_main.cc (hendrie) - Fix "no modules match" message for --helpshort, etc (hendrie) * Wed Aug 15 2007 - Google Inc. - google-gflags: version 0.6 - Deal correctly with case that libpthread is not linked in (csilvers) - Update Makefile/tests so we pass "make distcheck" (csilvers) - Document and test that last assignment to a flag wins (wan) * Tue Jun 12 2007 - Google Inc. - google-gflags: version 0.5 - Include all m4 macros in the distribution (csilvers) - Python: Fix broken data_files field in setup.py (sidlon) - Python: better string serliaizing and unparsing (abo, csimmons) - Fix checks for NaN and inf to work with Mac OS X (csilvers) * Thu Apr 19 2007 - Google Inc. - google-gflags: version 0.4 - Remove is_default from GetCommandLineFlagInfo (csilvers) - Portability fixes: includes, strtoll, gcc4.3 errors (csilvers) - A few doc typo cleanups (csilvers) * Wed Mar 28 2007 - Google Inc. - google-gflags: version 0.3 - python portability fix: use popen instead of subprocess (csilvers) - Add is_default to CommandLineFlagInfo (pchien) - Make docs a bit prettier (csilvers) - Actually include the python files in the distribution! :-/ (csilvers) * Mon Jan 22 2007 - Google Inc. - google-gflags: version 0.2 - added support for python commandlineflags, as well as c++ - gflags2man, a script to turn flags into a man page (dchristian) * Wed Dec 13 2006 - Google Inc. - google-gflags: version 0.1 gflags-2.1.2/INSTALL.md000066400000000000000000000045121250430723500144120ustar00rootroot00000000000000Installing a binary distribution package ======================================== No official binary distribution packages are provided by the gflags developers. There may, however, be binary packages available for your OS. Please consult also the package repositories of your Linux distribution. For example on Debian/Ubuntu Linux, gflags can be installed using the following command: sudo apt-get install gflags Compiling the source code ========================= The build system of gflags is since version 2.1 based on [CMake](http://cmake.org). The common steps to build, test, and install software are therefore: 1. Extract source files. 2. Create build directory and change to it. 3. Run CMake to configure the build tree. 4. Build the software using selected build tool. 5. Test the built software. 6. Install the built files. On Unix-like systems with GNU Make as build tool, these build steps can be summarized by the following sequence of commands executed in a shell, where ```$package``` and ```$version``` are shell variables which represent the name of this package and the obtained version of the software. $ tar xzf gflags-$version-source.tar.gz $ cd gflags-$version $ mkdir build && cd build $ ccmake .. - Press 'c' to configure the build system and 'e' to ignore warnings. - Set CMAKE_INSTALL_PREFIX and other CMake variables and options. - Continue pressing 'c' until the option 'g' is available. - Then press 'g' to generate the configuration files for GNU Make. $ make $ make test (optional) $ make install (optional) In the following, only gflags-specific CMake settings available to configure the build and installation are documented. CMake Option | Description ---------------------- | ------------------------------------------------------- CMAKE_INSTALL_PREFIX | Installation directory, e.g., "/usr/local" on Unix and "C:\Program Files\gflags" on Windows. GFLAGS_NAMESPACE | Name of the C++ namespace to be used by the gflags library. Note that the public source header files are installed in a subdirectory named after this namespace. To maintain backwards compatibility with the Google Commandline Flags, set this variable to "google". The default is "gflags". GFLAGS_INCLUDE_DIR | Name of include subdirectory where headers are installed into. gflags-2.1.2/README.md000066400000000000000000000261211250430723500142410ustar00rootroot0000000000000024 March 2015 ------------- Released gflags 2.1.2 with fixes of ABI incompatibilities to 2.0 caused by namespace change. The deprecated "google" namespace is yet kept as primary namespace while sybmols are imported into the new "gflags" namespace by default. This can be configured using GFLAGS_NAMESPACE and GLAGS_INCLUDE_DIR. Problems with the (patched) CMake modules FindThreads.cmake and CheckTypeSize.cmake are resolved by re-enabling the C language again even though gflags is C++. Finalized move of gflags project from Google Code to GitHub. Email addresses of original issue reporters got lost in the process. Given the age of most issue reports, this should be neglibable. Please report any further issues using the GitHub issue tracker. 30 March 2014 ------------- I've just released gflags 2.1.1. This release fixes a few bugs in the configuration of gflags\_declare.h and adds a separate GFLAGS\_INCLUDE\_DIR CMake variable to the build configuration. Setting GFLAGS\_NAMESPACE to "google" no longer changes also the include path of the public header files. This allows the use of the library with other Google projects such as glog which still use the deprecated "google" namespace for the gflags library, but include it as "gflags/gflags.h". 20 March 2014 ------------- I've just released gflags 2.1. The major changes are the use of CMake for the build configuration instead of the autotools and packaging support through CPack. The default namespace of all C++ symbols is now "gflags" instead of "google". This can be configured via the GFLAGS\_NAMESPACE variable. This release compiles with all major compilers without warnings and passed the unit tests on Ubuntu 12.04, Windows 7 (Visual Studio 2008 and 2010, Cygwin, MinGW), and Mac OS X (Xcode 5.1). The SVN repository on Google Code is now frozen and replaced by a Git repository such that it can be used as Git submodule by projects. The main hosting of this project remains at Google Code. Thanks to the distributed character of Git, I can push (and pull) changes from both GitHub and Google Code in order to keep the two public repositories in sync. When fixing an issue for a pull request through either of these hosting platforms, please reference the issue number as [described here](https://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control). For the further development, I am following the [Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) with feature branch names prefixed by "feature/" and bugfix branch names prefixed by "bugfix/", respectively. Binary and source [packages](https://github.com/schuhschuh/gflags/releases) are available on GitHub. 14 January 2013 --------------- The migration of the build system to CMake is almost complete. What remains to be done is rewriting the tests in Python such they can be executed on non-Unix platforms and splitting them up into separate CTest tests. Though merging these changes into the master branch yet remains to be done, it is recommended to already start using the [cmake-migration](https://github.com/schuhschuh/gflags/tree/cmake-migration) branch. 20 April 2013 ------------- More than a year has past since I (Andreas) took over the maintenance for `gflags`. Only few minor changes have been made since then, much to my regret. To get more involved and stimulate participation in the further development of the library, I moved the project source code today to [GitHub](https://github.com/schuhschuh/gflags). I believe that the strengths of [Git](http://git-scm.com/) will allow for better community collaboration as well as ease the integration of changes made by others. I encourage everyone who would like to contribute to send me pull requests. Git's lightweight feature branches will also provide the right tool for more radical changes which should only be merged back into the master branch after these are complete and implement the desired behavior. The SVN repository remains accessible at Google Code and I will keep the master branch of the Git repository hosted at GitHub and the trunk of the Subversion repository synchronized. Initially, I was going to simply switch the Google Code project to Git, but in this case the SVN repository would be frozen and force everyone who would like the latest development changes to use Git as well. Therefore I decided to host the public Git repository at GitHub instead. Please continue to report any issues with gflags on Google Code. The GitHub project will only be used to host the Git repository. One major change of the project structure I have in mind for the next weeks is the migration from autotools to [CMake](http://www.cmake.org/). Check out the (unstable!) [cmake-migration](https://github.com/schuhschuh/gflags/tree/cmake-migration) branch on GitHub for details. 25 January 2012 --------------- I've just released gflags 2.0. The `google-gflags` project has been renamed to `gflags`. I (csilvers) am stepping down as maintainer, to be replaced by Andreas Schuh. Welcome to the team, Andreas! I've seen the energy you have around gflags and the ideas you have for the project going forward, and look forward to having you on the team. I bumped the major version number up to 2 to reflect the new community ownership of the project. All the [changes](ChangeLog.txt) are related to the renaming. There are no functional changes from gflags 1.7. In particular, I've kept the code in the namespace `google`, though in a future version it should be renamed to `gflags`. I've also kept the `/usr/local/include/google/` subdirectory as synonym of `/usr/local/include/gflags/`, though the former name has been obsolete for some time now. 18 January 2011 --------------- The `google-gflags` Google Code page has been renamed to `gflags`, in preparation for the project being renamed to `gflags`. In the coming weeks, I'll be stepping down as maintainer for the gflags project, and as part of that Google is relinquishing ownership of the project; it will now be entirely community run. The name change reflects that shift. 20 December 2011 ---------------- I've just released gflags 1.7. This is a minor release; the major change is that `CommandLineFlagInfo` now exports the address in memory where the flag is located. There has also been a bugfix involving very long --help strings, and some other minor [changes](ChangeLog.txt). 29 July 2011 ------------ I've just released gflags 1.6. The major new feature in this release is support for setting version info, so that --version does something useful. One minor change has required bumping the library number: `ReparseCommandlineFlags` now returns `void` instead of `int` (the int return value was always meaningless). Though I doubt anyone ever used this (meaningless) return value, technically it's a change to the ABI that requires a version bump. A bit sad. There's also a procedural change with this release: I've changed the internal tools used to integrate Google-supplied patches for gflags into the opensource release. These new tools should result in more frequent updates with better change descriptions. They will also result in future `ChangeLog` entries being much more verbose (for better or for worse). See the [ChangeLog](ChangeLog.txt) for a full list of changes for this release. 24 January 2011 --------------- I've just released gflags 1.5. This release has only minor changes from 1.4, including some slightly better reporting in --help, and an new memory-cleanup function that can help when running gflags-using libraries under valgrind. The major change is to fix up the macros (`DEFINE_bool` and the like) to work more reliably inside namespaces. If you have not had a problem with these macros, and don't need any of the other changes described, there is no need to upgrade. See the [ChangeLog](ChangeLog.txt) for a full list of changes for this release. 11 October 2010 --------------- I've just released gflags 1.4. This release has only minor changes from 1.3, including some documentation tweaks and some work to make the library smaller. If 1.3 is working well for you, there's no particular reason to upgrade. 4 January 2010 -------------- I've just released gflags 1.3. gflags now compiles under MSVC, and all tests pass. I **really** never thought non-unix-y Windows folks would want gflags, but at least some of them do. The major news, though, is that I've separated out the python package into its own library, [python-gflags](http://code.google.com/p/python-gflags). If you're interested in the Python version of gflags, that's the place to get it now. 10 September 2009 ----------------- I've just released gflags 1.2. The major change from gflags 1.1 is it now compiles under MinGW (as well as cygwin), and all tests pass. I never thought Windows folks would want unix-style command-line flags, since they're so different from the Windows style, but I guess I was wrong! The other changes are minor, such as support for --htmlxml in the python version of gflags. 15 April 2009 ------------- I've just released gflags 1.1. It has only minor changes fdrom gflags 1.0 (see the [ChangeLog](ChangeLog.txt) for details). The major change is that I moved to a new system for creating .deb and .rpm files. This allows me to create x86\_64 deb and rpm files. In the process of moving to this new system, I noticed an inconsistency: the tar.gz and .rpm files created libraries named libgflags.so, but the deb file created libgoogle-gflags.so. I have fixed the deb file to create libraries like the others. I'm no expert in debian packaging, but I believe this has caused the package name to change as well. Please let me know (at [[mailto:google-gflags@googlegroups.com](mailto:google-gflags@googlegroups.com) google-gflags@googlegroups.com]) if this causes problems for you -- especially if you know of a fix! I would be happy to change the deb packages to add symlinks from the old library name to the new (libgoogle-gflags.so -> libgflags.so), but that is beyond my knowledge of how to make .debs. If you've tried to install a .rpm or .deb and it doesn't work for you, let me know. I'm excited to finally have 64-bit package files, but there may still be some wrinkles in the new system to iron out. 1 October 2008 -------------- gflags 1.0rc2 was out for a few weeks without any issues, so gflags 1.0 is now released. This is much like gflags 0.9. The major change is that the .h files have been moved from `/usr/include/google` to `/usr/include/gflags`. While I have backwards-compatibility forwarding headeds in place, please rewrite existing code to say ``` #include ``` instead of ``` #include ``` I've kept the default namespace to google. You can still change with with the appropriate flag to the configure script (`./configure --help` to see the flags). If you have feedback as to whether the default namespace should change to gflags, which would be a non-backwards-compatible change, send mail to `google-gflags@googlegroups.com`! Version 1.0 also has some neat new features, like support for bash commandline-completion of help flags. See the [ChangeLog](ChangeLog.txt) for more details. If I don't hear any bad news for a few weeks, I'll release 1.0-final. gflags-2.1.2/cmake/000077500000000000000000000000001250430723500140405ustar00rootroot00000000000000gflags-2.1.2/cmake/README_runtime.txt000066400000000000000000000003561250430723500173050ustar00rootroot00000000000000This package contains runtime libraries only which are required by applications that use these libraries for the commandline flags processing. If you want to develop such application, download and install the development package instead. gflags-2.1.2/cmake/config.cmake.in000066400000000000000000000014451250430723500167200ustar00rootroot00000000000000## gflags CMake configuration file # library version information set (@PACKAGE_NAME@_VERSION_STRING "@PACKAGE_VERSION@") set (@PACKAGE_NAME@_VERSION_MAJOR @PACKAGE_VERSION_MAJOR@) set (@PACKAGE_NAME@_VERSION_MINOR @PACKAGE_VERSION_MINOR@) set (@PACKAGE_NAME@_VERSION_PATCH @PACKAGE_VERSION_PATCH@) # import targets include ("${CMAKE_CURRENT_LIST_DIR}/@PACKAGE_NAME@-export.cmake") # installation prefix get_filename_component (CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component (_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_PREFIX_REL2CONFIG_DIR@" ABSOLUTE) # include directory set (@PACKAGE_NAME@_INCLUDE_DIR "${_INSTALL_PREFIX}/@INCLUDE_INSTALL_DIR@") # gflags library set (@PACKAGE_NAME@_LIBRARIES gflags) # unset private variables unset (_INSTALL_PREFIX) gflags-2.1.2/cmake/execute_test.cmake000066400000000000000000000033641250430723500175510ustar00rootroot00000000000000# ---------------------------------------------------------------------------- # sanitize string stored in variable for use in regular expression. macro (sanitize_for_regex STRVAR) string (REGEX REPLACE "([.+*?^$()])" "\\\\\\1" ${STRVAR} "${${STRVAR}}") endmacro () # ---------------------------------------------------------------------------- # script arguments if (NOT COMMAND) message (FATAL_ERROR "Test command not specified!") endif () if (NOT DEFINED EXPECTED_RC) set (EXPECTED_RC 0) endif () if (EXPECTED_OUTPUT) sanitize_for_regex(EXPECTED_OUTPUT) endif () if (UNEXPECTED_OUTPUT) sanitize_for_regex(UNEXPECTED_OUTPUT) endif () # ---------------------------------------------------------------------------- # set a few environment variables (useful for --tryfromenv) set (ENV{FLAGS_undefok} "foo,bar") set (ENV{FLAGS_weirdo} "") set (ENV{FLAGS_version} "true") set (ENV{FLAGS_help} "false") # ---------------------------------------------------------------------------- # execute test command execute_process( COMMAND ${COMMAND} RESULT_VARIABLE RC OUTPUT_VARIABLE OUTPUT ERROR_VARIABLE OUTPUT ) if (OUTPUT) message ("${OUTPUT}") endif () # ---------------------------------------------------------------------------- # check test result if (NOT RC EQUAL EXPECTED_RC) string (REPLACE ";" " " COMMAND "${COMMAND}") message (FATAL_ERROR "Command:\n\t${COMMAND}\nExit status is ${RC}, expected ${EXPECTED_RC}") endif () if (EXPECTED_OUTPUT AND NOT OUTPUT MATCHES "${EXPECTED_OUTPUT}") message (FATAL_ERROR "Test output does not match expected output: ${EXPECTED_OUTPUT}") endif () if (UNEXPECTED_OUTPUT AND OUTPUT MATCHES "${UNEXPECTED_OUTPUT}") message (FATAL_ERROR "Test output matches unexpected output: ${UNEXPECTED_OUTPUT}") endif ()gflags-2.1.2/cmake/package.cmake.in000066400000000000000000000040361250430723500170450ustar00rootroot00000000000000# Per-generator CPack configuration file. See CPACK_PROJECT_CONFIG_FILE documented at # http://www.cmake.org/cmake/help/v2.8.12/cpack.html#variable:CPACK_PROJECT_CONFIG_FILE # # All common CPACK_* variables are set in CMakeLists.txt already. This file only # overrides some of these to provide package generator specific settings. # whether package contains all development files or only runtime files set (DEVEL @INSTALL_HEADERS@) # ------------------------------------------------------------------------------ # Mac OS X package if (CPACK_GENERATOR MATCHES "PackageMaker|DragNDrop") set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") if (DEVEL) set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-devel") endif () set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPACK_PACKAGE_VERSION}") # ------------------------------------------------------------------------------ # Debian package elseif (CPACK_GENERATOR MATCHES "DEB") set (CPACK_PACKAGE_FILE_NAME "lib${CPACK_PACKAGE_NAME}") if (DEVEL) set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-dev") else () set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}0") endif () set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}_${CPACK_PACKAGE_VERSION}-1_${CPACK_PACKAGE_ARCHITECTURE}") set (CPACK_DEBIAN_PACKAGE_DEPENDS) set (CPACK_DEBIAN_PACKAGE_SECTION "devel") set (CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CPACK_RPM_PACKAGE_URL}") set (CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") set (CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${CPACK_PACKAGE_ARCHITECTURE}") # ------------------------------------------------------------------------------ # RPM package elseif (CPACK_GENERATOR MATCHES "RPM") set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") if (DEVEL) set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-devel") endif () set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPACK_PACKAGE_VERSION}-1.${CPACK_PACKAGE_ARCHITECTURE}") endif () gflags-2.1.2/cmake/utils.cmake000066400000000000000000000071551250430723500162120ustar00rootroot00000000000000## Utility CMake functions. # ---------------------------------------------------------------------------- ## Convert boolean value to 0 or 1 macro (bool_to_int VAR) if (${VAR}) set (${VAR} 1) else () set (${VAR} 0) endif () endmacro () # ---------------------------------------------------------------------------- ## Extract version numbers from version string. function (version_numbers version major minor patch) if (version MATCHES "([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?(rc[1-9][0-9]*|[a-z]+)?") if (CMAKE_MATCH_1) set (_major ${CMAKE_MATCH_1}) else () set (_major 0) endif () if (CMAKE_MATCH_2) set (_minor ${CMAKE_MATCH_2}) string (REGEX REPLACE "^\\." "" _minor "${_minor}") else () set (_minor 0) endif () if (CMAKE_MATCH_3) set (_patch ${CMAKE_MATCH_3}) string (REGEX REPLACE "^\\." "" _patch "${_patch}") else () set (_patch 0) endif () else () set (_major 0) set (_minor 0) set (_patch 0) endif () set ("${major}" "${_major}" PARENT_SCOPE) set ("${minor}" "${_minor}" PARENT_SCOPE) set ("${patch}" "${_patch}" PARENT_SCOPE) endfunction () # ---------------------------------------------------------------------------- ## Configure public header files function (configure_headers out) set (tmp) foreach (src IN LISTS ARGN) if (IS_ABSOLUTE "${src}") list (APPEND tmp "${src}") elseif (EXISTS "${PROJECT_SOURCE_DIR}/src/${src}.in") configure_file ("${PROJECT_SOURCE_DIR}/src/${src}.in" "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}" @ONLY) list (APPEND tmp "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}") else () configure_file ("${PROJECT_SOURCE_DIR}/src/${src}" "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}" COPYONLY) list (APPEND tmp "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}") endif () endforeach () set (${out} "${tmp}" PARENT_SCOPE) endfunction () # ---------------------------------------------------------------------------- ## Configure source files with .in suffix function (configure_sources out) set (tmp) foreach (src IN LISTS ARGN) if (src MATCHES ".h$" AND EXISTS "${PROJECT_SOURCE_DIR}/src/${src}.in") configure_file ("${PROJECT_SOURCE_DIR}/src/${src}.in" "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}" @ONLY) list (APPEND tmp "${PROJECT_BINARY_DIR}/include/${GFLAGS_INCLUDE_DIR}/${src}") else () list (APPEND tmp "${PROJECT_SOURCE_DIR}/src/${src}") endif () endforeach () set (${out} "${tmp}" PARENT_SCOPE) endfunction () # ---------------------------------------------------------------------------- ## Add usage test # # Using PASS_REGULAR_EXPRESSION and FAIL_REGULAR_EXPRESSION would # do as well, but CMake/CTest does not allow us to specify an # expected exit status. Moreover, the execute_test.cmake script # sets environment variables needed by the --fromenv/--tryfromenv tests. macro (add_gflags_test name expected_rc expected_output unexpected_output cmd) set (args "--test_tmpdir=${PROJECT_BINARY_DIR}/Testing/Temporary" "--srcdir=${PROJECT_SOURCE_DIR}/test") add_test ( NAME ${name} COMMAND "${CMAKE_COMMAND}" "-DCOMMAND:STRING=$;${args};${ARGN}" "-DEXPECTED_RC:STRING=${expected_rc}" "-DEXPECTED_OUTPUT:STRING=${expected_output}" "-DUNEXPECTED_OUTPUT:STRING=${unexpected_output}" -P "${PROJECT_SOURCE_DIR}/cmake/execute_test.cmake" WORKING_DIRECTORY "${GFLAGS_FLAGFILES_DIR}" ) endmacro () gflags-2.1.2/cmake/version.cmake.in000066400000000000000000000013241250430723500171340ustar00rootroot00000000000000## gflags CMake configuration version file # ----------------------------------------------------------------------------- # library version set (PACKAGE_VERSION "@PACKAGE_VERSION@") # ----------------------------------------------------------------------------- # check compatibility # Perform compatibility check here using the input CMake variables. # See example in http://www.cmake.org/Wiki/CMake_2.6_Notes. set (PACKAGE_VERSION_COMPATIBLE TRUE) set (PACKAGE_VERSION_UNSUITABLE FALSE) if ("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@PACKAGE_VERSION_MAJOR@" AND "${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@PACKAGE_VERSION_MINOR@") set (PACKAGE_VERSION_EXACT TRUE) else () set (PACKAGE_VERSION_EXACT FALSE) endif () gflags-2.1.2/doc/000077500000000000000000000000001250430723500135255ustar00rootroot00000000000000gflags-2.1.2/doc/designstyle.css000066400000000000000000000040001250430723500165630ustar00rootroot00000000000000body { background-color: #ffffff; color: black; margin-right: 1in; margin-left: 1in; } h1, h2, h3, h4, h5, h6 { color: #3366ff; font-family: sans-serif; } @media print { /* Darker version for printing */ h1, h2, h3, h4, h5, h6 { color: #000080; font-family: helvetica, sans-serif; } } h1 { text-align: center; font-size: 18pt; } h2 { margin-left: -0.5in; } h3 { margin-left: -0.25in; } h4 { margin-left: -0.125in; } hr { margin-left: -1in; } /* Definition lists: definition term bold */ dt { font-weight: bold; } address { text-align: right; } /* Use the tag for bits of code and for variables and objects. */ code,pre,samp,var { color: #006000; } /* Use the tag for file and directory paths and names. */ file { color: #905050; font-family: monospace; } /* Use the tag for stuff the user should type. */ kbd { color: #600000; } div.note p { float: right; width: 3in; margin-right: 0%; padding: 1px; border: 2px solid #6060a0; background-color: #fffff0; } UL.nobullets { list-style-type: none; list-style-image: none; margin-left: -1em; } /* body:after { content: "Google Confidential"; } */ /* pretty printing styles. See prettify.js */ .str { color: #080; } .kwd { color: #008; } .com { color: #800; } .typ { color: #606; } .lit { color: #066; } .pun { color: #660; } .pln { color: #000; } .tag { color: #008; } .atn { color: #606; } .atv { color: #080; } pre.prettyprint { padding: 2px; border: 1px solid #888; } .embsrc { background: #eee; } @media print { .str { color: #060; } .kwd { color: #006; font-weight: bold; } .com { color: #600; font-style: italic; } .typ { color: #404; font-weight: bold; } .lit { color: #044; } .pun { color: #440; } .pln { color: #000; } .tag { color: #006; font-weight: bold; } .atn { color: #404; } .atv { color: #060; } } /* Table Column Headers */ .hdr { color: #006; font-weight: bold; background-color: #dddddd; } .hdr2 { color: #006; background-color: #eeeeee; }gflags-2.1.2/doc/index.html000066400000000000000000000546051250430723500155340ustar00rootroot00000000000000 How To Use Gflags (formerly Google Commandline Flags)

How To Use gflags (formerly Google Commandline Flags)

(as of )
Table of contents
Introduction
Finding and Linking to gflags using CMake
DEFINE: Defining Flags In Program
Accessing the Flag
DECLARE: Using the Flag in a Different File
RegisterFlagValidator: Sanity-checking Flag Values
Putting It Together: How to Set Up Flags
Setting Flags on the Command Line
Setting Flags at Runtime
Changing the Default Flag Value
Special Flags
The API

Introduction, and Comparison to Other Commandline Flags Libraries

Commandline flags are flags that users specify on the command line when they run an executable. In the command

   fgrep -l -f /var/tmp/foo johannes brahms

-l and -f /var/tmp/foo are the two commandline flags. (johannes and brahms, which don't start with a dash, are commandline arguments.)

Typically, an application lists what flags the user is allowed to pass in, and what arguments they take -- in this example, -l takes no argument, and -f takes a string (in particular, a filename) as an argument. Users can use a library to help parse the commandline and store the flags in some data structure.

Gflags, the commandline flags library used within Google, differs from other libraries, such as getopt(), in that flag definitions can be scattered around the source code, and not just listed in one place such as main(). In practice, this means that a single source-code file will define and use flags that are meaningful to that file. Any application that links in that file will get the flags, and the gflags library will automatically handle that flag appropriately.

There's significant gain in flexibility, and ease of code reuse, due to this technique. However, there is a danger that two files will define the same flag, and then give an error when they're linked together.

The rest of this document describes how to use the commandlineflag library. It's a C++ library, so examples are in C++. However, there is a Python port with the same functionality, and this discussion translates directly to Python.

Finding and Linking to gflags using CMake

Using gflags within a project which uses CMake for its build system is easy. Therefore, simply add the following CMake code to your CMakeLists.txt file.

   find_package (gflags REQUIRED)
   include_directories (${gflags_INCLUDE_DIR})
   
   add_executable (foo main.cc)
   target_link_libraries (foo gflags)

DEFINE: Defining Flags In Program

Defining a flag is easy: just use the appropriate macro for the type you want the flag to be, as defined at the bottom of gflags/gflags.h. Here's an example file, foo.cc:

   #include <gflags/gflags.h>

   DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
   DEFINE_string(languages, "english,french,german",
                 "comma-separated list of languages to offer in the 'lang' menu");

DEFINE_bool defines a boolean flag. Here are the types supported:

  • DEFINE_bool: boolean
  • DEFINE_int32: 32-bit integer
  • DEFINE_int64: 64-bit integer
  • DEFINE_uint64: unsigned 64-bit integer
  • DEFINE_double: double
  • DEFINE_string: C++ string

Note that there are no 'complex' types like lists: the "languages" flag in our example is a list of strings, but is defined of type "string", not "list_of_string" or similar. This is by design. We'd rather use only simple types for the flags, and allow for complex, arbitrary parsing routines to parse them, than to try to put the logic inside the flags library proper.

All DEFINE macros take the same three arguments: the name of the flag, its default value, and a 'help' string that describes its use. The 'help' string is displayed when the user runs the application with the --help flag.

You can define a flag in any source-code file in your executable. Only define a flag once! If you want to access a flag in more than one source file, DEFINE it in one file, and DECLARE it in the others. Even better, DEFINE it in foo.cc and DECLARE it in foo.h; then everyone who #includes foo.h can use the flag.

Defining flags in libraries rather than in main() is powerful, but does have some costs. One is that a library might not have a good default value for its flags, for example if the flag holds a filename that might not exist in some environments. To mitigate such problems, you can use flag validators to ensure prompt notification (in the form of a crash) of an invalid flag value.

Note that while most functions in this library are defined in the google namespace, DEFINE_foo (and DECLARE_foo, below), should always be in the global namespace.

Accessing the Flag

All defined flags are available to the program as just a normal variable, with the prefix FLAGS_ prepended. In the above example, the macros define two variables, FLAGS_big_menu (a bool), and FLAGS_languages (a C++ string).

You can read and write to the flag just like any other variable:

   if (FLAGS_consider_made_up_languages)
     FLAGS_languages += ",klingon";   // implied by --consider_made_up_languages
   if (FLAGS_languages.find("finnish") != string::npos)
     HandleFinnish();

You can also get and set flag values via special functions in gflags.h. That's a rarer use case, though.

DECLARE: Using the Flag in a Different File

Accessing a flag in the manner of the previous section only works if the flag was DEFINE-ed at the top of the file. If it wasn't, you'll get an 'unknown variable' error.

The DECLARE_type macro is available when you want to use a flag that's defined in another file. For instance, if I were writing bar.cc but wanted to access the big_menu, flag, I would put this near the top of bar.cc:

   DECLARE_bool(big_menu);

This is functionally equivalent to saying extern FLAGS_big_menu.

Note that such an extern declaration introduces a dependency between your file and the file that defines the big_menu flag: foo.cc, in this case. Such implicit dependencies can be difficult to manage in large projects. For that reason we recommend the following guideline:

If you DEFINE a flag in foo.cc, either don't DECLARE it at all, only DECLARE it in tightly related tests, or only DECLARE it in foo.h.

You should go the do-not-DECLARE route when the flag is only needed by foo.cc, and not in any other file. If you want to modify the value of the flag in the related test file to see if it is functioning as expected, DECLARE it in the foo_test.cc file.

If the flag does span multiple files, DECLARE it in the associated .h file, and make others #include that .h file if they want to access the flag. The #include will make explicit the dependency between the two files. This causes the flag to be a global variable.

RegisterFlagValidator: Sanity-checking Flag Values

After DEFINE-ing a flag, you may optionally register a validator function with the flag. If you do this, after the flag is parsed from the commandline, and whenever its value is changed via a call to SetCommandLineOption(), the validator function is called with the new value as an argument. The validator function should return 'true' if the flag value is valid, and false otherwise. If the function returns false for the new setting of the flag, the flag will retain its current value. If it returns false for the default value, ParseCommandLineFlags will die.

Here is an example use of this functionality:

static bool ValidatePort(const char* flagname, int32 value) {
   if (value > 0 && value < 32768)   // value is ok
     return true;
   printf("Invalid value for --%s: %d\n", flagname, (int)value);
   return false;
}
DEFINE_int32(port, 0, "What port to listen on");
static const bool port_dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort);

By doing the registration at global initialization time (right after the DEFINE), we ensure that the registration happens before the commandline is parsed at the beginning of main().

RegisterFlagValidator() returns true if the registration is successful. It return false if the registration fails because a) the first argument does not refer to a commandline flag, or b) a different validator has already been registered for this flag.

Putting It Together: How to Set Up Flags

The final piece is the one that tells the executable to process the commandline flags, and set the FLAGS_* variables to the appropriate, non-default value based on what is seen on the commandline. This is equivalent to the getopt() call in the getopt library, but has much less overhead to use. In fact, it's just a single function call:

   gflags::ParseCommandLineFlags(&argc, &argv, true);

Usually, this code is at the beginning of main(). argc and argv are exactly as passed in to main(). This routine might modify them, which is why pointers to them are passed in.

The last argument is called "remove_flags". If true, then ParseCommandLineFlags removes the flags and their arguments from argv, and modifies argc appropriately. In this case, after the function call, argv will hold only commandline arguments, and not commandline flags.

If, on the other hand, remove_flags is false, then ParseCommandLineFlags will leave argc unchanged, but will rearrange the arguments in argv so that the flags are all at the beginning. For example, if the input is "/bin/foo" "arg1" "-q" "arg2" (which is legal but weird), the function will rearrange argv so it reads "/bin/foo", "-q", "arg1", "arg2". In this case, ParseCommandLineFlags returns the index into argv that holds the first commandline argument: that is, the index past the last flag. (In this example, it would return 2, since argv[2] points to arg1.)

In either case, the FLAGS_* variables are modified based on what was passed in on the commandline.

Setting Flags on the Command Line

The reason you make something a flag instead of a compile-time constant, is so users can specify a non-default value on the commandline. Here's how they might do it for an application that links in foo.cc:

   app_containing_foo --nobig_menu -languages="chinese,japanese,korean" ...

This sets FLAGS_big_menu = false; and FLAGS_languages = "chinese,japanese,korean", when ParseCommandLineFlags is run.

Note the atypical syntax for setting a boolean flag to false: putting "no" in front of its name. There's a fair bit of flexibility to how flags may be specified. Here's an example of all the ways to specify the "languages" flag:

  • app_containing_foo --languages="chinese,japanese,korean"
  • app_containing_foo -languages="chinese,japanese,korean"
  • app_containing_foo --languages "chinese,japanese,korean"
  • app_containing_foo -languages "chinese,japanese,korean"

For boolean flags, the possibilities are slightly different:

  • app_containing_foo --big_menu
  • app_containing_foo --nobig_menu
  • app_containing_foo --big_menu=true
  • app_containing_foo --big_menu=false

(as well as the single-dash variant on all of these).

Despite this flexibility, we recommend using only a single form: --variable=value for non-boolean flags, and --variable/--novariable for boolean flags. This consistency will make your code more readable, and is also the format required for certain special-use cases like flagfiles.

It is a fatal error to specify a flag on the commandline that has not been DEFINED somewhere in the executable. If you need that functionality for some reason -- say you want to use the same set of flags for several executables, but not all of them DEFINE every flag in your list -- you can specify --undefok to suppress the error.

As in getopt(), -- by itself will terminate flags processing. So in foo -f1 1 -- -f2 2, f1 is considered a flag, but -f2 is not.

If a flag is specified more than once, only the last specification is used; the others are ignored.

Note that flags do not have single-letter synonyms, like they do in the getopt library, nor do we allow "combining" flags behind a single dash, as in ls -la.

Changing the Default Flag Value

Sometimes a flag is defined in a library, and you want to change its default value in one application but not others. It's simple to do this: just assign a new value to the flag in main(), before calling ParseCommandLineFlags():

   DECLARE_bool(lib_verbose);   // mylib has a lib_verbose flag, default is false
   int main(int argc, char** argv) {
     FLAGS_lib_verbose = true;  // in my app, I want a verbose lib by default
     ParseCommandLineFlags(...);
   }

For this application, users can still set the flag value on the commandline, but if they do not, the flag's value will default to true.

Special Flags

There are a few flags defined by the commandlineflags module itself, and are available to all applications that use commandlineflags. These fall into three categories. First are the 'reporting' flags that, when found, cause the application to print some information about itself and exit.

--help shows all flags from all files, sorted by file and then by name; shows the flagname, its default value, and its help string
--helpfull same as -help, but unambiguously asks for all flags (in case -help changes in the future)
--helpshort shows only flags for the file with the same name as the executable (usually the one containing main())
--helpxml like --help, but output is in xml for easier parsing
--helpon=FILE   shows only flags defined in FILE.*
--helpmatch=S shows only flags defined in *S*.*
--helppackage shows flags defined in files in same directory as main()
--version prints version info for the executable

Second are the flags that affect how other flags are parsed.

--undefok=flagname,flagname,... for those names listed as the argument to --undefok, suppress the normal error-exit that occurs when --name is seen on the commandline, but name has not been DEFINED anywhere in the application

Third are the 'recursive' flags, that cause other flag values to be set: --fromenv, --tryfromenv, --flagfile. These are described below in more detail.

--fromenv

--fromenv=foo,bar says to read the values for the foo and bar flags from the environment. In concert with this flag, you must actually set the values in the environment, via a line like one of the two below:

   export FLAGS_foo=xxx; export FLAGS_bar=yyy   # sh
   setenv FLAGS_foo xxx; setenv FLAGS_bar yyy   # tcsh

This is equivalent to specifying --foo=xxx, --bar=yyy on the commandline.

Note it is a fatal error to say --fromenv=foo if foo is not DEFINED somewhere in the application. (Though you can suppress this error via --undefok=foo, just like for any other flag.)

It is also a fatal error to say --fromenv=foo if FLAGS_foo is not actually defined in the environment.

--tryfromenv

--tryfromenv is exactly like --fromenv, except it is not a fatal error to say --tryfromenv=foo if FLAGS_foo is not actually defined in the environment. Instead, in such cases, FLAGS_foo just keeps its default value as specified in the application.

Note it is still an error to say --tryfromenv=foo if foo is not DEFINED somewhere in the application.

--flagfile

--flagfile=f tells the commandlineflags module to read the file f, and to run all the flag-assignments found in that file as if these flags had been specified on the commandline.

In its simplest form, f should just be a list of flag assignments, one per line. Unlike on the commandline, the equals sign separating a flagname from its argument is required for flagfiles. An example flagfile, /tmp/myflags:

--nobig_menus
--languages=english,french

With this flagfile, the following two lines are equivalent:

   ./myapp --foo --nobig_menus --languages=english,french --bar
   ./myapp --foo --flagfile=/tmp/myflags --bar

Note that many errors are silently suppressed in flagfiles. In particular, unrecognized flagnames are silently ignored, as are flags that are missing a required value (e.g., a flagfile that just says --languages).

The general format of a flagfile is a bit more complicated than the simple, common case above. It is: a sequence of filenames, one per line, followed by a sequence of flags, one per line, repeated as many times as desired. Filenames in a flagfile can use wildcards (* and ?), and the sequence of flags located after a sequence of filenames is processed only if the current executable's name matches one of the filenames. It is possible to start the flagfile with a sequence of flags instead of a sequence of filenames; if such a sequence of flags is present, these flags are applied to the current executable no matter what it is.

Lines that start with a # are ignored as comments. Leading whitespace is also ignored in flagfiles, as are blank lines.

It is possible for a flagfile to use the --flagfile flag to include another flagfile.

Flags are always processed in the expected order. That is, processing begins by examining the flags specified directly on the command line. If a flagfile is specified, its contents are processed, and then processing continues with remaining flags from the command line.

The API

In addition to accessing FLAGS_foo directly, it is possible to access the flags programmatically, through an API. It is also possible to access information about a flag, such as its default value and help-string. A FlagSaver makes it easy to modify flags and then automatically undo the modifications later. Finally, there are somewhat unrelated, but useful, routines to easily access parts of argv outside main, including the program name (argv[0]).

For more information about these routines, and other useful helper methods such as gflags::SetUsageMessage() and gflags::SetVersionString, see gflags.h.

Miscellaneous Notes

If your application has code like this:

   #define STRIP_FLAG_HELP 1    // this must go before the #include!
   #include <gflags/gflags.h>

we will remove the help messages from the compiled source. This can reduce the size of the resulting binary somewhat, and may also be useful for security reasons.


Craig Silverstein, Andreas Schuh
gflags-2.1.2/src/000077500000000000000000000000001250430723500135475ustar00rootroot00000000000000gflags-2.1.2/src/config.h.in000066400000000000000000000063301250430723500155740ustar00rootroot00000000000000/* Generated from config.h.in during build configuration using CMake. */ // Note: This header file is only used internally. It is not part of public interface! // --------------------------------------------------------------------------- // System checks // Define if you build this library for a MS Windows OS. #cmakedefine OS_WINDOWS // Define if you have the header file. #cmakedefine HAVE_STDINT_H // Define if you have the header file. #cmakedefine HAVE_SYS_TYPES_H // Define if you have the header file. #cmakedefine HAVE_INTTYPES_H // Define if you have the header file. #cmakedefine HAVE_SYS_STAT_H // Define if you have the header file. #cmakedefine HAVE_UNISTD_H // Define if you have the header file. #cmakedefine HAVE_FNMATCH_H // Define if you have the header file (Windows 2000/XP). #cmakedefine HAVE_SHLWAPI_H // Define if you have the strtoll function. #cmakedefine HAVE_STRTOLL // Define if you have the strtoq function. #cmakedefine HAVE_STRTOQ // Define if you have the header file. #cmakedefine HAVE_PTHREAD // Define if your pthread library defines the type pthread_rwlock_t #cmakedefine HAVE_RWLOCK // gcc requires this to get PRId64, etc. #if defined(HAVE_INTTYPES_H) && !defined(__STDC_FORMAT_MACROS) # define __STDC_FORMAT_MACROS 1 #endif // --------------------------------------------------------------------------- // Package information // Name of package. #define PACKAGE @PROJECT_NAME@ // Define to the full name of this package. #define PACKAGE_NAME @PACKAGE_NAME@ // Define to the full name and version of this package. #define PACKAGE_STRING @PACKAGE_STRING@ // Define to the one symbol short name of this package. #define PACKAGE_TARNAME @PACKAGE_TARNAME@ // Define to the version of this package. #define PACKAGE_VERSION @PACKAGE_VERSION@ // Version number of package. #define VERSION PACKAGE_VERSION // Define to the address where bug reports for this package should be sent. #define PACKAGE_BUGREPORT @PACKAGE_BUGREPORT@ // --------------------------------------------------------------------------- // Path separator #ifndef PATH_SEPARATOR # ifdef OS_WINDOWS # define PATH_SEPARATOR '\\' # else # define PATH_SEPARATOR '/' # endif #endif // --------------------------------------------------------------------------- // Windows // Whether gflags library is a DLL. #ifndef GFLAGS_IS_A_DLL # define GFLAGS_IS_A_DLL 0 #endif // Always export symbols when compiling a shared library as this file is only // included by internal modules when building the gflags library itself. // The gflags_declare.h header file will set it to import these symbols otherwise. #ifndef GFLAGS_DLL_DECL # if GFLAGS_IS_A_DLL && defined(_MSC_VER) # define GFLAGS_DLL_DECL __declspec(dllexport) # else # define GFLAGS_DLL_DECL # endif #endif // Flags defined by the gflags library itself must be exported #ifndef GFLAGS_DLL_DEFINE_FLAG # define GFLAGS_DLL_DEFINE_FLAG GFLAGS_DLL_DECL #endif #ifdef OS_WINDOWS // The unittests import the symbols of the shared gflags library # if GFLAGS_IS_A_DLL && defined(_MSC_VER) # define GFLAGS_DLL_DECL_FOR_UNITTESTS __declspec(dllimport) # endif # include "windows_port.h" #endif gflags-2.1.2/src/gflags.cc000066400000000000000000002175401250430723500153320ustar00rootroot00000000000000// Copyright (c) 1999, 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. // --- // Revamped and reorganized by Craig Silverstein // // This file contains the implementation of all our command line flags // stuff. Here's how everything fits together // // * FlagRegistry owns CommandLineFlags owns FlagValue. // * FlagSaver holds a FlagRegistry (saves it at construct time, // restores it at destroy time). // * CommandLineFlagParser lives outside that hierarchy, but works on // CommandLineFlags (modifying the FlagValues). // * Free functions like SetCommandLineOption() work via one of the // above (such as CommandLineFlagParser). // // In more detail: // // -- The main classes that hold flag data: // // FlagValue holds the current value of a flag. It's // pseudo-templatized: every operation on a FlagValue is typed. It // also deals with storage-lifetime issues (so flag values don't go // away in a destructor), which is why we need a whole class to hold a // variable's value. // // CommandLineFlag is all the information about a single command-line // flag. It has a FlagValue for the flag's current value, but also // the flag's name, type, etc. // // FlagRegistry is a collection of CommandLineFlags. There's the // global registry, which is where flags defined via DEFINE_foo() // live. But it's possible to define your own flag, manually, in a // different registry you create. (In practice, multiple registries // are used only by FlagSaver). // // A given FlagValue is owned by exactly one CommandLineFlag. A given // CommandLineFlag is owned by exactly one FlagRegistry. FlagRegistry // has a lock; any operation that writes to a FlagValue or // CommandLineFlag owned by that registry must acquire the // FlagRegistry lock before doing so. // // --- Some other classes and free functions: // // CommandLineFlagInfo is a client-exposed version of CommandLineFlag. // Once it's instantiated, it has no dependencies or relationships // with any other part of this file. // // FlagRegisterer is the helper class used by the DEFINE_* macros to // allow work to be done at global initialization time. // // CommandLineFlagParser is the class that reads from the commandline // and instantiates flag values based on that. It needs to poke into // the innards of the FlagValue->CommandLineFlag->FlagRegistry class // hierarchy to do that. It's careful to acquire the FlagRegistry // lock before doing any writing or other non-const actions. // // GetCommandLineOption is just a hook into registry routines to // retrieve a flag based on its name. SetCommandLineOption, on the // other hand, hooks into CommandLineFlagParser. Other API functions // are, similarly, mostly hooks into the functionality described above. #include "config.h" #include "gflags.h" #include #include #include #if defined(HAVE_FNMATCH_H) # include #elif defined(HAVE_SHLWAPI_H) # include #endif #include // For va_list and related operations #include #include #include #include #include #include // for pair<> #include #include "mutex.h" #include "util.h" // Special flags, type 1: the 'recursive' flags. They set another flag's val. DEFINE_string(flagfile, "", "load flags from file"); DEFINE_string(fromenv, "", "set flags from the environment" " [use 'export FLAGS_flag1=value']"); DEFINE_string(tryfromenv, "", "set flags from the environment if present"); // Special flags, type 2: the 'parsing' flags. They modify how we parse. DEFINE_string(undefok, "", "comma-separated list of flag names that it is okay to specify " "on the command line even if the program does not define a flag " "with that name. IMPORTANT: flags in this list that have " "arguments MUST use the flag=value format"); namespace GFLAGS_NAMESPACE { using std::map; using std::pair; using std::sort; using std::string; using std::vector; // This is used by the unittest to test error-exit code void GFLAGS_DLL_DECL (*gflags_exitfunc)(int) = &exit; // from stdlib.h // The help message indicating that the commandline flag has been // 'stripped'. It will not show up when doing "-help" and its // variants. The flag is stripped if STRIP_FLAG_HELP is set to 1 // before including base/gflags.h // This is used by this file, and also in gflags_reporting.cc const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001"; namespace { // There are also 'reporting' flags, in gflags_reporting.cc. static const char kError[] = "ERROR: "; // Indicates that undefined options are to be ignored. // Enables deferred processing of flags in dynamically loaded libraries. static bool allow_command_line_reparsing = false; static bool logging_is_probably_set_up = false; // This is a 'prototype' validate-function. 'Real' validate // functions, take a flag-value as an argument: ValidateFn(bool) or // ValidateFn(uint64). However, for easier storage, we strip off this // argument and then restore it when actually calling the function on // a flag value. typedef bool (*ValidateFnProto)(); // Whether we should die when reporting an error. enum DieWhenReporting { DIE, DO_NOT_DIE }; // Report Error and exit if requested. static void ReportError(DieWhenReporting should_die, const char* format, ...) { char error_message[255]; va_list ap; va_start(ap, format); vsnprintf(error_message, sizeof(error_message), format, ap); va_end(ap); fprintf(stderr, "%s", error_message); fflush(stderr); // should be unnecessary, but cygwin's rxvt buffers stderr if (should_die == DIE) gflags_exitfunc(1); } // -------------------------------------------------------------------- // FlagValue // This represent the value a single flag might have. The major // functionality is to convert from a string to an object of a // given type, and back. Thread-compatible. // -------------------------------------------------------------------- class CommandLineFlag; class FlagValue { public: FlagValue(void* valbuf, const char* type, bool transfer_ownership_of_value); ~FlagValue(); bool ParseFrom(const char* spec); string ToString() const; private: friend class CommandLineFlag; // for many things, including Validate() friend class GFLAGS_NAMESPACE::FlagSaverImpl; // calls New() friend class FlagRegistry; // checks value_buffer_ for flags_by_ptr_ map template friend T GetFromEnv(const char*, const char*, T); friend bool TryParseLocked(const CommandLineFlag*, FlagValue*, const char*, string*); // for New(), CopyFrom() enum ValueType { FV_BOOL = 0, FV_INT32 = 1, FV_INT64 = 2, FV_UINT64 = 3, FV_DOUBLE = 4, FV_STRING = 5, FV_MAX_INDEX = 5, }; const char* TypeName() const; bool Equal(const FlagValue& x) const; FlagValue* New() const; // creates a new one with default value void CopyFrom(const FlagValue& x); int ValueSize() const; // Calls the given validate-fn on value_buffer_, and returns // whatever it returns. But first casts validate_fn_proto to a // function that takes our value as an argument (eg void // (*validate_fn)(bool) for a bool flag). bool Validate(const char* flagname, ValidateFnProto validate_fn_proto) const; void* value_buffer_; // points to the buffer holding our data int8 type_; // how to interpret value_ bool owns_value_; // whether to free value on destruct FlagValue(const FlagValue&); // no copying! void operator=(const FlagValue&); }; // This could be a templated method of FlagValue, but doing so adds to the // size of the .o. Since there's no type-safety here anyway, macro is ok. #define VALUE_AS(type) *reinterpret_cast(value_buffer_) #define OTHER_VALUE_AS(fv, type) *reinterpret_cast(fv.value_buffer_) #define SET_VALUE_AS(type, value) VALUE_AS(type) = (value) FlagValue::FlagValue(void* valbuf, const char* type, bool transfer_ownership_of_value) : value_buffer_(valbuf), owns_value_(transfer_ownership_of_value) { for (type_ = 0; type_ <= FV_MAX_INDEX; ++type_) { if (!strcmp(type, TypeName())) { break; } } assert(type_ <= FV_MAX_INDEX); // Unknown typename } FlagValue::~FlagValue() { if (!owns_value_) { return; } switch (type_) { case FV_BOOL: delete reinterpret_cast(value_buffer_); break; case FV_INT32: delete reinterpret_cast(value_buffer_); break; case FV_INT64: delete reinterpret_cast(value_buffer_); break; case FV_UINT64: delete reinterpret_cast(value_buffer_); break; case FV_DOUBLE: delete reinterpret_cast(value_buffer_); break; case FV_STRING: delete reinterpret_cast(value_buffer_); break; } } bool FlagValue::ParseFrom(const char* value) { if (type_ == FV_BOOL) { const char* kTrue[] = { "1", "t", "true", "y", "yes" }; const char* kFalse[] = { "0", "f", "false", "n", "no" }; COMPILE_ASSERT(sizeof(kTrue) == sizeof(kFalse), true_false_equal); for (size_t i = 0; i < sizeof(kTrue)/sizeof(*kTrue); ++i) { if (strcasecmp(value, kTrue[i]) == 0) { SET_VALUE_AS(bool, true); return true; } else if (strcasecmp(value, kFalse[i]) == 0) { SET_VALUE_AS(bool, false); return true; } } return false; // didn't match a legal input } else if (type_ == FV_STRING) { SET_VALUE_AS(string, value); return true; } // OK, it's likely to be numeric, and we'll be using a strtoXXX method. if (value[0] == '\0') // empty-string is only allowed for string type. return false; char* end; // Leading 0x puts us in base 16. But leading 0 does not put us in base 8! // It caused too many bugs when we had that behavior. int base = 10; // by default if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) base = 16; errno = 0; switch (type_) { case FV_INT32: { const int64 r = strto64(value, &end, base); if (errno || end != value + strlen(value)) return false; // bad parse if (static_cast(r) != r) // worked, but number out of range return false; SET_VALUE_AS(int32, static_cast(r)); return true; } case FV_INT64: { const int64 r = strto64(value, &end, base); if (errno || end != value + strlen(value)) return false; // bad parse SET_VALUE_AS(int64, r); return true; } case FV_UINT64: { while (*value == ' ') value++; if (*value == '-') return false; // negative number const uint64 r = strtou64(value, &end, base); if (errno || end != value + strlen(value)) return false; // bad parse SET_VALUE_AS(uint64, r); return true; } case FV_DOUBLE: { const double r = strtod(value, &end); if (errno || end != value + strlen(value)) return false; // bad parse SET_VALUE_AS(double, r); return true; } default: { assert(false); // unknown type return false; } } } string FlagValue::ToString() const { char intbuf[64]; // enough to hold even the biggest number switch (type_) { case FV_BOOL: return VALUE_AS(bool) ? "true" : "false"; case FV_INT32: snprintf(intbuf, sizeof(intbuf), "%" PRId32, VALUE_AS(int32)); return intbuf; case FV_INT64: snprintf(intbuf, sizeof(intbuf), "%" PRId64, VALUE_AS(int64)); return intbuf; case FV_UINT64: snprintf(intbuf, sizeof(intbuf), "%" PRIu64, VALUE_AS(uint64)); return intbuf; case FV_DOUBLE: snprintf(intbuf, sizeof(intbuf), "%.17g", VALUE_AS(double)); return intbuf; case FV_STRING: return VALUE_AS(string); default: assert(false); return ""; // unknown type } } bool FlagValue::Validate(const char* flagname, ValidateFnProto validate_fn_proto) const { switch (type_) { case FV_BOOL: return reinterpret_cast( validate_fn_proto)(flagname, VALUE_AS(bool)); case FV_INT32: return reinterpret_cast( validate_fn_proto)(flagname, VALUE_AS(int32)); case FV_INT64: return reinterpret_cast( validate_fn_proto)(flagname, VALUE_AS(int64)); case FV_UINT64: return reinterpret_cast( validate_fn_proto)(flagname, VALUE_AS(uint64)); case FV_DOUBLE: return reinterpret_cast( validate_fn_proto)(flagname, VALUE_AS(double)); case FV_STRING: return reinterpret_cast( validate_fn_proto)(flagname, VALUE_AS(string)); default: assert(false); // unknown type return false; } } const char* FlagValue::TypeName() const { static const char types[] = "bool\0xx" "int32\0x" "int64\0x" "uint64\0" "double\0" "string"; if (type_ > FV_MAX_INDEX) { assert(false); return ""; } // Directly indexing the strings in the 'types' string, each of them is 7 bytes long. return &types[type_ * 7]; } bool FlagValue::Equal(const FlagValue& x) const { if (type_ != x.type_) return false; switch (type_) { case FV_BOOL: return VALUE_AS(bool) == OTHER_VALUE_AS(x, bool); case FV_INT32: return VALUE_AS(int32) == OTHER_VALUE_AS(x, int32); case FV_INT64: return VALUE_AS(int64) == OTHER_VALUE_AS(x, int64); case FV_UINT64: return VALUE_AS(uint64) == OTHER_VALUE_AS(x, uint64); case FV_DOUBLE: return VALUE_AS(double) == OTHER_VALUE_AS(x, double); case FV_STRING: return VALUE_AS(string) == OTHER_VALUE_AS(x, string); default: assert(false); return false; // unknown type } } FlagValue* FlagValue::New() const { const char *type = TypeName(); switch (type_) { case FV_BOOL: return new FlagValue(new bool(false), type, true); case FV_INT32: return new FlagValue(new int32(0), type, true); case FV_INT64: return new FlagValue(new int64(0), type, true); case FV_UINT64: return new FlagValue(new uint64(0), type, true); case FV_DOUBLE: return new FlagValue(new double(0.0), type, true); case FV_STRING: return new FlagValue(new string, type, true); default: assert(false); return NULL; // unknown type } } void FlagValue::CopyFrom(const FlagValue& x) { assert(type_ == x.type_); switch (type_) { case FV_BOOL: SET_VALUE_AS(bool, OTHER_VALUE_AS(x, bool)); break; case FV_INT32: SET_VALUE_AS(int32, OTHER_VALUE_AS(x, int32)); break; case FV_INT64: SET_VALUE_AS(int64, OTHER_VALUE_AS(x, int64)); break; case FV_UINT64: SET_VALUE_AS(uint64, OTHER_VALUE_AS(x, uint64)); break; case FV_DOUBLE: SET_VALUE_AS(double, OTHER_VALUE_AS(x, double)); break; case FV_STRING: SET_VALUE_AS(string, OTHER_VALUE_AS(x, string)); break; default: assert(false); // unknown type } } int FlagValue::ValueSize() const { if (type_ > FV_MAX_INDEX) { assert(false); // unknown type return 0; } static const uint8 valuesize[] = { sizeof(bool), sizeof(int32), sizeof(int64), sizeof(uint64), sizeof(double), sizeof(string), }; return valuesize[type_]; } // -------------------------------------------------------------------- // CommandLineFlag // This represents a single flag, including its name, description, // default value, and current value. Mostly this serves as a // struct, though it also knows how to register itself. // All CommandLineFlags are owned by a (exactly one) // FlagRegistry. If you wish to modify fields in this class, you // should acquire the FlagRegistry lock for the registry that owns // this flag. // -------------------------------------------------------------------- class CommandLineFlag { public: // Note: we take over memory-ownership of current_val and default_val. CommandLineFlag(const char* name, const char* help, const char* filename, FlagValue* current_val, FlagValue* default_val); ~CommandLineFlag(); const char* name() const { return name_; } const char* help() const { return help_; } const char* filename() const { return file_; } const char* CleanFileName() const; // nixes irrelevant prefix such as homedir string current_value() const { return current_->ToString(); } string default_value() const { return defvalue_->ToString(); } const char* type_name() const { return defvalue_->TypeName(); } ValidateFnProto validate_function() const { return validate_fn_proto_; } const void* flag_ptr() const { return current_->value_buffer_; } void FillCommandLineFlagInfo(struct CommandLineFlagInfo* result); // If validate_fn_proto_ is non-NULL, calls it on value, returns result. bool Validate(const FlagValue& value) const; bool ValidateCurrent() const { return Validate(*current_); } private: // for SetFlagLocked() and setting flags_by_ptr_ friend class FlagRegistry; friend class GFLAGS_NAMESPACE::FlagSaverImpl; // for cloning the values // set validate_fn friend bool AddFlagValidator(const void*, ValidateFnProto); // This copies all the non-const members: modified, processed, defvalue, etc. void CopyFrom(const CommandLineFlag& src); void UpdateModifiedBit(); const char* const name_; // Flag name const char* const help_; // Help message const char* const file_; // Which file did this come from? bool modified_; // Set after default assignment? FlagValue* defvalue_; // Default value for flag FlagValue* current_; // Current value for flag // This is a casted, 'generic' version of validate_fn, which actually // takes a flag-value as an arg (void (*validate_fn)(bool), say). // When we pass this to current_->Validate(), it will cast it back to // the proper type. This may be NULL to mean we have no validate_fn. ValidateFnProto validate_fn_proto_; CommandLineFlag(const CommandLineFlag&); // no copying! void operator=(const CommandLineFlag&); }; CommandLineFlag::CommandLineFlag(const char* name, const char* help, const char* filename, FlagValue* current_val, FlagValue* default_val) : name_(name), help_(help), file_(filename), modified_(false), defvalue_(default_val), current_(current_val), validate_fn_proto_(NULL) { } CommandLineFlag::~CommandLineFlag() { delete current_; delete defvalue_; } const char* CommandLineFlag::CleanFileName() const { // Compute top-level directory & file that this appears in // search full path backwards. // Stop going backwards at kRootDir; and skip by the first slash. static const char kRootDir[] = ""; // can set this to root directory, if (sizeof(kRootDir)-1 == 0) // no prefix to strip return filename(); const char* clean_name = filename() + strlen(filename()) - 1; while ( clean_name > filename() ) { if (*clean_name == PATH_SEPARATOR) { if (strncmp(clean_name, kRootDir, sizeof(kRootDir)-1) == 0) { clean_name += sizeof(kRootDir)-1; // past root-dir break; } } --clean_name; } while ( *clean_name == PATH_SEPARATOR ) ++clean_name; // Skip any slashes return clean_name; } void CommandLineFlag::FillCommandLineFlagInfo( CommandLineFlagInfo* result) { result->name = name(); result->type = type_name(); result->description = help(); result->current_value = current_value(); result->default_value = default_value(); result->filename = CleanFileName(); UpdateModifiedBit(); result->is_default = !modified_; result->has_validator_fn = validate_function() != NULL; result->flag_ptr = flag_ptr(); } void CommandLineFlag::UpdateModifiedBit() { // Update the "modified" bit in case somebody bypassed the // Flags API and wrote directly through the FLAGS_name variable. if (!modified_ && !current_->Equal(*defvalue_)) { modified_ = true; } } void CommandLineFlag::CopyFrom(const CommandLineFlag& src) { // Note we only copy the non-const members; others are fixed at construct time if (modified_ != src.modified_) modified_ = src.modified_; if (!current_->Equal(*src.current_)) current_->CopyFrom(*src.current_); if (!defvalue_->Equal(*src.defvalue_)) defvalue_->CopyFrom(*src.defvalue_); if (validate_fn_proto_ != src.validate_fn_proto_) validate_fn_proto_ = src.validate_fn_proto_; } bool CommandLineFlag::Validate(const FlagValue& value) const { if (validate_function() == NULL) return true; else return value.Validate(name(), validate_function()); } // -------------------------------------------------------------------- // FlagRegistry // A FlagRegistry singleton object holds all flag objects indexed // by their names so that if you know a flag's name (as a C // string), you can access or set it. If the function is named // FooLocked(), you must own the registry lock before calling // the function; otherwise, you should *not* hold the lock, and // the function will acquire it itself if needed. // -------------------------------------------------------------------- struct StringCmp { // Used by the FlagRegistry map class to compare char*'s bool operator() (const char* s1, const char* s2) const { return (strcmp(s1, s2) < 0); } }; class FlagRegistry { public: FlagRegistry() { } ~FlagRegistry() { // Not using STLDeleteElements as that resides in util and this // class is base. for (FlagMap::iterator p = flags_.begin(), e = flags_.end(); p != e; ++p) { CommandLineFlag* flag = p->second; delete flag; } } static void DeleteGlobalRegistry() { delete global_registry_; global_registry_ = NULL; } // Store a flag in this registry. Takes ownership of the given pointer. void RegisterFlag(CommandLineFlag* flag); void Lock() { lock_.Lock(); } void Unlock() { lock_.Unlock(); } // Returns the flag object for the specified name, or NULL if not found. CommandLineFlag* FindFlagLocked(const char* name); // Returns the flag object whose current-value is stored at flag_ptr. // That is, for whom current_->value_buffer_ == flag_ptr CommandLineFlag* FindFlagViaPtrLocked(const void* flag_ptr); // A fancier form of FindFlag that works correctly if name is of the // form flag=value. In that case, we set key to point to flag, and // modify v to point to the value (if present), and return the flag // with the given name. If the flag does not exist, returns NULL // and sets error_message. CommandLineFlag* SplitArgumentLocked(const char* argument, string* key, const char** v, string* error_message); // Set the value of a flag. If the flag was successfully set to // value, set msg to indicate the new flag-value, and return true. // Otherwise, set msg to indicate the error, leave flag unchanged, // and return false. msg can be NULL. bool SetFlagLocked(CommandLineFlag* flag, const char* value, FlagSettingMode set_mode, string* msg); static FlagRegistry* GlobalRegistry(); // returns a singleton registry private: friend class GFLAGS_NAMESPACE::FlagSaverImpl; // reads all the flags in order to copy them friend class CommandLineFlagParser; // for ValidateAllFlags friend void GFLAGS_NAMESPACE::GetAllFlags(vector*); // The map from name to flag, for FindFlagLocked(). typedef map FlagMap; typedef FlagMap::iterator FlagIterator; typedef FlagMap::const_iterator FlagConstIterator; FlagMap flags_; // The map from current-value pointer to flag, fo FindFlagViaPtrLocked(). typedef map FlagPtrMap; FlagPtrMap flags_by_ptr_; static FlagRegistry* global_registry_; // a singleton registry Mutex lock_; static Mutex global_registry_lock_; static void InitGlobalRegistry(); // Disallow FlagRegistry(const FlagRegistry&); FlagRegistry& operator=(const FlagRegistry&); }; class FlagRegistryLock { public: explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); } ~FlagRegistryLock() { fr_->Unlock(); } private: FlagRegistry *const fr_; }; void FlagRegistry::RegisterFlag(CommandLineFlag* flag) { Lock(); pair ins = flags_.insert(pair(flag->name(), flag)); if (ins.second == false) { // means the name was already in the map if (strcmp(ins.first->second->filename(), flag->filename()) != 0) { ReportError(DIE, "ERROR: flag '%s' was defined more than once " "(in files '%s' and '%s').\n", flag->name(), ins.first->second->filename(), flag->filename()); } else { ReportError(DIE, "ERROR: something wrong with flag '%s' in file '%s'. " "One possibility: file '%s' is being linked both statically " "and dynamically into this executable.\n", flag->name(), flag->filename(), flag->filename()); } } // Also add to the flags_by_ptr_ map. flags_by_ptr_[flag->current_->value_buffer_] = flag; Unlock(); } CommandLineFlag* FlagRegistry::FindFlagLocked(const char* name) { FlagConstIterator i = flags_.find(name); if (i == flags_.end()) { return NULL; } else { return i->second; } } CommandLineFlag* FlagRegistry::FindFlagViaPtrLocked(const void* flag_ptr) { FlagPtrMap::const_iterator i = flags_by_ptr_.find(flag_ptr); if (i == flags_by_ptr_.end()) { return NULL; } else { return i->second; } } CommandLineFlag* FlagRegistry::SplitArgumentLocked(const char* arg, string* key, const char** v, string* error_message) { // Find the flag object for this option const char* flag_name; const char* value = strchr(arg, '='); if (value == NULL) { key->assign(arg); *v = NULL; } else { // Strip out the "=value" portion from arg key->assign(arg, value-arg); *v = ++value; // advance past the '=' } flag_name = key->c_str(); CommandLineFlag* flag = FindFlagLocked(flag_name); if (flag == NULL) { // If we can't find the flag-name, then we should return an error. // The one exception is if 1) the flag-name is 'nox', 2) there // exists a flag named 'x', and 3) 'x' is a boolean flag. // In that case, we want to return flag 'x'. if (!(flag_name[0] == 'n' && flag_name[1] == 'o')) { // flag-name is not 'nox', so we're not in the exception case. *error_message = StringPrintf("%sunknown command line flag '%s'\n", kError, key->c_str()); return NULL; } flag = FindFlagLocked(flag_name+2); if (flag == NULL) { // No flag named 'x' exists, so we're not in the exception case. *error_message = StringPrintf("%sunknown command line flag '%s'\n", kError, key->c_str()); return NULL; } if (strcmp(flag->type_name(), "bool") != 0) { // 'x' exists but is not boolean, so we're not in the exception case. *error_message = StringPrintf( "%sboolean value (%s) specified for %s command line flag\n", kError, key->c_str(), flag->type_name()); return NULL; } // We're in the exception case! // Make up a fake value to replace the "no" we stripped out key->assign(flag_name+2); // the name without the "no" *v = "0"; } // Assign a value if this is a boolean flag if (*v == NULL && strcmp(flag->type_name(), "bool") == 0) { *v = "1"; // the --nox case was already handled, so this is the --x case } return flag; } bool TryParseLocked(const CommandLineFlag* flag, FlagValue* flag_value, const char* value, string* msg) { // Use tenative_value, not flag_value, until we know value is valid. FlagValue* tentative_value = flag_value->New(); if (!tentative_value->ParseFrom(value)) { if (msg) { StringAppendF(msg, "%sillegal value '%s' specified for %s flag '%s'\n", kError, value, flag->type_name(), flag->name()); } delete tentative_value; return false; } else if (!flag->Validate(*tentative_value)) { if (msg) { StringAppendF(msg, "%sfailed validation of new value '%s' for flag '%s'\n", kError, tentative_value->ToString().c_str(), flag->name()); } delete tentative_value; return false; } else { flag_value->CopyFrom(*tentative_value); if (msg) { StringAppendF(msg, "%s set to %s\n", flag->name(), flag_value->ToString().c_str()); } delete tentative_value; return true; } } bool FlagRegistry::SetFlagLocked(CommandLineFlag* flag, const char* value, FlagSettingMode set_mode, string* msg) { flag->UpdateModifiedBit(); switch (set_mode) { case SET_FLAGS_VALUE: { // set or modify the flag's value if (!TryParseLocked(flag, flag->current_, value, msg)) return false; flag->modified_ = true; break; } case SET_FLAG_IF_DEFAULT: { // set the flag's value, but only if it hasn't been set by someone else if (!flag->modified_) { if (!TryParseLocked(flag, flag->current_, value, msg)) return false; flag->modified_ = true; } else { *msg = StringPrintf("%s set to %s", flag->name(), flag->current_value().c_str()); } break; } case SET_FLAGS_DEFAULT: { // modify the flag's default-value if (!TryParseLocked(flag, flag->defvalue_, value, msg)) return false; if (!flag->modified_) { // Need to set both defvalue *and* current, in this case TryParseLocked(flag, flag->current_, value, NULL); } break; } default: { // unknown set_mode assert(false); return false; } } return true; } // Get the singleton FlagRegistry object FlagRegistry* FlagRegistry::global_registry_ = NULL; Mutex FlagRegistry::global_registry_lock_(Mutex::LINKER_INITIALIZED); FlagRegistry* FlagRegistry::GlobalRegistry() { MutexLock acquire_lock(&global_registry_lock_); if (!global_registry_) { global_registry_ = new FlagRegistry; } return global_registry_; } // -------------------------------------------------------------------- // CommandLineFlagParser // Parsing is done in two stages. In the first, we go through // argv. For every flag-like arg we can make sense of, we parse // it and set the appropriate FLAGS_* variable. For every flag- // like arg we can't make sense of, we store it in a vector, // along with an explanation of the trouble. In stage 2, we // handle the 'reporting' flags like --help and --mpm_version. // (This is via a call to HandleCommandLineHelpFlags(), in // gflags_reporting.cc.) // An optional stage 3 prints out the error messages. // This is a bit of a simplification. For instance, --flagfile // is handled as soon as it's seen in stage 1, not in stage 2. // -------------------------------------------------------------------- class CommandLineFlagParser { public: // The argument is the flag-registry to register the parsed flags in explicit CommandLineFlagParser(FlagRegistry* reg) : registry_(reg) {} ~CommandLineFlagParser() {} // Stage 1: Every time this is called, it reads all flags in argv. // However, it ignores all flags that have been successfully set // before. Typically this is only called once, so this 'reparsing' // behavior isn't important. It can be useful when trying to // reparse after loading a dll, though. uint32 ParseNewCommandLineFlags(int* argc, char*** argv, bool remove_flags); // Stage 2: print reporting info and exit, if requested. // In gflags_reporting.cc:HandleCommandLineHelpFlags(). // Stage 3: validate all the commandline flags that have validators // registered. void ValidateAllFlags(); // Stage 4: report any errors and return true if any were found. bool ReportErrors(); // Set a particular command line option. "newval" is a string // describing the new value that the option has been set to. If // option_name does not specify a valid option name, or value is not // a valid value for option_name, newval is empty. Does recursive // processing for --flagfile and --fromenv. Returns the new value // if everything went ok, or empty-string if not. (Actually, the // return-string could hold many flag/value pairs due to --flagfile.) // NB: Must have called registry_->Lock() before calling this function. string ProcessSingleOptionLocked(CommandLineFlag* flag, const char* value, FlagSettingMode set_mode); // Set a whole batch of command line options as specified by contentdata, // which is in flagfile format (and probably has been read from a flagfile). // Returns the new value if everything went ok, or empty-string if // not. (Actually, the return-string could hold many flag/value // pairs due to --flagfile.) // NB: Must have called registry_->Lock() before calling this function. string ProcessOptionsFromStringLocked(const string& contentdata, FlagSettingMode set_mode); // These are the 'recursive' flags, defined at the top of this file. // Whenever we see these flags on the commandline, we must take action. // These are called by ProcessSingleOptionLocked and, similarly, return // new values if everything went ok, or the empty-string if not. string ProcessFlagfileLocked(const string& flagval, FlagSettingMode set_mode); // diff fromenv/tryfromenv string ProcessFromenvLocked(const string& flagval, FlagSettingMode set_mode, bool errors_are_fatal); private: FlagRegistry* const registry_; map error_flags_; // map from name to error message // This could be a set, but we reuse the map to minimize the .o size map undefined_names_; // --[flag] name was not registered }; // Parse a list of (comma-separated) flags. static void ParseFlagList(const char* value, vector* flags) { for (const char *p = value; p && *p; value = p) { p = strchr(value, ','); size_t len; if (p) { len = p - value; p++; } else { len = strlen(value); } if (len == 0) ReportError(DIE, "ERROR: empty flaglist entry\n"); if (value[0] == '-') ReportError(DIE, "ERROR: flag \"%*s\" begins with '-'\n", len, value); flags->push_back(string(value, len)); } } // Snarf an entire file into a C++ string. This is just so that we // can do all the I/O in one place and not worry about it everywhere. // Plus, it's convenient to have the whole file contents at hand. // Adds a newline at the end of the file. #define PFATAL(s) do { perror(s); gflags_exitfunc(1); } while (0) static string ReadFileIntoString(const char* filename) { const int kBufSize = 8092; char buffer[kBufSize]; string s; FILE* fp; if ((errno = SafeFOpen(&fp, filename, "r")) != 0) PFATAL(filename); size_t n; while ( (n=fread(buffer, 1, kBufSize, fp)) > 0 ) { if (ferror(fp)) PFATAL(filename); s.append(buffer, n); } fclose(fp); return s; } uint32 CommandLineFlagParser::ParseNewCommandLineFlags(int* argc, char*** argv, bool remove_flags) { const char *program_name = strrchr((*argv)[0], PATH_SEPARATOR); // nix path program_name = (program_name == NULL ? (*argv)[0] : program_name+1); int first_nonopt = *argc; // for non-options moved to the end registry_->Lock(); for (int i = 1; i < first_nonopt; i++) { char* arg = (*argv)[i]; // Like getopt(), we permute non-option flags to be at the end. if (arg[0] != '-' || // must be a program argument (arg[0] == '-' && arg[1] == '\0')) { // "-" is an argument, not a flag memmove((*argv) + i, (*argv) + i+1, (*argc - (i+1)) * sizeof((*argv)[i])); (*argv)[*argc-1] = arg; // we go last first_nonopt--; // we've been pushed onto the stack i--; // to undo the i++ in the loop continue; } if (arg[0] == '-') arg++; // allow leading '-' if (arg[0] == '-') arg++; // or leading '--' // -- alone means what it does for GNU: stop options parsing if (*arg == '\0') { first_nonopt = i+1; break; } // Find the flag object for this option string key; const char* value; string error_message; CommandLineFlag* flag = registry_->SplitArgumentLocked(arg, &key, &value, &error_message); if (flag == NULL) { undefined_names_[key] = ""; // value isn't actually used error_flags_[key] = error_message; continue; } if (value == NULL) { // Boolean options are always assigned a value by SplitArgumentLocked() assert(strcmp(flag->type_name(), "bool") != 0); if (i+1 >= first_nonopt) { // This flag needs a value, but there is nothing available error_flags_[key] = (string(kError) + "flag '" + (*argv)[i] + "'" + " is missing its argument"); if (flag->help() && flag->help()[0] > '\001') { // Be useful in case we have a non-stripped description. error_flags_[key] += string("; flag description: ") + flag->help(); } error_flags_[key] += "\n"; break; // we treat this as an unrecoverable error } else { value = (*argv)[++i]; // read next arg for value // Heuristic to detect the case where someone treats a string arg // like a bool: // --my_string_var --foo=bar // We look for a flag of string type, whose value begins with a // dash, and where the flag-name and value are separated by a // space rather than an '='. // To avoid false positives, we also require the word "true" // or "false" in the help string. Without this, a valid usage // "-lat -30.5" would trigger the warning. The common cases we // want to solve talk about true and false as values. if (value[0] == '-' && strcmp(flag->type_name(), "string") == 0 && (strstr(flag->help(), "true") || strstr(flag->help(), "false"))) { LOG(WARNING) << "Did you really mean to set flag '" << flag->name() << "' to the value '" << value << "'?"; } } } // TODO(csilvers): only set a flag if we hadn't set it before here ProcessSingleOptionLocked(flag, value, SET_FLAGS_VALUE); } registry_->Unlock(); if (remove_flags) { // Fix up argc and argv by removing command line flags (*argv)[first_nonopt-1] = (*argv)[0]; (*argv) += (first_nonopt-1); (*argc) -= (first_nonopt-1); first_nonopt = 1; // because we still don't count argv[0] } logging_is_probably_set_up = true; // because we've parsed --logdir, etc. return first_nonopt; } string CommandLineFlagParser::ProcessFlagfileLocked(const string& flagval, FlagSettingMode set_mode) { if (flagval.empty()) return ""; string msg; vector filename_list; ParseFlagList(flagval.c_str(), &filename_list); // take a list of filenames for (size_t i = 0; i < filename_list.size(); ++i) { const char* file = filename_list[i].c_str(); msg += ProcessOptionsFromStringLocked(ReadFileIntoString(file), set_mode); } return msg; } string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval, FlagSettingMode set_mode, bool errors_are_fatal) { if (flagval.empty()) return ""; string msg; vector flaglist; ParseFlagList(flagval.c_str(), &flaglist); for (size_t i = 0; i < flaglist.size(); ++i) { const char* flagname = flaglist[i].c_str(); CommandLineFlag* flag = registry_->FindFlagLocked(flagname); if (flag == NULL) { error_flags_[flagname] = StringPrintf("%sunknown command line flag '%s' " "(via --fromenv or --tryfromenv)\n", kError, flagname); undefined_names_[flagname] = ""; continue; } const string envname = string("FLAGS_") + string(flagname); string envval; if (!SafeGetEnv(envname.c_str(), envval)) { if (errors_are_fatal) { error_flags_[flagname] = (string(kError) + envname + " not found in environment\n"); } continue; } // Avoid infinite recursion. if (envval == "fromenv" || envval == "tryfromenv") { error_flags_[flagname] = StringPrintf("%sinfinite recursion on environment flag '%s'\n", kError, envval.c_str()); continue; } msg += ProcessSingleOptionLocked(flag, envval.c_str(), set_mode); } return msg; } string CommandLineFlagParser::ProcessSingleOptionLocked( CommandLineFlag* flag, const char* value, FlagSettingMode set_mode) { string msg; if (value && !registry_->SetFlagLocked(flag, value, set_mode, &msg)) { error_flags_[flag->name()] = msg; return ""; } // The recursive flags, --flagfile and --fromenv and --tryfromenv, // must be dealt with as soon as they're seen. They will emit // messages of their own. if (strcmp(flag->name(), "flagfile") == 0) { msg += ProcessFlagfileLocked(FLAGS_flagfile, set_mode); } else if (strcmp(flag->name(), "fromenv") == 0) { // last arg indicates envval-not-found is fatal (unlike in --tryfromenv) msg += ProcessFromenvLocked(FLAGS_fromenv, set_mode, true); } else if (strcmp(flag->name(), "tryfromenv") == 0) { msg += ProcessFromenvLocked(FLAGS_tryfromenv, set_mode, false); } return msg; } void CommandLineFlagParser::ValidateAllFlags() { FlagRegistryLock frl(registry_); for (FlagRegistry::FlagConstIterator i = registry_->flags_.begin(); i != registry_->flags_.end(); ++i) { if (!i->second->ValidateCurrent()) { // only set a message if one isn't already there. (If there's // an error message, our job is done, even if it's not exactly // the same error.) if (error_flags_[i->second->name()].empty()) error_flags_[i->second->name()] = string(kError) + "--" + i->second->name() + " must be set on the commandline" " (default value fails validation)\n"; } } } bool CommandLineFlagParser::ReportErrors() { // error_flags_ indicates errors we saw while parsing. // But we ignore undefined-names if ok'ed by --undef_ok if (!FLAGS_undefok.empty()) { vector flaglist; ParseFlagList(FLAGS_undefok.c_str(), &flaglist); for (size_t i = 0; i < flaglist.size(); ++i) { // We also deal with --no, in case the flagname was boolean const string no_version = string("no") + flaglist[i]; if (undefined_names_.find(flaglist[i]) != undefined_names_.end()) { error_flags_[flaglist[i]] = ""; // clear the error message } else if (undefined_names_.find(no_version) != undefined_names_.end()) { error_flags_[no_version] = ""; } } } // Likewise, if they decided to allow reparsing, all undefined-names // are ok; we just silently ignore them now, and hope that a future // parse will pick them up somehow. if (allow_command_line_reparsing) { for (map::const_iterator it = undefined_names_.begin(); it != undefined_names_.end(); ++it) error_flags_[it->first] = ""; // clear the error message } bool found_error = false; string error_message; for (map::const_iterator it = error_flags_.begin(); it != error_flags_.end(); ++it) { if (!it->second.empty()) { error_message.append(it->second.data(), it->second.size()); found_error = true; } } if (found_error) ReportError(DO_NOT_DIE, "%s", error_message.c_str()); return found_error; } string CommandLineFlagParser::ProcessOptionsFromStringLocked( const string& contentdata, FlagSettingMode set_mode) { string retval; const char* flagfile_contents = contentdata.c_str(); bool flags_are_relevant = true; // set to false when filenames don't match bool in_filename_section = false; const char* line_end = flagfile_contents; // We read this file a line at a time. for (; line_end; flagfile_contents = line_end + 1) { while (*flagfile_contents && isspace(*flagfile_contents)) ++flagfile_contents; line_end = strchr(flagfile_contents, '\n'); size_t len = line_end ? line_end - flagfile_contents : strlen(flagfile_contents); string line(flagfile_contents, len); // Each line can be one of four things: // 1) A comment line -- we skip it // 2) An empty line -- we skip it // 3) A list of filenames -- starts a new filenames+flags section // 4) A --flag=value line -- apply if previous filenames match if (line.empty() || line[0] == '#') { // comment or empty line; just ignore } else if (line[0] == '-') { // flag in_filename_section = false; // instead, it was a flag-line if (!flags_are_relevant) // skip this flag; applies to someone else continue; const char* name_and_val = line.c_str() + 1; // skip the leading - if (*name_and_val == '-') name_and_val++; // skip second - too string key; const char* value; string error_message; CommandLineFlag* flag = registry_->SplitArgumentLocked(name_and_val, &key, &value, &error_message); // By API, errors parsing flagfile lines are silently ignored. if (flag == NULL) { // "WARNING: flagname '" + key + "' not found\n" } else if (value == NULL) { // "WARNING: flagname '" + key + "' missing a value\n" } else { retval += ProcessSingleOptionLocked(flag, value, set_mode); } } else { // a filename! if (!in_filename_section) { // start over: assume filenames don't match in_filename_section = true; flags_are_relevant = false; } // Split the line up at spaces into glob-patterns const char* space = line.c_str(); // just has to be non-NULL for (const char* word = line.c_str(); *space; word = space+1) { if (flags_are_relevant) // we can stop as soon as we match break; space = strchr(word, ' '); if (space == NULL) space = word + strlen(word); const string glob(word, space - word); // We try matching both against the full argv0 and basename(argv0) if (glob == ProgramInvocationName() // small optimization || glob == ProgramInvocationShortName() #if defined(HAVE_FNMATCH_H) || fnmatch(glob.c_str(), ProgramInvocationName(), FNM_PATHNAME) == 0 || fnmatch(glob.c_str(), ProgramInvocationShortName(), FNM_PATHNAME) == 0 #elif defined(HAVE_SHLWAPI_H) || PathMatchSpec(glob.c_str(), ProgramInvocationName()) || PathMatchSpec(glob.c_str(), ProgramInvocationShortName()) #endif ) { flags_are_relevant = true; } } } } return retval; } // -------------------------------------------------------------------- // GetFromEnv() // AddFlagValidator() // These are helper functions for routines like BoolFromEnv() and // RegisterFlagValidator, defined below. They're defined here so // they can live in the unnamed namespace (which makes friendship // declarations for these classes possible). // -------------------------------------------------------------------- template T GetFromEnv(const char *varname, const char* type, T dflt) { std::string valstr; if (SafeGetEnv(varname, valstr)) { FlagValue ifv(new T, type, true); if (!ifv.ParseFrom(valstr.c_str())) { ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n", varname, valstr.c_str()); } return OTHER_VALUE_AS(ifv, T); } else return dflt; } bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) { // We want a lock around this routine, in case two threads try to // add a validator (hopefully the same one!) at once. We could use // our own thread, but we need to loook at the registry anyway, so // we just steal that one. FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); // First, find the flag whose current-flag storage is 'flag'. // This is the CommandLineFlag whose current_->value_buffer_ == flag CommandLineFlag* flag = registry->FindFlagViaPtrLocked(flag_ptr); if (!flag) { LOG(WARNING) << "Ignoring RegisterValidateFunction() for flag pointer " << flag_ptr << ": no flag found at that address"; return false; } else if (validate_fn_proto == flag->validate_function()) { return true; // ok to register the same function over and over again } else if (validate_fn_proto != NULL && flag->validate_function() != NULL) { LOG(WARNING) << "Ignoring RegisterValidateFunction() for flag '" << flag->name() << "': validate-fn already registered"; return false; } else { flag->validate_fn_proto_ = validate_fn_proto; return true; } } } // end unnamed namespaces // Now define the functions that are exported via the .h file // -------------------------------------------------------------------- // FlagRegisterer // This class exists merely to have a global constructor (the // kind that runs before main(), that goes an initializes each // flag that's been declared. Note that it's very important we // don't have a destructor that deletes flag_, because that would // cause us to delete current_storage/defvalue_storage as well, // which can cause a crash if anything tries to access the flag // values in a global destructor. // -------------------------------------------------------------------- FlagRegisterer::FlagRegisterer(const char* name, const char* type, const char* help, const char* filename, void* current_storage, void* defvalue_storage) { if (help == NULL) help = ""; // FlagValue expects the type-name to not include any namespace // components, so we get rid of those, if any. if (strchr(type, ':')) type = strrchr(type, ':') + 1; FlagValue* current = new FlagValue(current_storage, type, false); FlagValue* defvalue = new FlagValue(defvalue_storage, type, false); // Importantly, flag_ will never be deleted, so storage is always good. CommandLineFlag* flag = new CommandLineFlag(name, help, filename, current, defvalue); FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry } // -------------------------------------------------------------------- // GetAllFlags() // The main way the FlagRegistry class exposes its data. This // returns, as strings, all the info about all the flags in // the main registry, sorted first by filename they are defined // in, and then by flagname. // -------------------------------------------------------------------- struct FilenameFlagnameCmp { bool operator()(const CommandLineFlagInfo& a, const CommandLineFlagInfo& b) const { int cmp = strcmp(a.filename.c_str(), b.filename.c_str()); if (cmp == 0) cmp = strcmp(a.name.c_str(), b.name.c_str()); // secondary sort key return cmp < 0; } }; void GetAllFlags(vector* OUTPUT) { FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); registry->Lock(); for (FlagRegistry::FlagConstIterator i = registry->flags_.begin(); i != registry->flags_.end(); ++i) { CommandLineFlagInfo fi; i->second->FillCommandLineFlagInfo(&fi); OUTPUT->push_back(fi); } registry->Unlock(); // Now sort the flags, first by filename they occur in, then alphabetically sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameCmp()); } // -------------------------------------------------------------------- // SetArgv() // GetArgvs() // GetArgv() // GetArgv0() // ProgramInvocationName() // ProgramInvocationShortName() // SetUsageMessage() // ProgramUsage() // Functions to set and get argv. Typically the setter is called // by ParseCommandLineFlags. Also can get the ProgramUsage string, // set by SetUsageMessage. // -------------------------------------------------------------------- // These values are not protected by a Mutex because they are normally // set only once during program startup. static const char* argv0 = "UNKNOWN"; // just the program name static const char* cmdline = ""; // the entire command-line static vector argvs; static uint32 argv_sum = 0; static const char* program_usage = NULL; void SetArgv(int argc, const char** argv) { static bool called_set_argv = false; if (called_set_argv) // we already have an argv for you return; called_set_argv = true; assert(argc > 0); // every program has at least a progname argv0 = strdup(argv[0]); // small memory leak, but fn only called once assert(argv0); string cmdline_string; // easier than doing strcats for (int i = 0; i < argc; i++) { if (i != 0) { cmdline_string += " "; } cmdline_string += argv[i]; argvs.push_back(argv[i]); } cmdline = strdup(cmdline_string.c_str()); // another small memory leak assert(cmdline); // Compute a simple sum of all the chars in argv for (const char* c = cmdline; *c; c++) argv_sum += *c; } const vector& GetArgvs() { return argvs; } const char* GetArgv() { return cmdline; } const char* GetArgv0() { return argv0; } uint32 GetArgvSum() { return argv_sum; } const char* ProgramInvocationName() { // like the GNU libc fn return GetArgv0(); } const char* ProgramInvocationShortName() { // like the GNU libc fn const char* slash = strrchr(argv0, '/'); #ifdef OS_WINDOWS if (!slash) slash = strrchr(argv0, '\\'); #endif return slash ? slash + 1 : argv0; } void SetUsageMessage(const string& usage) { if (program_usage != NULL) ReportError(DIE, "ERROR: SetUsageMessage() called twice\n"); program_usage = strdup(usage.c_str()); // small memory leak } const char* ProgramUsage() { if (program_usage) { return program_usage; } return "Warning: SetUsageMessage() never called"; } // -------------------------------------------------------------------- // SetVersionString() // VersionString() // -------------------------------------------------------------------- static const char* version_string = NULL; void SetVersionString(const string& version) { if (version_string != NULL) ReportError(DIE, "ERROR: SetVersionString() called twice\n"); version_string = strdup(version.c_str()); // small memory leak } const char* VersionString() { return version_string ? version_string : ""; } // -------------------------------------------------------------------- // GetCommandLineOption() // GetCommandLineFlagInfo() // GetCommandLineFlagInfoOrDie() // SetCommandLineOption() // SetCommandLineOptionWithMode() // The programmatic way to set a flag's value, using a string // for its name rather than the variable itself (that is, // SetCommandLineOption("foo", x) rather than FLAGS_foo = x). // There's also a bit more flexibility here due to the various // set-modes, but typically these are used when you only have // that flag's name as a string, perhaps at runtime. // All of these work on the default, global registry. // For GetCommandLineOption, return false if no such flag // is known, true otherwise. We clear "value" if a suitable // flag is found. // -------------------------------------------------------------------- bool GetCommandLineOption(const char* name, string* value) { if (NULL == name) return false; assert(value); FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); CommandLineFlag* flag = registry->FindFlagLocked(name); if (flag == NULL) { return false; } else { *value = flag->current_value(); return true; } } bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) { if (NULL == name) return false; FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); CommandLineFlag* flag = registry->FindFlagLocked(name); if (flag == NULL) { return false; } else { assert(OUTPUT); flag->FillCommandLineFlagInfo(OUTPUT); return true; } } CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) { CommandLineFlagInfo info; if (!GetCommandLineFlagInfo(name, &info)) { fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exist\n", name); gflags_exitfunc(1); // almost certainly gflags_exitfunc() } return info; } string SetCommandLineOptionWithMode(const char* name, const char* value, FlagSettingMode set_mode) { string result; FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); CommandLineFlag* flag = registry->FindFlagLocked(name); if (flag) { CommandLineFlagParser parser(registry); result = parser.ProcessSingleOptionLocked(flag, value, set_mode); if (!result.empty()) { // in the error case, we've already logged // Could consider logging this change } } // The API of this function is that we return empty string on error return result; } string SetCommandLineOption(const char* name, const char* value) { return SetCommandLineOptionWithMode(name, value, SET_FLAGS_VALUE); } // -------------------------------------------------------------------- // FlagSaver // FlagSaverImpl // This class stores the states of all flags at construct time, // and restores all flags to that state at destruct time. // Its major implementation challenge is that it never modifies // pointers in the 'main' registry, so global FLAG_* vars always // point to the right place. // -------------------------------------------------------------------- class FlagSaverImpl { public: // Constructs an empty FlagSaverImpl object. explicit FlagSaverImpl(FlagRegistry* main_registry) : main_registry_(main_registry) { } ~FlagSaverImpl() { // reclaim memory from each of our CommandLineFlags vector::const_iterator it; for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) delete *it; } // Saves the flag states from the flag registry into this object. // It's an error to call this more than once. // Must be called when the registry mutex is not held. void SaveFromRegistry() { FlagRegistryLock frl(main_registry_); assert(backup_registry_.empty()); // call only once! for (FlagRegistry::FlagConstIterator it = main_registry_->flags_.begin(); it != main_registry_->flags_.end(); ++it) { const CommandLineFlag* main = it->second; // Sets up all the const variables in backup correctly CommandLineFlag* backup = new CommandLineFlag( main->name(), main->help(), main->filename(), main->current_->New(), main->defvalue_->New()); // Sets up all the non-const variables in backup correctly backup->CopyFrom(*main); backup_registry_.push_back(backup); // add it to a convenient list } } // Restores the saved flag states into the flag registry. We // assume no flags were added or deleted from the registry since // the SaveFromRegistry; if they were, that's trouble! Must be // called when the registry mutex is not held. void RestoreToRegistry() { FlagRegistryLock frl(main_registry_); vector::const_iterator it; for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) { CommandLineFlag* main = main_registry_->FindFlagLocked((*it)->name()); if (main != NULL) { // if NULL, flag got deleted from registry(!) main->CopyFrom(**it); } } } private: FlagRegistry* const main_registry_; vector backup_registry_; FlagSaverImpl(const FlagSaverImpl&); // no copying! void operator=(const FlagSaverImpl&); }; FlagSaver::FlagSaver() : impl_(new FlagSaverImpl(FlagRegistry::GlobalRegistry())) { impl_->SaveFromRegistry(); } FlagSaver::~FlagSaver() { impl_->RestoreToRegistry(); delete impl_; } // -------------------------------------------------------------------- // CommandlineFlagsIntoString() // ReadFlagsFromString() // AppendFlagsIntoFile() // ReadFromFlagsFile() // These are mostly-deprecated routines that stick the // commandline flags into a file/string and read them back // out again. I can see a use for CommandlineFlagsIntoString, // for creating a flagfile, but the rest don't seem that useful // -- some, I think, are a poor-man's attempt at FlagSaver -- // and are included only until we can delete them from callers. // Note they don't save --flagfile flags (though they do save // the result of having called the flagfile, of course). // -------------------------------------------------------------------- static string TheseCommandlineFlagsIntoString( const vector& flags) { vector::const_iterator i; size_t retval_space = 0; for (i = flags.begin(); i != flags.end(); ++i) { // An (over)estimate of how much space it will take to print this flag retval_space += i->name.length() + i->current_value.length() + 5; } string retval; retval.reserve(retval_space); for (i = flags.begin(); i != flags.end(); ++i) { retval += "--"; retval += i->name; retval += "="; retval += i->current_value; retval += "\n"; } return retval; } string CommandlineFlagsIntoString() { vector sorted_flags; GetAllFlags(&sorted_flags); return TheseCommandlineFlagsIntoString(sorted_flags); } bool ReadFlagsFromString(const string& flagfilecontents, const char* /*prog_name*/, // TODO(csilvers): nix this bool errors_are_fatal) { FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); FlagSaverImpl saved_states(registry); saved_states.SaveFromRegistry(); CommandLineFlagParser parser(registry); registry->Lock(); parser.ProcessOptionsFromStringLocked(flagfilecontents, SET_FLAGS_VALUE); registry->Unlock(); // Should we handle --help and such when reading flags from a string? Sure. HandleCommandLineHelpFlags(); if (parser.ReportErrors()) { // Error. Restore all global flags to their previous values. if (errors_are_fatal) gflags_exitfunc(1); saved_states.RestoreToRegistry(); return false; } return true; } // TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName() bool AppendFlagsIntoFile(const string& filename, const char *prog_name) { FILE *fp; if (SafeFOpen(&fp, filename.c_str(), "a") != 0) { return false; } if (prog_name) fprintf(fp, "%s\n", prog_name); vector flags; GetAllFlags(&flags); // But we don't want --flagfile, which leads to weird recursion issues vector::iterator i; for (i = flags.begin(); i != flags.end(); ++i) { if (strcmp(i->name.c_str(), "flagfile") == 0) { flags.erase(i); break; } } fprintf(fp, "%s", TheseCommandlineFlagsIntoString(flags).c_str()); fclose(fp); return true; } bool ReadFromFlagsFile(const string& filename, const char* prog_name, bool errors_are_fatal) { return ReadFlagsFromString(ReadFileIntoString(filename.c_str()), prog_name, errors_are_fatal); } // -------------------------------------------------------------------- // BoolFromEnv() // Int32FromEnv() // Int64FromEnv() // Uint64FromEnv() // DoubleFromEnv() // StringFromEnv() // Reads the value from the environment and returns it. // We use an FlagValue to make the parsing easy. // Example usage: // DEFINE_bool(myflag, BoolFromEnv("MYFLAG_DEFAULT", false), "whatever"); // -------------------------------------------------------------------- bool BoolFromEnv(const char *v, bool dflt) { return GetFromEnv(v, "bool", dflt); } int32 Int32FromEnv(const char *v, int32 dflt) { return GetFromEnv(v, "int32", dflt); } int64 Int64FromEnv(const char *v, int64 dflt) { return GetFromEnv(v, "int64", dflt); } uint64 Uint64FromEnv(const char *v, uint64 dflt) { return GetFromEnv(v, "uint64", dflt); } double DoubleFromEnv(const char *v, double dflt) { return GetFromEnv(v, "double", dflt); } #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4996) // ignore getenv security warning #endif const char *StringFromEnv(const char *varname, const char *dflt) { const char* const val = getenv(varname); return val ? val : dflt; } #ifdef _MSC_VER # pragma warning(pop) #endif // -------------------------------------------------------------------- // RegisterFlagValidator() // RegisterFlagValidator() is the function that clients use to // 'decorate' a flag with a validation function. Once this is // done, every time the flag is set (including when the flag // is parsed from argv), the validator-function is called. // These functions return true if the validator was added // successfully, or false if not: the flag already has a validator, // (only one allowed per flag), the 1st arg isn't a flag, etc. // This function is not thread-safe. // -------------------------------------------------------------------- bool RegisterFlagValidator(const bool* flag, bool (*validate_fn)(const char*, bool)) { return AddFlagValidator(flag, reinterpret_cast(validate_fn)); } bool RegisterFlagValidator(const int32* flag, bool (*validate_fn)(const char*, int32)) { return AddFlagValidator(flag, reinterpret_cast(validate_fn)); } bool RegisterFlagValidator(const int64* flag, bool (*validate_fn)(const char*, int64)) { return AddFlagValidator(flag, reinterpret_cast(validate_fn)); } bool RegisterFlagValidator(const uint64* flag, bool (*validate_fn)(const char*, uint64)) { return AddFlagValidator(flag, reinterpret_cast(validate_fn)); } bool RegisterFlagValidator(const double* flag, bool (*validate_fn)(const char*, double)) { return AddFlagValidator(flag, reinterpret_cast(validate_fn)); } bool RegisterFlagValidator(const string* flag, bool (*validate_fn)(const char*, const string&)) { return AddFlagValidator(flag, reinterpret_cast(validate_fn)); } // -------------------------------------------------------------------- // ParseCommandLineFlags() // ParseCommandLineNonHelpFlags() // HandleCommandLineHelpFlags() // This is the main function called from main(), to actually // parse the commandline. It modifies argc and argv as described // at the top of gflags.h. You can also divide this // function into two parts, if you want to do work between // the parsing of the flags and the printing of any help output. // -------------------------------------------------------------------- static uint32 ParseCommandLineFlagsInternal(int* argc, char*** argv, bool remove_flags, bool do_report) { SetArgv(*argc, const_cast(*argv)); // save it for later FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); CommandLineFlagParser parser(registry); // When we parse the commandline flags, we'll handle --flagfile, // --tryfromenv, etc. as we see them (since flag-evaluation order // may be important). But sometimes apps set FLAGS_tryfromenv/etc. // manually before calling ParseCommandLineFlags. We want to evaluate // those too, as if they were the first flags on the commandline. registry->Lock(); parser.ProcessFlagfileLocked(FLAGS_flagfile, SET_FLAGS_VALUE); // Last arg here indicates whether flag-not-found is a fatal error or not parser.ProcessFromenvLocked(FLAGS_fromenv, SET_FLAGS_VALUE, true); parser.ProcessFromenvLocked(FLAGS_tryfromenv, SET_FLAGS_VALUE, false); registry->Unlock(); // Now get the flags specified on the commandline const int r = parser.ParseNewCommandLineFlags(argc, argv, remove_flags); if (do_report) HandleCommandLineHelpFlags(); // may cause us to exit on --help, etc. // See if any of the unset flags fail their validation checks parser.ValidateAllFlags(); if (parser.ReportErrors()) // may cause us to exit on illegal flags gflags_exitfunc(1); return r; } uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) { return ParseCommandLineFlagsInternal(argc, argv, remove_flags, true); } uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv, bool remove_flags) { return ParseCommandLineFlagsInternal(argc, argv, remove_flags, false); } // -------------------------------------------------------------------- // AllowCommandLineReparsing() // ReparseCommandLineNonHelpFlags() // This is most useful for shared libraries. The idea is if // a flag is defined in a shared library that is dlopen'ed // sometime after main(), you can ParseCommandLineFlags before // the dlopen, then ReparseCommandLineNonHelpFlags() after the // dlopen, to get the new flags. But you have to explicitly // Allow() it; otherwise, you get the normal default behavior // of unrecognized flags calling a fatal error. // TODO(csilvers): this isn't used. Just delete it? // -------------------------------------------------------------------- void AllowCommandLineReparsing() { allow_command_line_reparsing = true; } void ReparseCommandLineNonHelpFlags() { // We make a copy of argc and argv to pass in const vector& argvs = GetArgvs(); int tmp_argc = static_cast(argvs.size()); char** tmp_argv = new char* [tmp_argc + 1]; for (int i = 0; i < tmp_argc; ++i) tmp_argv[i] = strdup(argvs[i].c_str()); // TODO(csilvers): don't dup ParseCommandLineNonHelpFlags(&tmp_argc, &tmp_argv, false); for (int i = 0; i < tmp_argc; ++i) free(tmp_argv[i]); delete[] tmp_argv; } void ShutDownCommandLineFlags() { FlagRegistry::DeleteGlobalRegistry(); } } // namespace GFLAGS_NAMESPACE gflags-2.1.2/src/gflags.h.in000066400000000000000000000671211250430723500155770ustar00rootroot00000000000000// Copyright (c) 2006, 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. // --- // Revamped and reorganized by Craig Silverstein // // This is the file that should be included by any file which declares // or defines a command line flag or wants to parse command line flags // or print a program usage message (which will include information about // flags). Executive summary, in the form of an example foo.cc file: // // #include "foo.h" // foo.h has a line "DECLARE_int32(start);" // #include "validators.h" // hypothetical file defining ValidateIsFile() // // DEFINE_int32(end, 1000, "The last record to read"); // // DEFINE_string(filename, "my_file.txt", "The file to read"); // // Crash if the specified file does not exist. // static bool dummy = RegisterFlagValidator(&FLAGS_filename, // &ValidateIsFile); // // DECLARE_bool(verbose); // some other file has a DEFINE_bool(verbose, ...) // // void MyFunc() { // if (FLAGS_verbose) printf("Records %d-%d\n", FLAGS_start, FLAGS_end); // } // // Then, at the command-line: // ./foo --noverbose --start=5 --end=100 // // For more details, see // doc/gflags.html // // --- A note about thread-safety: // // We describe many functions in this routine as being thread-hostile, // thread-compatible, or thread-safe. Here are the meanings we use: // // thread-safe: it is safe for multiple threads to call this routine // (or, when referring to a class, methods of this class) // concurrently. // thread-hostile: it is not safe for multiple threads to call this // routine (or methods of this class) concurrently. In gflags, // most thread-hostile routines are intended to be called early in, // or even before, main() -- that is, before threads are spawned. // thread-compatible: it is safe for multiple threads to read from // this variable (when applied to variables), or to call const // methods of this class (when applied to classes), as long as no // other thread is writing to the variable or calling non-const // methods of this class. #ifndef GFLAGS_GFLAGS_H_ #define GFLAGS_GFLAGS_H_ #include #include #include "gflags_declare.h" // IWYU pragma: export // We always want to export variables defined in user code #ifndef GFLAGS_DLL_DEFINE_FLAG # ifdef _MSC_VER # define GFLAGS_DLL_DEFINE_FLAG __declspec(dllexport) # else # define GFLAGS_DLL_DEFINE_FLAG # endif #endif namespace GFLAGS_NAMESPACE { // -------------------------------------------------------------------- // To actually define a flag in a file, use DEFINE_bool, // DEFINE_string, etc. at the bottom of this file. You may also find // it useful to register a validator with the flag. This ensures that // when the flag is parsed from the commandline, or is later set via // SetCommandLineOption, we call the validation function. It is _not_ // called when you assign the value to the flag directly using the = operator. // // The validation function should return true if the flag value is valid, and // false otherwise. If the function returns false for the new setting of the // flag, the flag will retain its current value. If it returns false for the // default value, ParseCommandLineFlags() will die. // // This function is safe to call at global construct time (as in the // example below). // // Example use: // static bool ValidatePort(const char* flagname, int32 value) { // if (value > 0 && value < 32768) // value is ok // return true; // printf("Invalid value for --%s: %d\n", flagname, (int)value); // return false; // } // DEFINE_int32(port, 0, "What port to listen on"); // static bool dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort); // Returns true if successfully registered, false if not (because the // first argument doesn't point to a command-line flag, or because a // validator is already registered for this flag). extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const bool* flag, bool (*validate_fn)(const char*, bool)); extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const int32* flag, bool (*validate_fn)(const char*, int32)); extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const int64* flag, bool (*validate_fn)(const char*, int64)); extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const uint64* flag, bool (*validate_fn)(const char*, uint64)); extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const double* flag, bool (*validate_fn)(const char*, double)); extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const std::string* flag, bool (*validate_fn)(const char*, const std::string&)); // Convenience macro for the registration of a flag validator #define DEFINE_validator(name, validator) \ static const bool name##_validator_registered = \ GFLAGS_NAMESPACE::RegisterFlagValidator(&FLAGS_##name, validator) // -------------------------------------------------------------------- // These methods are the best way to get access to info about the // list of commandline flags. Note that these routines are pretty slow. // GetAllFlags: mostly-complete info about the list, sorted by file. // ShowUsageWithFlags: pretty-prints the list to stdout (what --help does) // ShowUsageWithFlagsRestrict: limit to filenames with restrict as a substr // // In addition to accessing flags, you can also access argv[0] (the program // name) and argv (the entire commandline), which we sock away a copy of. // These variables are static, so you should only set them once. // // No need to export this data only structure from DLL, avoiding VS warning 4251. struct CommandLineFlagInfo { std::string name; // the name of the flag std::string type; // the type of the flag: int32, etc std::string description; // the "help text" associated with the flag std::string current_value; // the current value, as a string std::string default_value; // the default value, as a string std::string filename; // 'cleaned' version of filename holding the flag bool has_validator_fn; // true if RegisterFlagValidator called on this flag bool is_default; // true if the flag has the default value and // has not been set explicitly from the cmdline // or via SetCommandLineOption const void* flag_ptr; // pointer to the flag's current value (i.e. FLAGS_foo) }; // Using this inside of a validator is a recipe for a deadlock. // TODO(user) Fix locking when validators are running, to make it safe to // call validators during ParseAllFlags. // Also make sure then to uncomment the corresponding unit test in // gflags_unittest.sh extern GFLAGS_DLL_DECL void GetAllFlags(std::vector* OUTPUT); // These two are actually defined in gflags_reporting.cc. extern GFLAGS_DLL_DECL void ShowUsageWithFlags(const char *argv0); // what --help does extern GFLAGS_DLL_DECL void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict); // Create a descriptive string for a flag. // Goes to some trouble to make pretty line breaks. extern GFLAGS_DLL_DECL std::string DescribeOneFlag(const CommandLineFlagInfo& flag); // Thread-hostile; meant to be called before any threads are spawned. extern GFLAGS_DLL_DECL void SetArgv(int argc, const char** argv); // The following functions are thread-safe as long as SetArgv() is // only called before any threads start. extern GFLAGS_DLL_DECL const std::vector& GetArgvs(); extern GFLAGS_DLL_DECL const char* GetArgv(); // all of argv as a string extern GFLAGS_DLL_DECL const char* GetArgv0(); // only argv0 extern GFLAGS_DLL_DECL uint32 GetArgvSum(); // simple checksum of argv extern GFLAGS_DLL_DECL const char* ProgramInvocationName(); // argv0, or "UNKNOWN" if not set extern GFLAGS_DLL_DECL const char* ProgramInvocationShortName(); // basename(argv0) // ProgramUsage() is thread-safe as long as SetUsageMessage() is only // called before any threads start. extern GFLAGS_DLL_DECL const char* ProgramUsage(); // string set by SetUsageMessage() // VersionString() is thread-safe as long as SetVersionString() is only // called before any threads start. extern GFLAGS_DLL_DECL const char* VersionString(); // string set by SetVersionString() // -------------------------------------------------------------------- // Normally you access commandline flags by just saying "if (FLAGS_foo)" // or whatever, and set them by calling "FLAGS_foo = bar" (or, more // commonly, via the DEFINE_foo macro). But if you need a bit more // control, we have programmatic ways to get/set the flags as well. // These programmatic ways to access flags are thread-safe, but direct // access is only thread-compatible. // Return true iff the flagname was found. // OUTPUT is set to the flag's value, or unchanged if we return false. extern GFLAGS_DLL_DECL bool GetCommandLineOption(const char* name, std::string* OUTPUT); // Return true iff the flagname was found. OUTPUT is set to the flag's // CommandLineFlagInfo or unchanged if we return false. extern GFLAGS_DLL_DECL bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT); // Return the CommandLineFlagInfo of the flagname. exit() if name not found. // Example usage, to check if a flag's value is currently the default value: // if (GetCommandLineFlagInfoOrDie("foo").is_default) ... extern GFLAGS_DLL_DECL CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name); enum GFLAGS_DLL_DECL FlagSettingMode { // update the flag's value (can call this multiple times). SET_FLAGS_VALUE, // update the flag's value, but *only if* it has not yet been updated // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef". SET_FLAG_IF_DEFAULT, // set the flag's default value to this. If the flag has not yet updated // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef") // change the flag's current value to the new default value as well. SET_FLAGS_DEFAULT }; // Set a particular flag ("command line option"). Returns a string // describing the new value that the option has been set to. The // return value API is not well-specified, so basically just depend on // it to be empty if the setting failed for some reason -- the name is // not a valid flag name, or the value is not a valid value -- and // non-empty else. // SetCommandLineOption uses set_mode == SET_FLAGS_VALUE (the common case) extern GFLAGS_DLL_DECL std::string SetCommandLineOption (const char* name, const char* value); extern GFLAGS_DLL_DECL std::string SetCommandLineOptionWithMode(const char* name, const char* value, FlagSettingMode set_mode); // -------------------------------------------------------------------- // Saves the states (value, default value, whether the user has set // the flag, registered validators, etc) of all flags, and restores // them when the FlagSaver is destroyed. This is very useful in // tests, say, when you want to let your tests change the flags, but // make sure that they get reverted to the original states when your // test is complete. // // Example usage: // void TestFoo() { // FlagSaver s1; // FLAG_foo = false; // FLAG_bar = "some value"; // // // test happens here. You can return at any time // // without worrying about restoring the FLAG values. // } // // Note: This class is marked with GFLAGS_ATTRIBUTE_UNUSED because all // the work is done in the constructor and destructor, so in the standard // usage example above, the compiler would complain that it's an // unused variable. // // This class is thread-safe. However, its destructor writes to // exactly the set of flags that have changed value during its // lifetime, so concurrent _direct_ access to those flags // (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe. class GFLAGS_DLL_DECL FlagSaver { public: FlagSaver(); ~FlagSaver(); private: class FlagSaverImpl* impl_; // we use pimpl here to keep API steady FlagSaver(const FlagSaver&); // no copying! void operator=(const FlagSaver&); }@GFLAGS_ATTRIBUTE_UNUSED@; // -------------------------------------------------------------------- // Some deprecated or hopefully-soon-to-be-deprecated functions. // This is often used for logging. TODO(csilvers): figure out a better way extern GFLAGS_DLL_DECL std::string CommandlineFlagsIntoString(); // Usually where this is used, a FlagSaver should be used instead. extern GFLAGS_DLL_DECL bool ReadFlagsFromString(const std::string& flagfilecontents, const char* prog_name, bool errors_are_fatal); // uses SET_FLAGS_VALUE // These let you manually implement --flagfile functionality. // DEPRECATED. extern GFLAGS_DLL_DECL bool AppendFlagsIntoFile(const std::string& filename, const char* prog_name); extern GFLAGS_DLL_DECL bool ReadFromFlagsFile(const std::string& filename, const char* prog_name, bool errors_are_fatal); // uses SET_FLAGS_VALUE // -------------------------------------------------------------------- // Useful routines for initializing flags from the environment. // In each case, if 'varname' does not exist in the environment // return defval. If 'varname' does exist but is not valid // (e.g., not a number for an int32 flag), abort with an error. // Otherwise, return the value. NOTE: for booleans, for true use // 't' or 'T' or 'true' or '1', for false 'f' or 'F' or 'false' or '0'. extern GFLAGS_DLL_DECL bool BoolFromEnv(const char *varname, bool defval); extern GFLAGS_DLL_DECL int32 Int32FromEnv(const char *varname, int32 defval); extern GFLAGS_DLL_DECL int64 Int64FromEnv(const char *varname, int64 defval); extern GFLAGS_DLL_DECL uint64 Uint64FromEnv(const char *varname, uint64 defval); extern GFLAGS_DLL_DECL double DoubleFromEnv(const char *varname, double defval); extern GFLAGS_DLL_DECL const char *StringFromEnv(const char *varname, const char *defval); // -------------------------------------------------------------------- // The next two functions parse gflags from main(): // Set the "usage" message for this program. For example: // string usage("This program does nothing. Sample usage:\n"); // usage += argv[0] + " "; // SetUsageMessage(usage); // Do not include commandline flags in the usage: we do that for you! // Thread-hostile; meant to be called before any threads are spawned. extern GFLAGS_DLL_DECL void SetUsageMessage(const std::string& usage); // Sets the version string, which is emitted with --version. // For instance: SetVersionString("1.3"); // Thread-hostile; meant to be called before any threads are spawned. extern GFLAGS_DLL_DECL void SetVersionString(const std::string& version); // Looks for flags in argv and parses them. Rearranges argv to put // flags first, or removes them entirely if remove_flags is true. // If a flag is defined more than once in the command line or flag // file, the last definition is used. Returns the index (into argv) // of the first non-flag argument. // See top-of-file for more details on this function. #ifndef SWIG // In swig, use ParseCommandLineFlagsScript() instead. extern GFLAGS_DLL_DECL uint32 ParseCommandLineFlags(int *argc, char*** argv, bool remove_flags); #endif // Calls to ParseCommandLineNonHelpFlags and then to // HandleCommandLineHelpFlags can be used instead of a call to // ParseCommandLineFlags during initialization, in order to allow for // changing default values for some FLAGS (via // e.g. SetCommandLineOptionWithMode calls) between the time of // command line parsing and the time of dumping help information for // the flags as a result of command line parsing. If a flag is // defined more than once in the command line or flag file, the last // definition is used. Returns the index (into argv) of the first // non-flag argument. (If remove_flags is true, will always return 1.) extern GFLAGS_DLL_DECL uint32 ParseCommandLineNonHelpFlags(int *argc, char*** argv, bool remove_flags); // This is actually defined in gflags_reporting.cc. // This function is misnamed (it also handles --version, etc.), but // it's too late to change that now. :-( extern GFLAGS_DLL_DECL void HandleCommandLineHelpFlags(); // in gflags_reporting.cc // Allow command line reparsing. Disables the error normally // generated when an unknown flag is found, since it may be found in a // later parse. Thread-hostile; meant to be called before any threads // are spawned. extern GFLAGS_DLL_DECL void AllowCommandLineReparsing(); // Reparse the flags that have not yet been recognized. Only flags // registered since the last parse will be recognized. Any flag value // must be provided as part of the argument using "=", not as a // separate command line argument that follows the flag argument. // Intended for handling flags from dynamically loaded libraries, // since their flags are not registered until they are loaded. extern GFLAGS_DLL_DECL void ReparseCommandLineNonHelpFlags(); // Clean up memory allocated by flags. This is only needed to reduce // the quantity of "potentially leaked" reports emitted by memory // debugging tools such as valgrind. It is not required for normal // operation, or for the google perftools heap-checker. It must only // be called when the process is about to exit, and all threads that // might access flags are quiescent. Referencing flags after this is // called will have unexpected consequences. This is not safe to run // when multiple threads might be running: the function is // thread-hostile. extern GFLAGS_DLL_DECL void ShutDownCommandLineFlags(); // -------------------------------------------------------------------- // Now come the command line flag declaration/definition macros that // will actually be used. They're kind of hairy. A major reason // for this is initialization: we want people to be able to access // variables in global constructors and have that not crash, even if // their global constructor runs before the global constructor here. // (Obviously, we can't guarantee the flags will have the correct // default value in that case, but at least accessing them is safe.) // The only way to do that is have flags point to a static buffer. // So we make one, using a union to ensure proper alignment, and // then use placement-new to actually set up the flag with the // correct default value. In the same vein, we have to worry about // flag access in global destructors, so FlagRegisterer has to be // careful never to destroy the flag-values it constructs. // // Note that when we define a flag variable FLAGS_, we also // preemptively define a junk variable, FLAGS_no. This is to // cause a link-time error if someone tries to define 2 flags with // names like "logging" and "nologging". We do this because a bool // flag FLAG can be set from the command line to true with a "-FLAG" // argument, and to false with a "-noFLAG" argument, and so this can // potentially avert confusion. // // We also put flags into their own namespace. It is purposefully // named in an opaque way that people should have trouble typing // directly. The idea is that DEFINE puts the flag in the weird // namespace, and DECLARE imports the flag from there into the current // namespace. The net result is to force people to use DECLARE to get // access to a flag, rather than saying "extern GFLAGS_DLL_DECL bool FLAGS_whatever;" // or some such instead. We want this so we can put extra // functionality (like sanity-checking) in DECLARE if we want, and // make sure it is picked up everywhere. // // We also put the type of the variable in the namespace, so that // people can't DECLARE_int32 something that they DEFINE_bool'd // elsewhere. class GFLAGS_DLL_DECL FlagRegisterer { public: FlagRegisterer(const char* name, const char* type, const char* help, const char* filename, void* current_storage, void* defvalue_storage); }; // If your application #defines STRIP_FLAG_HELP to a non-zero value // before #including this file, we remove the help message from the // binary file. This can reduce the size of the resulting binary // somewhat, and may also be useful for security reasons. extern GFLAGS_DLL_DECL const char kStrippedFlagHelp[]; } // namespace GFLAGS_NAMESPACE #ifndef SWIG // In swig, ignore the main flag declarations #if defined(STRIP_FLAG_HELP) && STRIP_FLAG_HELP > 0 // Need this construct to avoid the 'defined but not used' warning. #define MAYBE_STRIPPED_HELP(txt) \ (false ? (txt) : GFLAGS_NAMESPACE::kStrippedFlagHelp) #else #define MAYBE_STRIPPED_HELP(txt) txt #endif // Each command-line flag has two variables associated with it: one // with the current value, and one with the default value. However, // we have a third variable, which is where value is assigned; it's a // constant. This guarantees that FLAG_##value is initialized at // static initialization time (e.g. before program-start) rather than // than global construction time (which is after program-start but // before main), at least when 'value' is a compile-time constant. We // use a small trick for the "default value" variable, and call it // FLAGS_no. This serves the second purpose of assuring a // compile error if someone tries to define a flag named no // which is illegal (--foo and --nofoo both affect the "foo" flag). #define DEFINE_VARIABLE(type, shorttype, name, value, help) \ namespace fL##shorttype { \ static const type FLAGS_nono##name = value; \ /* We always want to export defined variables, dll or no */ \ GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = FLAGS_nono##name; \ type FLAGS_no##name = FLAGS_nono##name; \ static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \ #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__, \ &FLAGS_##name, &FLAGS_no##name); \ } \ using fL##shorttype::FLAGS_##name // For DEFINE_bool, we want to do the extra check that the passed-in // value is actually a bool, and not a string or something that can be // coerced to a bool. These declarations (no definition needed!) will // help us do that, and never evaluate From, which is important. // We'll use 'sizeof(IsBool(val))' to distinguish. This code requires // that the compiler have different sizes for bool & double. Since // this is not guaranteed by the standard, we check it with a // COMPILE_ASSERT. namespace fLB { struct CompileAssert {}; typedef CompileAssert expected_sizeof_double_neq_sizeof_bool[ (sizeof(double) != sizeof(bool)) ? 1 : -1]; template double GFLAGS_DLL_DECL IsBoolFlag(const From& from); GFLAGS_DLL_DECL bool IsBoolFlag(bool from); } // namespace fLB // Here are the actual DEFINE_*-macros. The respective DECLARE_*-macros // are in a separate include, gflags_declare.h, for reducing // the physical transitive size for DECLARE use. #define DEFINE_bool(name, val, txt) \ namespace fLB { \ typedef ::fLB::CompileAssert FLAG_##name##_value_is_not_a_bool[ \ (sizeof(::fLB::IsBoolFlag(val)) != sizeof(double))? 1: -1]; \ } \ DEFINE_VARIABLE(bool, B, name, val, txt) #define DEFINE_int32(name, val, txt) \ DEFINE_VARIABLE(GFLAGS_NAMESPACE::int32, I, \ name, val, txt) #define DEFINE_int64(name, val, txt) \ DEFINE_VARIABLE(GFLAGS_NAMESPACE::int64, I64, \ name, val, txt) #define DEFINE_uint64(name,val, txt) \ DEFINE_VARIABLE(GFLAGS_NAMESPACE::uint64, U64, \ name, val, txt) #define DEFINE_double(name, val, txt) \ DEFINE_VARIABLE(double, D, name, val, txt) // Strings are trickier, because they're not a POD, so we can't // construct them at static-initialization time (instead they get // constructed at global-constructor time, which is much later). To // try to avoid crashes in that case, we use a char buffer to store // the string, which we can static-initialize, and then placement-new // into it later. It's not perfect, but the best we can do. namespace fLS { inline clstring* dont_pass0toDEFINE_string(char *stringspot, const char *value) { return new(stringspot) clstring(value); } inline clstring* dont_pass0toDEFINE_string(char *stringspot, const clstring &value) { return new(stringspot) clstring(value); } inline clstring* dont_pass0toDEFINE_string(char *stringspot, int value); } // namespace fLS // We need to define a var named FLAGS_no##name so people don't define // --string and --nostring. And we need a temporary place to put val // so we don't have to evaluate it twice. Two great needs that go // great together! // The weird 'using' + 'extern' inside the fLS namespace is to work around // an unknown compiler bug/issue with the gcc 4.2.1 on SUSE 10. See // http://code.google.com/p/google-gflags/issues/detail?id=20 #define DEFINE_string(name, val, txt) \ namespace fLS { \ using ::fLS::clstring; \ static union { void* align; char s[sizeof(clstring)]; } s_##name[2]; \ clstring* const FLAGS_no##name = ::fLS:: \ dont_pass0toDEFINE_string(s_##name[0].s, \ val); \ static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \ #name, "string", MAYBE_STRIPPED_HELP(txt), __FILE__, \ s_##name[0].s, new (s_##name[1].s) clstring(*FLAGS_no##name)); \ extern GFLAGS_DLL_DEFINE_FLAG clstring& FLAGS_##name; \ using fLS::FLAGS_##name; \ clstring& FLAGS_##name = *FLAGS_no##name; \ } \ using fLS::FLAGS_##name #endif // SWIG @INCLUDE_GFLAGS_NS_H@ #endif // GFLAGS_GFLAGS_H_ gflags-2.1.2/src/gflags_completions.cc000066400000000000000000000652401250430723500177440ustar00rootroot00000000000000// Copyright (c) 2008, 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. // // --- // Bash-style command line flag completion for C++ binaries // // This module implements bash-style completions. It achieves this // goal in the following broad chunks: // // 1) Take a to-be-completed word, and examine it for search hints // 2) Identify all potentially matching flags // 2a) If there are no matching flags, do nothing. // 2b) If all matching flags share a common prefix longer than the // completion word, output just that matching prefix // 3) Categorize those flags to produce a rough ordering of relevence. // 4) Potentially trim the set of flags returned to a smaller number // that bash is happier with // 5) Output the matching flags in groups ordered by relevence. // 5a) Force bash to place most-relevent groups at the top of the list // 5b) Trim most flag's descriptions to fit on a single terminal line #include "config.h" #include #include #include // for strlen #include #include #include #include #include "gflags.h" #include "util.h" using std::set; using std::string; using std::vector; DEFINE_string(tab_completion_word, "", "If non-empty, HandleCommandLineCompletions() will hijack the " "process and attempt to do bash-style command line flag " "completion on this value."); DEFINE_int32(tab_completion_columns, 80, "Number of columns to use in output for tab completion"); namespace GFLAGS_NAMESPACE { namespace { // Function prototypes and Type forward declarations. Code may be // more easily understood if it is roughly ordered according to // control flow, rather than by C's "declare before use" ordering struct CompletionOptions; struct NotableFlags; // The entry point if flag completion is to be used. static void PrintFlagCompletionInfo(void); // 1) Examine search word static void CanonicalizeCursorWordAndSearchOptions( const string &cursor_word, string *canonical_search_token, CompletionOptions *options); static bool RemoveTrailingChar(string *str, char c); // 2) Find all matches static void FindMatchingFlags( const vector &all_flags, const CompletionOptions &options, const string &match_token, set *all_matches, string *longest_common_prefix); static bool DoesSingleFlagMatch( const CommandLineFlagInfo &flag, const CompletionOptions &options, const string &match_token); // 3) Categorize matches static void CategorizeAllMatchingFlags( const set &all_matches, const string &search_token, const string &module, const string &package_dir, NotableFlags *notable_flags); static void TryFindModuleAndPackageDir( const vector all_flags, string *module, string *package_dir); // 4) Decide which flags to use static void FinalizeCompletionOutput( const set &matching_flags, CompletionOptions *options, NotableFlags *notable_flags, vector *completions); static void RetrieveUnusedFlags( const set &matching_flags, const NotableFlags ¬able_flags, set *unused_flags); // 5) Output matches static void OutputSingleGroupWithLimit( const set &group, const string &line_indentation, const string &header, const string &footer, bool long_output_format, int *remaining_line_limit, size_t *completion_elements_added, vector *completions); // (helpers for #5) static string GetShortFlagLine( const string &line_indentation, const CommandLineFlagInfo &info); static string GetLongFlagLine( const string &line_indentation, const CommandLineFlagInfo &info); // // Useful types // Try to deduce the intentions behind this completion attempt. Return the // canonical search term in 'canonical_search_token'. Binary search options // are returned in the various booleans, which should all have intuitive // semantics, possibly except: // - return_all_matching_flags: Generally, we'll trim the number of // returned candidates to some small number, showing those that are // most likely to be useful first. If this is set, however, the user // really does want us to return every single flag as an option. // - force_no_update: Any time we output lines, all of which share a // common prefix, bash will 'helpfully' not even bother to show the // output, instead changing the current word to be that common prefix. // If it's clear this shouldn't happen, we'll set this boolean struct CompletionOptions { bool flag_name_substring_search; bool flag_location_substring_search; bool flag_description_substring_search; bool return_all_matching_flags; bool force_no_update; }; // Notable flags are flags that are special or preferred for some // reason. For example, flags that are defined in the binary's module // are expected to be much more relevent than flags defined in some // other random location. These sets are specified roughly in precedence // order. Once a flag is placed in one of these 'higher' sets, it won't // be placed in any of the 'lower' sets. struct NotableFlags { typedef set FlagSet; FlagSet perfect_match_flag; FlagSet module_flags; // Found in module file FlagSet package_flags; // Found in same directory as module file FlagSet most_common_flags; // One of the XXX most commonly supplied flags FlagSet subpackage_flags; // Found in subdirectories of package }; // // Tab completion implementation - entry point static void PrintFlagCompletionInfo(void) { string cursor_word = FLAGS_tab_completion_word; string canonical_token; CompletionOptions options = { }; CanonicalizeCursorWordAndSearchOptions( cursor_word, &canonical_token, &options); DVLOG(1) << "Identified canonical_token: '" << canonical_token << "'"; vector all_flags; set matching_flags; GetAllFlags(&all_flags); DVLOG(2) << "Found " << all_flags.size() << " flags overall"; string longest_common_prefix; FindMatchingFlags( all_flags, options, canonical_token, &matching_flags, &longest_common_prefix); DVLOG(1) << "Identified " << matching_flags.size() << " matching flags"; DVLOG(1) << "Identified " << longest_common_prefix << " as longest common prefix."; if (longest_common_prefix.size() > canonical_token.size()) { // There's actually a shared common prefix to all matching flags, // so may as well output that and quit quickly. DVLOG(1) << "The common prefix '" << longest_common_prefix << "' was longer than the token '" << canonical_token << "'. Returning just this prefix for completion."; fprintf(stdout, "--%s", longest_common_prefix.c_str()); return; } if (matching_flags.empty()) { VLOG(1) << "There were no matching flags, returning nothing."; return; } string module; string package_dir; TryFindModuleAndPackageDir(all_flags, &module, &package_dir); DVLOG(1) << "Identified module: '" << module << "'"; DVLOG(1) << "Identified package_dir: '" << package_dir << "'"; NotableFlags notable_flags; CategorizeAllMatchingFlags( matching_flags, canonical_token, module, package_dir, ¬able_flags); DVLOG(2) << "Categorized matching flags:"; DVLOG(2) << " perfect_match: " << notable_flags.perfect_match_flag.size(); DVLOG(2) << " module: " << notable_flags.module_flags.size(); DVLOG(2) << " package: " << notable_flags.package_flags.size(); DVLOG(2) << " most common: " << notable_flags.most_common_flags.size(); DVLOG(2) << " subpackage: " << notable_flags.subpackage_flags.size(); vector completions; FinalizeCompletionOutput( matching_flags, &options, ¬able_flags, &completions); if (options.force_no_update) completions.push_back("~"); DVLOG(1) << "Finalized with " << completions.size() << " chosen completions"; for (vector::const_iterator it = completions.begin(); it != completions.end(); ++it) { DVLOG(9) << " Completion entry: '" << *it << "'"; fprintf(stdout, "%s\n", it->c_str()); } } // 1) Examine search word (and helper method) static void CanonicalizeCursorWordAndSearchOptions( const string &cursor_word, string *canonical_search_token, CompletionOptions *options) { *canonical_search_token = cursor_word; if (canonical_search_token->empty()) return; // Get rid of leading quotes and dashes in the search term if ((*canonical_search_token)[0] == '"') *canonical_search_token = canonical_search_token->substr(1); while ((*canonical_search_token)[0] == '-') *canonical_search_token = canonical_search_token->substr(1); options->flag_name_substring_search = false; options->flag_location_substring_search = false; options->flag_description_substring_search = false; options->return_all_matching_flags = false; options->force_no_update = false; // Look for all search options we can deduce now. Do this by walking // backwards through the term, looking for up to three '?' and up to // one '+' as suffixed characters. Consume them if found, and remove // them from the canonical search token. int found_question_marks = 0; int found_plusses = 0; while (true) { if (found_question_marks < 3 && RemoveTrailingChar(canonical_search_token, '?')) { ++found_question_marks; continue; } if (found_plusses < 1 && RemoveTrailingChar(canonical_search_token, '+')) { ++found_plusses; continue; } break; } switch (found_question_marks) { // all fallthroughs case 3: options->flag_description_substring_search = true; case 2: options->flag_location_substring_search = true; case 1: options->flag_name_substring_search = true; }; options->return_all_matching_flags = (found_plusses > 0); } // Returns true if a char was removed static bool RemoveTrailingChar(string *str, char c) { if (str->empty()) return false; if ((*str)[str->size() - 1] == c) { *str = str->substr(0, str->size() - 1); return true; } return false; } // 2) Find all matches (and helper methods) static void FindMatchingFlags( const vector &all_flags, const CompletionOptions &options, const string &match_token, set *all_matches, string *longest_common_prefix) { all_matches->clear(); bool first_match = true; for (vector::const_iterator it = all_flags.begin(); it != all_flags.end(); ++it) { if (DoesSingleFlagMatch(*it, options, match_token)) { all_matches->insert(&*it); if (first_match) { first_match = false; *longest_common_prefix = it->name; } else { if (longest_common_prefix->empty() || it->name.empty()) { longest_common_prefix->clear(); continue; } string::size_type pos = 0; while (pos < longest_common_prefix->size() && pos < it->name.size() && (*longest_common_prefix)[pos] == it->name[pos]) ++pos; longest_common_prefix->erase(pos); } } } } // Given the set of all flags, the parsed match options, and the // canonical search token, produce the set of all candidate matching // flags for subsequent analysis or filtering. static bool DoesSingleFlagMatch( const CommandLineFlagInfo &flag, const CompletionOptions &options, const string &match_token) { // Is there a prefix match? string::size_type pos = flag.name.find(match_token); if (pos == 0) return true; // Is there a substring match if we want it? if (options.flag_name_substring_search && pos != string::npos) return true; // Is there a location match if we want it? if (options.flag_location_substring_search && flag.filename.find(match_token) != string::npos) return true; // TODO(user): All searches should probably be case-insensitive // (especially this one...) if (options.flag_description_substring_search && flag.description.find(match_token) != string::npos) return true; return false; } // 3) Categorize matches (and helper method) // Given a set of matching flags, categorize them by // likely relevence to this specific binary static void CategorizeAllMatchingFlags( const set &all_matches, const string &search_token, const string &module, // empty if we couldn't find any const string &package_dir, // empty if we couldn't find any NotableFlags *notable_flags) { notable_flags->perfect_match_flag.clear(); notable_flags->module_flags.clear(); notable_flags->package_flags.clear(); notable_flags->most_common_flags.clear(); notable_flags->subpackage_flags.clear(); for (set::const_iterator it = all_matches.begin(); it != all_matches.end(); ++it) { DVLOG(2) << "Examining match '" << (*it)->name << "'"; DVLOG(7) << " filename: '" << (*it)->filename << "'"; string::size_type pos = string::npos; if (!package_dir.empty()) pos = (*it)->filename.find(package_dir); string::size_type slash = string::npos; if (pos != string::npos) // candidate for package or subpackage match slash = (*it)->filename.find( PATH_SEPARATOR, pos + package_dir.size() + 1); if ((*it)->name == search_token) { // Exact match on some flag's name notable_flags->perfect_match_flag.insert(*it); DVLOG(3) << "Result: perfect match"; } else if (!module.empty() && (*it)->filename == module) { // Exact match on module filename notable_flags->module_flags.insert(*it); DVLOG(3) << "Result: module match"; } else if (!package_dir.empty() && pos != string::npos && slash == string::npos) { // In the package, since there was no slash after the package portion notable_flags->package_flags.insert(*it); DVLOG(3) << "Result: package match"; } else if (false) { // In the list of the XXX most commonly supplied flags overall // TODO(user): Compile this list. DVLOG(3) << "Result: most-common match"; } else if (!package_dir.empty() && pos != string::npos && slash != string::npos) { // In a subdirectory of the package notable_flags->subpackage_flags.insert(*it); DVLOG(3) << "Result: subpackage match"; } DVLOG(3) << "Result: not special match"; } } static void PushNameWithSuffix(vector* suffixes, const char* suffix) { suffixes->push_back( StringPrintf("/%s%s", ProgramInvocationShortName(), suffix)); } static void TryFindModuleAndPackageDir( const vector all_flags, string *module, string *package_dir) { module->clear(); package_dir->clear(); vector suffixes; // TODO(user): There's some inherant ambiguity here - multiple directories // could share the same trailing folder and file structure (and even worse, // same file names), causing us to be unsure as to which of the two is the // actual package for this binary. In this case, we'll arbitrarily choose. PushNameWithSuffix(&suffixes, "."); PushNameWithSuffix(&suffixes, "-main."); PushNameWithSuffix(&suffixes, "_main."); // These four are new but probably merited? PushNameWithSuffix(&suffixes, "-test."); PushNameWithSuffix(&suffixes, "_test."); PushNameWithSuffix(&suffixes, "-unittest."); PushNameWithSuffix(&suffixes, "_unittest."); for (vector::const_iterator it = all_flags.begin(); it != all_flags.end(); ++it) { for (vector::const_iterator suffix = suffixes.begin(); suffix != suffixes.end(); ++suffix) { // TODO(user): Make sure the match is near the end of the string if (it->filename.find(*suffix) != string::npos) { *module = it->filename; string::size_type sep = it->filename.rfind(PATH_SEPARATOR); *package_dir = it->filename.substr(0, (sep == string::npos) ? 0 : sep); return; } } } } // Can't specialize template type on a locally defined type. Silly C++... struct DisplayInfoGroup { const char* header; const char* footer; set *group; int SizeInLines() const { int size_in_lines = static_cast(group->size()) + 1; if (strlen(header) > 0) { size_in_lines++; } if (strlen(footer) > 0) { size_in_lines++; } return size_in_lines; } }; // 4) Finalize and trim output flag set static void FinalizeCompletionOutput( const set &matching_flags, CompletionOptions *options, NotableFlags *notable_flags, vector *completions) { // We want to output lines in groups. Each group needs to be indented // the same to keep its lines together. Unless otherwise required, // only 99 lines should be output to prevent bash from harassing the // user. // First, figure out which output groups we'll actually use. For each // nonempty group, there will be ~3 lines of header & footer, plus all // output lines themselves. int max_desired_lines = // "999999 flags should be enough for anyone. -dave" (options->return_all_matching_flags ? 999999 : 98); int lines_so_far = 0; vector output_groups; bool perfect_match_found = false; if (lines_so_far < max_desired_lines && !notable_flags->perfect_match_flag.empty()) { perfect_match_found = true; DisplayInfoGroup group = { "", "==========", ¬able_flags->perfect_match_flag }; lines_so_far += group.SizeInLines(); output_groups.push_back(group); } if (lines_so_far < max_desired_lines && !notable_flags->module_flags.empty()) { DisplayInfoGroup group = { "-* Matching module flags *-", "===========================", ¬able_flags->module_flags }; lines_so_far += group.SizeInLines(); output_groups.push_back(group); } if (lines_so_far < max_desired_lines && !notable_flags->package_flags.empty()) { DisplayInfoGroup group = { "-* Matching package flags *-", "============================", ¬able_flags->package_flags }; lines_so_far += group.SizeInLines(); output_groups.push_back(group); } if (lines_so_far < max_desired_lines && !notable_flags->most_common_flags.empty()) { DisplayInfoGroup group = { "-* Commonly used flags *-", "=========================", ¬able_flags->most_common_flags }; lines_so_far += group.SizeInLines(); output_groups.push_back(group); } if (lines_so_far < max_desired_lines && !notable_flags->subpackage_flags.empty()) { DisplayInfoGroup group = { "-* Matching sub-package flags *-", "================================", ¬able_flags->subpackage_flags }; lines_so_far += group.SizeInLines(); output_groups.push_back(group); } set obscure_flags; // flags not notable if (lines_so_far < max_desired_lines) { RetrieveUnusedFlags(matching_flags, *notable_flags, &obscure_flags); if (!obscure_flags.empty()) { DisplayInfoGroup group = { "-* Other flags *-", "", &obscure_flags }; lines_so_far += group.SizeInLines(); output_groups.push_back(group); } } // Second, go through each of the chosen output groups and output // as many of those flags as we can, while remaining below our limit int remaining_lines = max_desired_lines; size_t completions_output = 0; int indent = static_cast(output_groups.size()) - 1; for (vector::const_iterator it = output_groups.begin(); it != output_groups.end(); ++it, --indent) { OutputSingleGroupWithLimit( *it->group, // group string(indent, ' '), // line indentation string(it->header), // header string(it->footer), // footer perfect_match_found, // long format &remaining_lines, // line limit - reduces this by number printed &completions_output, // completions (not lines) added completions); // produced completions perfect_match_found = false; } if (completions_output != matching_flags.size()) { options->force_no_update = false; completions->push_back("~ (Remaining flags hidden) ~"); } else { options->force_no_update = true; } } static void RetrieveUnusedFlags( const set &matching_flags, const NotableFlags ¬able_flags, set *unused_flags) { // Remove from 'matching_flags' set all members of the sets of // flags we've already printed (specifically, those in notable_flags) for (set::const_iterator it = matching_flags.begin(); it != matching_flags.end(); ++it) { if (notable_flags.perfect_match_flag.count(*it) || notable_flags.module_flags.count(*it) || notable_flags.package_flags.count(*it) || notable_flags.most_common_flags.count(*it) || notable_flags.subpackage_flags.count(*it)) continue; unused_flags->insert(*it); } } // 5) Output matches (and helper methods) static void OutputSingleGroupWithLimit( const set &group, const string &line_indentation, const string &header, const string &footer, bool long_output_format, int *remaining_line_limit, size_t *completion_elements_output, vector *completions) { if (group.empty()) return; if (!header.empty()) { if (*remaining_line_limit < 2) return; *remaining_line_limit -= 2; completions->push_back(line_indentation + header); completions->push_back(line_indentation + string(header.size(), '-')); } for (set::const_iterator it = group.begin(); it != group.end() && *remaining_line_limit > 0; ++it) { --*remaining_line_limit; ++*completion_elements_output; completions->push_back( (long_output_format ? GetLongFlagLine(line_indentation, **it) : GetShortFlagLine(line_indentation, **it))); } if (!footer.empty()) { if (*remaining_line_limit < 1) return; --*remaining_line_limit; completions->push_back(line_indentation + footer); } } static string GetShortFlagLine( const string &line_indentation, const CommandLineFlagInfo &info) { string prefix; bool is_string = (info.type == "string"); SStringPrintf(&prefix, "%s--%s [%s%s%s] ", line_indentation.c_str(), info.name.c_str(), (is_string ? "'" : ""), info.default_value.c_str(), (is_string ? "'" : "")); int remainder = FLAGS_tab_completion_columns - static_cast(prefix.size()); string suffix; if (remainder > 0) suffix = (static_cast(info.description.size()) > remainder ? (info.description.substr(0, remainder - 3) + "...").c_str() : info.description.c_str()); return prefix + suffix; } static string GetLongFlagLine( const string &line_indentation, const CommandLineFlagInfo &info) { string output = DescribeOneFlag(info); // Replace '-' with '--', and remove trailing newline before appending // the module definition location. string old_flagname = "-" + info.name; output.replace( output.find(old_flagname), old_flagname.size(), "-" + old_flagname); // Stick a newline and indentation in front of the type and default // portions of DescribeOneFlag()s description static const char kNewlineWithIndent[] = "\n "; output.replace(output.find(" type:"), 1, string(kNewlineWithIndent)); output.replace(output.find(" default:"), 1, string(kNewlineWithIndent)); output = StringPrintf("%s Details for '--%s':\n" "%s defined: %s", line_indentation.c_str(), info.name.c_str(), output.c_str(), info.filename.c_str()); // Eliminate any doubled newlines that crept in. Specifically, if // DescribeOneFlag() decided to break the line just before "type" // or "default", we don't want to introduce an extra blank line static const string line_of_spaces(FLAGS_tab_completion_columns, ' '); static const char kDoubledNewlines[] = "\n \n"; for (string::size_type newlines = output.find(kDoubledNewlines); newlines != string::npos; newlines = output.find(kDoubledNewlines)) // Replace each 'doubled newline' with a single newline output.replace(newlines, sizeof(kDoubledNewlines) - 1, string("\n")); for (string::size_type newline = output.find('\n'); newline != string::npos; newline = output.find('\n')) { int newline_pos = static_cast(newline) % FLAGS_tab_completion_columns; int missing_spaces = FLAGS_tab_completion_columns - newline_pos; output.replace(newline, 1, line_of_spaces, 1, missing_spaces); } return output; } } // anonymous void HandleCommandLineCompletions(void) { if (FLAGS_tab_completion_word.empty()) return; PrintFlagCompletionInfo(); gflags_exitfunc(0); } } // namespace GFLAGS_NAMESPACE gflags-2.1.2/src/gflags_completions.h.in000066400000000000000000000132151250430723500202060ustar00rootroot00000000000000// Copyright (c) 2008, 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. // // --- // // Implement helpful bash-style command line flag completions // // ** Functional API: // HandleCommandLineCompletions() should be called early during // program startup, but after command line flag code has been // initialized, such as the beginning of HandleCommandLineHelpFlags(). // It checks the value of the flag --tab_completion_word. If this // flag is empty, nothing happens here. If it contains a string, // however, then HandleCommandLineCompletions() will hijack the // process, attempting to identify the intention behind this // completion. Regardless of the outcome of this deduction, the // process will be terminated, similar to --helpshort flag // handling. // // ** Overview of Bash completions: // Bash can be told to programatically determine completions for the // current 'cursor word'. It does this by (in this case) invoking a // command with some additional arguments identifying the command // being executed, the word being completed, and the previous word // (if any). Bash then expects a sequence of output lines to be // printed to stdout. If these lines all contain a common prefix // longer than the cursor word, bash will replace the cursor word // with that common prefix, and display nothing. If there isn't such // a common prefix, bash will display the lines in pages using 'more'. // // ** Strategy taken for command line completions: // If we can deduce either the exact flag intended, or a common flag // prefix, we'll output exactly that. Otherwise, if information // must be displayed to the user, we'll take the opportunity to add // some helpful information beyond just the flag name (specifically, // we'll include the default flag value and as much of the flag's // description as can fit on a single terminal line width, as specified // by the flag --tab_completion_columns). Furthermore, we'll try to // make bash order the output such that the most useful or relevent // flags are the most likely to be shown at the top. // // ** Additional features: // To assist in finding that one really useful flag, substring matching // was implemented. Before pressing a to get completion for the // current word, you can append one or more '?' to the flag to do // substring matching. Here's the semantics: // --foo Show me all flags with names prefixed by 'foo' // --foo? Show me all flags with 'foo' somewhere in the name // --foo?? Same as prior case, but also search in module // definition path for 'foo' // --foo??? Same as prior case, but also search in flag // descriptions for 'foo' // Finally, we'll trim the output to a relatively small number of // flags to keep bash quiet about the verbosity of output. If one // really wanted to see all possible matches, appending a '+' to the // search word will force the exhaustive list of matches to be printed. // // ** How to have bash accept completions from a binary: // Bash requires that it be informed about each command that programmatic // completion should be enabled for. Example addition to a .bashrc // file would be (your path to gflags_completions.sh file may differ): /* $ complete -o bashdefault -o default -o nospace -C \ '/home/build/eng/bash/bash_completions.sh --tab_completion_columns $COLUMNS' \ time env binary_name another_binary [...] */ // This would allow the following to work: // $ /path/to/binary_name --vmodule // Or: // $ ./bin/path/another_binary --gfs_u // (etc) // // Sadly, it appears that bash gives no easy way to force this behavior for // all commands. That's where the "time" in the above example comes in. // If you haven't specifically added a command to the list of completion // supported commands, you can still get completions by prefixing the // entire command with "env". // $ env /some/brand/new/binary --vmod // Assuming that "binary" is a newly compiled binary, this should still // produce the expected completion output. #ifndef GFLAGS_COMPLETIONS_H_ #define GFLAGS_COMPLETIONS_H_ namespace @GFLAGS_NAMESPACE@ { extern void HandleCommandLineCompletions(void); } #endif // GFLAGS_COMPLETIONS_H_ gflags-2.1.2/src/gflags_completions.sh000077500000000000000000000120061250430723500177640ustar00rootroot00000000000000#!/bin/bash # Copyright (c) 2008, 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. # # --- # Author: Dave Nicponski # # This script is invoked by bash in response to a matching compspec. When # this happens, bash calls this script using the command shown in the -C # block of the complete entry, but also appends 3 arguments. They are: # - The command being used for completion # - The word being completed # - The word preceding the completion word. # # Here's an example of how you might use this script: # $ complete -o bashdefault -o default -o nospace -C \ # '/usr/local/bin/gflags_completions.sh --tab_completion_columns $COLUMNS' \ # time env binary_name another_binary [...] # completion_word_index gets the index of the (N-1)th argument for # this command line. completion_word gets the actual argument from # this command line at the (N-1)th position completion_word_index="$(($# - 1))" completion_word="${!completion_word_index}" # TODO(user): Replace this once gflags_completions.cc has # a bool parameter indicating unambiguously to hijack the process for # completion purposes. if [ -z "$completion_word" ]; then # Until an empty value for the completion word stops being misunderstood # by binaries, don't actually execute the binary or the process # won't be hijacked! exit 0 fi # binary_index gets the index of the command being completed (which bash # places in the (N-2)nd position. binary gets the actual command from # this command line at that (N-2)nd position binary_index="$(($# - 2))" binary="${!binary_index}" # For completions to be universal, we may have setup the compspec to # trigger on 'harmless pass-through' commands, like 'time' or 'env'. # If the command being completed is one of those two, we'll need to # identify the actual command being executed. To do this, we need # the actual command line that the was pressed on. Bash helpfully # places this in the $COMP_LINE variable. if [ "$binary" == "time" ] || [ "$binary" == "env" ]; then # we'll assume that the first 'argument' is actually the # binary # TODO(user): This is not perfect - the 'env' command, for instance, # is allowed to have options between the 'env' and 'the command to # be executed'. For example, consider: # $ env FOO="bar" bin/do_something --help # In this case, we'll mistake the FOO="bar" portion as the binary. # Perhaps we should continuing consuming leading words until we # either run out of words, or find a word that is a valid file # marked as executable. I can't think of any reason this wouldn't # work. # Break up the 'original command line' (not this script's command line, # rather the one the was pressed on) and find the second word. parts=( ${COMP_LINE} ) binary=${parts[1]} fi # Build the command line to use for completion. Basically it involves # passing through all the arguments given to this script (except the 3 # that bash added), and appending a '--tab_completion_word "WORD"' to # the arguments. params="" for ((i=1; i<=$(($# - 3)); ++i)); do params="$params \"${!i}\""; done params="$params --tab_completion_word \"$completion_word\"" # TODO(user): Perhaps stash the output in a temporary file somewhere # in /tmp, and only cat it to stdout if the command returned a success # code, to prevent false positives # If we think we have a reasonable command to execute, then execute it # and hope for the best. candidate=$(type -p "$binary") if [ ! -z "$candidate" ]; then eval "$candidate 2>/dev/null $params" elif [ -f "$binary" ] && [ -x "$binary" ]; then eval "$binary 2>/dev/null $params" fi gflags-2.1.2/src/gflags_declare.h.in000066400000000000000000000113741250430723500172550ustar00rootroot00000000000000// Copyright (c) 1999, 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. // --- // // Revamped and reorganized by Craig Silverstein // // This is the file that should be included by any file which declares // command line flag. #ifndef GFLAGS_DECLARE_H_ #define GFLAGS_DECLARE_H_ // --------------------------------------------------------------------------- // Namespace of gflags library symbols. #define GFLAGS_NAMESPACE @GFLAGS_NAMESPACE@ // --------------------------------------------------------------------------- // Windows DLL import/export. // We always want to import the symbols of the gflags library #ifndef GFLAGS_DLL_DECL # if @GFLAGS_IS_A_DLL@ && defined(_MSC_VER) # define GFLAGS_DLL_DECL __declspec(dllimport) # else # define GFLAGS_DLL_DECL # endif #endif // We always want to import variables declared in user code #ifndef GFLAGS_DLL_DECLARE_FLAG # ifdef _MSC_VER # define GFLAGS_DLL_DECLARE_FLAG __declspec(dllimport) # else # define GFLAGS_DLL_DECLARE_FLAG # endif #endif // --------------------------------------------------------------------------- // Flag types #include #if @HAVE_STDINT_H@ # include // the normal place uint32_t is defined #elif @HAVE_SYS_TYPES_H@ # include // the normal place u_int32_t is defined #elif @HAVE_INTTYPES_H@ # include // a third place for uint32_t or u_int32_t #endif namespace GFLAGS_NAMESPACE { #if @GFLAGS_INTTYPES_FORMAT_C99@ // C99 typedef int32_t int32; typedef uint32_t uint32; typedef int64_t int64; typedef uint64_t uint64; #elif @GFLAGS_INTTYPES_FORMAT_BSD@ // BSD typedef int32_t int32; typedef u_int32_t uint32; typedef int64_t int64; typedef u_int64_t uint64; #elif @GFLAGS_INTTYPES_FORMAT_VC7@ // Windows typedef __int32 int32; typedef unsigned __int32 uint32; typedef __int64 int64; typedef unsigned __int64 uint64; #else # error Do not know how to define a 32-bit integer quantity on your system #endif } // namespace GFLAGS_NAMESPACE namespace fLS { // The meaning of "string" might be different between now and when the // macros below get invoked (e.g., if someone is experimenting with // other string implementations that get defined after this file is // included). Save the current meaning now and use it in the macros. typedef std::string clstring; } // namespace fLS #define DECLARE_VARIABLE(type, shorttype, name) \ /* We always want to import declared variables, dll or no */ \ namespace fL##shorttype { extern GFLAGS_DLL_DECLARE_FLAG type FLAGS_##name; } \ using fL##shorttype::FLAGS_##name #define DECLARE_bool(name) \ DECLARE_VARIABLE(bool, B, name) #define DECLARE_int32(name) \ DECLARE_VARIABLE(::GFLAGS_NAMESPACE::int32, I, name) #define DECLARE_int64(name) \ DECLARE_VARIABLE(::GFLAGS_NAMESPACE::int64, I64, name) #define DECLARE_uint64(name) \ DECLARE_VARIABLE(::GFLAGS_NAMESPACE::uint64, U64, name) #define DECLARE_double(name) \ DECLARE_VARIABLE(double, D, name) #define DECLARE_string(name) \ /* We always want to import declared variables, dll or no */ \ namespace fLS { \ using ::fLS::clstring; \ extern GFLAGS_DLL_DECLARE_FLAG ::fLS::clstring& FLAGS_##name; \ } \ using fLS::FLAGS_##name #endif // GFLAGS_DECLARE_H_ gflags-2.1.2/src/gflags_ns.h.in000066400000000000000000000076641250430723500163050ustar00rootroot00000000000000// Copyright (c) 2014, Andreas Schuh // 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. // ----------------------------------------------------------------------------- // Imports the gflags library symbols into an alternative/deprecated namespace. #ifndef GFLAGS_GFLAGS_H_ # error The internal header gflags_@ns@.h may only be included by gflags.h #endif #ifndef GFLAGS_NS_@NS@_H_ #define GFLAGS_NS_@NS@_H_ namespace @ns@ { using GFLAGS_NAMESPACE::int32; using GFLAGS_NAMESPACE::uint32; using GFLAGS_NAMESPACE::int64; using GFLAGS_NAMESPACE::uint64; using GFLAGS_NAMESPACE::RegisterFlagValidator; using GFLAGS_NAMESPACE::CommandLineFlagInfo; using GFLAGS_NAMESPACE::GetAllFlags; using GFLAGS_NAMESPACE::ShowUsageWithFlags; using GFLAGS_NAMESPACE::ShowUsageWithFlagsRestrict; using GFLAGS_NAMESPACE::DescribeOneFlag; using GFLAGS_NAMESPACE::SetArgv; using GFLAGS_NAMESPACE::GetArgvs; using GFLAGS_NAMESPACE::GetArgv; using GFLAGS_NAMESPACE::GetArgv0; using GFLAGS_NAMESPACE::GetArgvSum; using GFLAGS_NAMESPACE::ProgramInvocationName; using GFLAGS_NAMESPACE::ProgramInvocationShortName; using GFLAGS_NAMESPACE::ProgramUsage; using GFLAGS_NAMESPACE::VersionString; using GFLAGS_NAMESPACE::GetCommandLineOption; using GFLAGS_NAMESPACE::GetCommandLineFlagInfo; using GFLAGS_NAMESPACE::GetCommandLineFlagInfoOrDie; using GFLAGS_NAMESPACE::FlagSettingMode; using GFLAGS_NAMESPACE::SET_FLAGS_VALUE; using GFLAGS_NAMESPACE::SET_FLAG_IF_DEFAULT; using GFLAGS_NAMESPACE::SET_FLAGS_DEFAULT; using GFLAGS_NAMESPACE::SetCommandLineOption; using GFLAGS_NAMESPACE::SetCommandLineOptionWithMode; using GFLAGS_NAMESPACE::FlagSaver; using GFLAGS_NAMESPACE::CommandlineFlagsIntoString; using GFLAGS_NAMESPACE::ReadFlagsFromString; using GFLAGS_NAMESPACE::AppendFlagsIntoFile; using GFLAGS_NAMESPACE::ReadFromFlagsFile; using GFLAGS_NAMESPACE::BoolFromEnv; using GFLAGS_NAMESPACE::Int32FromEnv; using GFLAGS_NAMESPACE::Int64FromEnv; using GFLAGS_NAMESPACE::Uint64FromEnv; using GFLAGS_NAMESPACE::DoubleFromEnv; using GFLAGS_NAMESPACE::StringFromEnv; using GFLAGS_NAMESPACE::SetUsageMessage; using GFLAGS_NAMESPACE::SetVersionString; using GFLAGS_NAMESPACE::ParseCommandLineNonHelpFlags; using GFLAGS_NAMESPACE::HandleCommandLineHelpFlags; using GFLAGS_NAMESPACE::AllowCommandLineReparsing; using GFLAGS_NAMESPACE::ReparseCommandLineNonHelpFlags; using GFLAGS_NAMESPACE::ShutDownCommandLineFlags; using GFLAGS_NAMESPACE::FlagRegisterer; #ifndef SWIG using GFLAGS_NAMESPACE::ParseCommandLineFlags; #endif } // namespace @ns@ #endif // GFLAGS_NS_@NS@_H_ gflags-2.1.2/src/gflags_reporting.cc000066400000000000000000000415441250430723500174220ustar00rootroot00000000000000// Copyright (c) 1999, 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. // --- // // Revamped and reorganized by Craig Silverstein // // This file contains code for handling the 'reporting' flags. These // are flags that, when present, cause the program to report some // information and then exit. --help and --version are the canonical // reporting flags, but we also have flags like --helpxml, etc. // // There's only one function that's meant to be called externally: // HandleCommandLineHelpFlags(). (Well, actually, ShowUsageWithFlags(), // ShowUsageWithFlagsRestrict(), and DescribeOneFlag() can be called // externally too, but there's little need for it.) These are all // declared in the main gflags.h header file. // // HandleCommandLineHelpFlags() will check what 'reporting' flags have // been defined, if any -- the "help" part of the function name is a // bit misleading -- and do the relevant reporting. It should be // called after all flag-values have been assigned, that is, after // parsing the command-line. #include #include #include #include #include #include #include "config.h" #include "gflags.h" #include "gflags_completions.h" #include "util.h" // The 'reporting' flags. They all call gflags_exitfunc(). DEFINE_bool (help, false, "show help on all flags [tip: all flags can have two dashes]"); DEFINE_bool (helpfull, false, "show help on all flags -- same as -help"); DEFINE_bool (helpshort, false, "show help on only the main module for this program"); DEFINE_string(helpon, "", "show help on the modules named by this flag value"); DEFINE_string(helpmatch, "", "show help on modules whose name contains the specified substr"); DEFINE_bool (helppackage, false, "show help on all modules in the main package"); DEFINE_bool (helpxml, false, "produce an xml version of help"); DEFINE_bool (version, false, "show version and build info and exit"); namespace GFLAGS_NAMESPACE { using std::string; using std::vector; // -------------------------------------------------------------------- // DescribeOneFlag() // DescribeOneFlagInXML() // Routines that pretty-print info about a flag. These use // a CommandLineFlagInfo, which is the way the gflags // API exposes static info about a flag. // -------------------------------------------------------------------- static const int kLineLength = 80; static void AddString(const string& s, string* final_string, int* chars_in_line) { const int slen = static_cast(s.length()); if (*chars_in_line + 1 + slen >= kLineLength) { // < 80 chars/line *final_string += "\n "; *chars_in_line = 6; } else { *final_string += " "; *chars_in_line += 1; } *final_string += s; *chars_in_line += slen; } static string PrintStringFlagsWithQuotes(const CommandLineFlagInfo& flag, const string& text, bool current) { const char* c_string = (current ? flag.current_value.c_str() : flag.default_value.c_str()); if (strcmp(flag.type.c_str(), "string") == 0) { // add quotes for strings return StringPrintf("%s: \"%s\"", text.c_str(), c_string); } else { return StringPrintf("%s: %s", text.c_str(), c_string); } } // Create a descriptive string for a flag. // Goes to some trouble to make pretty line breaks. string DescribeOneFlag(const CommandLineFlagInfo& flag) { string main_part; SStringPrintf(&main_part, " -%s (%s)", flag.name.c_str(), flag.description.c_str()); const char* c_string = main_part.c_str(); int chars_left = static_cast(main_part.length()); string final_string = ""; int chars_in_line = 0; // how many chars in current line so far? while (1) { assert(chars_left == strlen(c_string)); // Unless there's a \0 in there? const char* newline = strchr(c_string, '\n'); if (newline == NULL && chars_in_line+chars_left < kLineLength) { // The whole remainder of the string fits on this line final_string += c_string; chars_in_line += chars_left; break; } if (newline != NULL && newline - c_string < kLineLength - chars_in_line) { int n = static_cast(newline - c_string); final_string.append(c_string, n); chars_left -= n + 1; c_string += n + 1; } else { // Find the last whitespace on this 80-char line int whitespace = kLineLength-chars_in_line-1; // < 80 chars/line while ( whitespace > 0 && !isspace(c_string[whitespace]) ) { --whitespace; } if (whitespace <= 0) { // Couldn't find any whitespace to make a line break. Just dump the // rest out! final_string += c_string; chars_in_line = kLineLength; // next part gets its own line for sure! break; } final_string += string(c_string, whitespace); chars_in_line += whitespace; while (isspace(c_string[whitespace])) ++whitespace; c_string += whitespace; chars_left -= whitespace; } if (*c_string == '\0') break; StringAppendF(&final_string, "\n "); chars_in_line = 6; } // Append data type AddString(string("type: ") + flag.type, &final_string, &chars_in_line); // The listed default value will be the actual default from the flag // definition in the originating source file, unless the value has // subsequently been modified using SetCommandLineOptionWithMode() with mode // SET_FLAGS_DEFAULT, or by setting FLAGS_foo = bar before ParseCommandLineFlags(). AddString(PrintStringFlagsWithQuotes(flag, "default", false), &final_string, &chars_in_line); if (!flag.is_default) { AddString(PrintStringFlagsWithQuotes(flag, "currently", true), &final_string, &chars_in_line); } StringAppendF(&final_string, "\n"); return final_string; } // Simple routine to xml-escape a string: escape & and < only. static string XMLText(const string& txt) { string ans = txt; for (string::size_type pos = 0; (pos = ans.find("&", pos)) != string::npos; ) ans.replace(pos++, 1, "&"); for (string::size_type pos = 0; (pos = ans.find("<", pos)) != string::npos; ) ans.replace(pos++, 1, "<"); return ans; } static void AddXMLTag(string* r, const char* tag, const string& txt) { StringAppendF(r, "<%s>%s", tag, XMLText(txt).c_str(), tag); } static string DescribeOneFlagInXML(const CommandLineFlagInfo& flag) { // The file and flagname could have been attributes, but default // and meaning need to avoid attribute normalization. This way it // can be parsed by simple programs, in addition to xml parsers. string r(""); AddXMLTag(&r, "file", flag.filename); AddXMLTag(&r, "name", flag.name); AddXMLTag(&r, "meaning", flag.description); AddXMLTag(&r, "default", flag.default_value); AddXMLTag(&r, "current", flag.current_value); AddXMLTag(&r, "type", flag.type); r += ""; return r; } // -------------------------------------------------------------------- // ShowUsageWithFlags() // ShowUsageWithFlagsRestrict() // ShowXMLOfFlags() // These routines variously expose the registry's list of flag // values. ShowUsage*() prints the flag-value information // to stdout in a user-readable format (that's what --help uses). // The Restrict() version limits what flags are shown. // ShowXMLOfFlags() prints the flag-value information to stdout // in a machine-readable format. In all cases, the flags are // sorted: first by filename they are defined in, then by flagname. // -------------------------------------------------------------------- static const char* Basename(const char* filename) { const char* sep = strrchr(filename, PATH_SEPARATOR); return sep ? sep + 1 : filename; } static string Dirname(const string& filename) { string::size_type sep = filename.rfind(PATH_SEPARATOR); return filename.substr(0, (sep == string::npos) ? 0 : sep); } // Test whether a filename contains at least one of the substrings. static bool FileMatchesSubstring(const string& filename, const vector& substrings) { for (vector::const_iterator target = substrings.begin(); target != substrings.end(); ++target) { if (strstr(filename.c_str(), target->c_str()) != NULL) return true; // If the substring starts with a '/', that means that we want // the string to be at the beginning of a directory component. // That should match the first directory component as well, so // we allow '/foo' to match a filename of 'foo'. if (!target->empty() && (*target)[0] == PATH_SEPARATOR && strncmp(filename.c_str(), target->c_str() + 1, strlen(target->c_str() + 1)) == 0) return true; } return false; } // Show help for every filename which matches any of the target substrings. // If substrings is empty, shows help for every file. If a flag's help message // has been stripped (e.g. by adding '#define STRIP_FLAG_HELP 1' // before including gflags/gflags.h), then this flag will not be displayed // by '--help' and its variants. static void ShowUsageWithFlagsMatching(const char *argv0, const vector &substrings) { fprintf(stdout, "%s: %s\n", Basename(argv0), ProgramUsage()); vector flags; GetAllFlags(&flags); // flags are sorted by filename, then flagname string last_filename; // so we know when we're at a new file bool first_directory = true; // controls blank lines between dirs bool found_match = false; // stays false iff no dir matches restrict for (vector::const_iterator flag = flags.begin(); flag != flags.end(); ++flag) { if (substrings.empty() || FileMatchesSubstring(flag->filename, substrings)) { // If the flag has been stripped, pretend that it doesn't exist. if (flag->description == kStrippedFlagHelp) continue; found_match = true; // this flag passed the match! if (flag->filename != last_filename) { // new file if (Dirname(flag->filename) != Dirname(last_filename)) { // new dir! if (!first_directory) fprintf(stdout, "\n\n"); // put blank lines between directories first_directory = false; } fprintf(stdout, "\n Flags from %s:\n", flag->filename.c_str()); last_filename = flag->filename; } // Now print this flag fprintf(stdout, "%s", DescribeOneFlag(*flag).c_str()); } } if (!found_match && !substrings.empty()) { fprintf(stdout, "\n No modules matched: use -help\n"); } } void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict) { vector substrings; if (restrict != NULL && *restrict != '\0') { substrings.push_back(restrict); } ShowUsageWithFlagsMatching(argv0, substrings); } void ShowUsageWithFlags(const char *argv0) { ShowUsageWithFlagsRestrict(argv0, ""); } // Convert the help, program, and usage to xml. static void ShowXMLOfFlags(const char *prog_name) { vector flags; GetAllFlags(&flags); // flags are sorted: by filename, then flagname // XML. There is no corresponding schema yet fprintf(stdout, "\n"); // The document fprintf(stdout, "\n"); // the program name and usage fprintf(stdout, "%s\n", XMLText(Basename(prog_name)).c_str()); fprintf(stdout, "%s\n", XMLText(ProgramUsage()).c_str()); // All the flags for (vector::const_iterator flag = flags.begin(); flag != flags.end(); ++flag) { if (flag->description != kStrippedFlagHelp) fprintf(stdout, "%s\n", DescribeOneFlagInXML(*flag).c_str()); } // The end of the document fprintf(stdout, "\n"); } // -------------------------------------------------------------------- // ShowVersion() // Called upon --version. Prints build-related info. // -------------------------------------------------------------------- static void ShowVersion() { const char* version_string = VersionString(); if (version_string && *version_string) { fprintf(stdout, "%s version %s\n", ProgramInvocationShortName(), version_string); } else { fprintf(stdout, "%s\n", ProgramInvocationShortName()); } # if !defined(NDEBUG) fprintf(stdout, "Debug build (NDEBUG not #defined)\n"); # endif } static void AppendPrognameStrings(vector* substrings, const char* progname) { string r(""); r += PATH_SEPARATOR; r += progname; substrings->push_back(r + "."); substrings->push_back(r + "-main."); substrings->push_back(r + "_main."); } // -------------------------------------------------------------------- // HandleCommandLineHelpFlags() // Checks all the 'reporting' commandline flags to see if any // have been set. If so, handles them appropriately. Note // that all of them, by definition, cause the program to exit // if they trigger. // -------------------------------------------------------------------- void HandleCommandLineHelpFlags() { const char* progname = ProgramInvocationShortName(); HandleCommandLineCompletions(); vector substrings; AppendPrognameStrings(&substrings, progname); if (FLAGS_helpshort) { // show only flags related to this binary: // E.g. for fileutil.cc, want flags containing ... "/fileutil." cc ShowUsageWithFlagsMatching(progname, substrings); gflags_exitfunc(1); } else if (FLAGS_help || FLAGS_helpfull) { // show all options ShowUsageWithFlagsRestrict(progname, ""); // empty restrict gflags_exitfunc(1); } else if (!FLAGS_helpon.empty()) { string restrict = PATH_SEPARATOR + FLAGS_helpon + "."; ShowUsageWithFlagsRestrict(progname, restrict.c_str()); gflags_exitfunc(1); } else if (!FLAGS_helpmatch.empty()) { ShowUsageWithFlagsRestrict(progname, FLAGS_helpmatch.c_str()); gflags_exitfunc(1); } else if (FLAGS_helppackage) { // Shows help for all files in the same directory as main(). We // don't want to resort to looking at dirname(progname), because // the user can pick progname, and it may not relate to the file // where main() resides. So instead, we search the flags for a // filename like "/progname.cc", and take the dirname of that. vector flags; GetAllFlags(&flags); string last_package; for (vector::const_iterator flag = flags.begin(); flag != flags.end(); ++flag) { if (!FileMatchesSubstring(flag->filename, substrings)) continue; const string package = Dirname(flag->filename) + PATH_SEPARATOR; if (package != last_package) { ShowUsageWithFlagsRestrict(progname, package.c_str()); VLOG(7) << "Found package: " << package; if (!last_package.empty()) { // means this isn't our first pkg LOG(WARNING) << "Multiple packages contain a file=" << progname; } last_package = package; } } if (last_package.empty()) { // never found a package to print LOG(WARNING) << "Unable to find a package for file=" << progname; } gflags_exitfunc(1); } else if (FLAGS_helpxml) { ShowXMLOfFlags(progname); gflags_exitfunc(1); } else if (FLAGS_version) { ShowVersion(); // Unlike help, we may be asking for version in a script, so return 0 gflags_exitfunc(0); } } } // namespace GFLAGS_NAMESPACE gflags-2.1.2/src/mutex.h000066400000000000000000000342461250430723500150730ustar00rootroot00000000000000// Copyright (c) 2007, 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. // // --- // // A simple mutex wrapper, supporting locks and read-write locks. // You should assume the locks are *not* re-entrant. // // This class is meant to be internal-only and should be wrapped by an // internal namespace. Before you use this module, please give the // name of your internal namespace for this module. Or, if you want // to expose it, you'll want to move it to the Google namespace. We // cannot put this class in global namespace because there can be some // problems when we have multiple versions of Mutex in each shared object. // // NOTE: by default, we have #ifdef'ed out the TryLock() method. // This is for two reasons: // 1) TryLock() under Windows is a bit annoying (it requires a // #define to be defined very early). // 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG // mode. // If you need TryLock(), and either these two caveats are not a // problem for you, or you're willing to work around them, then // feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs // in the code below. // // CYGWIN NOTE: Cygwin support for rwlock seems to be buggy: // http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html // Because of that, we might as well use windows locks for // cygwin. They seem to be more reliable than the cygwin pthreads layer. // // TRICKY IMPLEMENTATION NOTE: // This class is designed to be safe to use during // dynamic-initialization -- that is, by global constructors that are // run before main() starts. The issue in this case is that // dynamic-initialization happens in an unpredictable order, and it // could be that someone else's dynamic initializer could call a // function that tries to acquire this mutex -- but that all happens // before this mutex's constructor has run. (This can happen even if // the mutex and the function that uses the mutex are in the same .cc // file.) Basically, because Mutex does non-trivial work in its // constructor, it's not, in the naive implementation, safe to use // before dynamic initialization has run on it. // // The solution used here is to pair the actual mutex primitive with a // bool that is set to true when the mutex is dynamically initialized. // (Before that it's false.) Then we modify all mutex routines to // look at the bool, and not try to lock/unlock until the bool makes // it to true (which happens after the Mutex constructor has run.) // // This works because before main() starts -- particularly, during // dynamic initialization -- there are no threads, so a) it's ok that // the mutex operations are a no-op, since we don't need locking then // anyway; and b) we can be quite confident our bool won't change // state between a call to Lock() and a call to Unlock() (that would // require a global constructor in one translation unit to call Lock() // and another global constructor in another translation unit to call // Unlock() later, which is pretty perverse). // // That said, it's tricky, and can conceivably fail; it's safest to // avoid trying to acquire a mutex in a global constructor, if you // can. One way it can fail is that a really smart compiler might // initialize the bool to true at static-initialization time (too // early) rather than at dynamic-initialization time. To discourage // that, we set is_safe_ to true in code (not the constructor // colon-initializer) and set it to true via a function that always // evaluates to true, but that the compiler can't know always // evaluates to true. This should be good enough. // // A related issue is code that could try to access the mutex // after it's been destroyed in the global destructors (because // the Mutex global destructor runs before some other global // destructor, that tries to acquire the mutex). The way we // deal with this is by taking a constructor arg that global // mutexes should pass in, that causes the destructor to do no // work. We still depend on the compiler not doing anything // weird to a Mutex's memory after it is destroyed, but for a // static global variable, that's pretty safe. #ifndef GFLAGS_MUTEX_H_ #define GFLAGS_MUTEX_H_ #include "gflags_declare.h" // to figure out pthreads support #if defined(NO_THREADS) typedef int MutexType; // to keep a lock-count #elif defined(OS_WINDOWS) # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN // We only need minimal includes # endif # ifndef NOMINMAX # define NOMINMAX // Don't want windows to override min()/max() # endif # ifdef GMUTEX_TRYLOCK // We need Windows NT or later for TryEnterCriticalSection(). If you // don't need that functionality, you can remove these _WIN32_WINNT // lines, and change TryLock() to assert(0) or something. # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 # endif # endif # include typedef CRITICAL_SECTION MutexType; #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) // Needed for pthread_rwlock_*. If it causes problems, you could take it // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it // *does* cause problems for FreeBSD, or MacOSX, but isn't needed // for locking there.) # ifdef __linux__ # if _XOPEN_SOURCE < 500 // including not being defined at all # undef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls # endif # endif # include typedef pthread_rwlock_t MutexType; #elif defined(HAVE_PTHREAD) # include typedef pthread_mutex_t MutexType; #else # error Need to implement mutex.h for your architecture, or #define NO_THREADS #endif #include #include // for abort() #define MUTEX_NAMESPACE gflags_mutex_namespace namespace MUTEX_NAMESPACE { class Mutex { public: // This is used for the single-arg constructor enum LinkerInitialized { LINKER_INITIALIZED }; // Create a Mutex that is not held by anybody. This constructor is // typically used for Mutexes allocated on the heap or the stack. inline Mutex(); // This constructor should be used for global, static Mutex objects. // It inhibits work being done by the destructor, which makes it // safer for code that tries to acqiure this mutex in their global // destructor. inline Mutex(LinkerInitialized); // Destructor inline ~Mutex(); inline void Lock(); // Block if needed until free then acquire exclusively inline void Unlock(); // Release a lock acquired via Lock() #ifdef GMUTEX_TRYLOCK inline bool TryLock(); // If free, Lock() and return true, else return false #endif // Note that on systems that don't support read-write locks, these may // be implemented as synonyms to Lock() and Unlock(). So you can use // these for efficiency, but don't use them anyplace where being able // to do shared reads is necessary to avoid deadlock. inline void ReaderLock(); // Block until free or shared then acquire a share inline void ReaderUnlock(); // Release a read share of this Mutex inline void WriterLock() { Lock(); } // Acquire an exclusive lock inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock() private: MutexType mutex_; // We want to make sure that the compiler sets is_safe_ to true only // when we tell it to, and never makes assumptions is_safe_ is // always true. volatile is the most reliable way to do that. volatile bool is_safe_; // This indicates which constructor was called. bool destroy_; inline void SetIsSafe() { is_safe_ = true; } // Catch the error of writing Mutex when intending MutexLock. Mutex(Mutex* /*ignored*/) {} // Disallow "evil" constructors Mutex(const Mutex&); void operator=(const Mutex&); }; // Now the implementation of Mutex for various systems #if defined(NO_THREADS) // When we don't have threads, we can be either reading or writing, // but not both. We can have lots of readers at once (in no-threads // mode, that's most likely to happen in recursive function calls), // but only one writer. We represent this by having mutex_ be -1 when // writing and a number > 0 when reading (and 0 when no lock is held). // // In debug mode, we assert these invariants, while in non-debug mode // we do nothing, for efficiency. That's why everything is in an // assert. Mutex::Mutex() : mutex_(0) { } Mutex::Mutex(Mutex::LinkerInitialized) : mutex_(0) { } Mutex::~Mutex() { assert(mutex_ == 0); } void Mutex::Lock() { assert(--mutex_ == -1); } void Mutex::Unlock() { assert(mutex_++ == -1); } #ifdef GMUTEX_TRYLOCK bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; } #endif void Mutex::ReaderLock() { assert(++mutex_ > 0); } void Mutex::ReaderUnlock() { assert(mutex_-- > 0); } #elif defined(OS_WINDOWS) Mutex::Mutex() : destroy_(true) { InitializeCriticalSection(&mutex_); SetIsSafe(); } Mutex::Mutex(LinkerInitialized) : destroy_(false) { InitializeCriticalSection(&mutex_); SetIsSafe(); } Mutex::~Mutex() { if (destroy_) DeleteCriticalSection(&mutex_); } void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); } void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); } #ifdef GMUTEX_TRYLOCK bool Mutex::TryLock() { return is_safe_ ? TryEnterCriticalSection(&mutex_) != 0 : true; } #endif void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks void Mutex::ReaderUnlock() { Unlock(); } #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) #define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ if (is_safe_ && fncall(&mutex_) != 0) abort(); \ } while (0) Mutex::Mutex() : destroy_(true) { SetIsSafe(); if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort(); } Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) { SetIsSafe(); if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort(); } Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_rwlock_destroy); } void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); } void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } #ifdef GMUTEX_TRYLOCK bool Mutex::TryLock() { return is_safe_ ? pthread_rwlock_trywrlock(&mutex_) == 0 : true; } #endif void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); } void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } #undef SAFE_PTHREAD #elif defined(HAVE_PTHREAD) #define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ if (is_safe_ && fncall(&mutex_) != 0) abort(); \ } while (0) Mutex::Mutex() : destroy_(true) { SetIsSafe(); if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort(); } Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) { SetIsSafe(); if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort(); } Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_mutex_destroy); } void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); } void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); } #ifdef GMUTEX_TRYLOCK bool Mutex::TryLock() { return is_safe_ ? pthread_mutex_trylock(&mutex_) == 0 : true; } #endif void Mutex::ReaderLock() { Lock(); } void Mutex::ReaderUnlock() { Unlock(); } #undef SAFE_PTHREAD #endif // -------------------------------------------------------------------------- // Some helper classes // MutexLock(mu) acquires mu when constructed and releases it when destroyed. class MutexLock { public: explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); } ~MutexLock() { mu_->Unlock(); } private: Mutex * const mu_; // Disallow "evil" constructors MutexLock(const MutexLock&); void operator=(const MutexLock&); }; // ReaderMutexLock and WriterMutexLock do the same, for rwlocks class ReaderMutexLock { public: explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); } ~ReaderMutexLock() { mu_->ReaderUnlock(); } private: Mutex * const mu_; // Disallow "evil" constructors ReaderMutexLock(const ReaderMutexLock&); void operator=(const ReaderMutexLock&); }; class WriterMutexLock { public: explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); } ~WriterMutexLock() { mu_->WriterUnlock(); } private: Mutex * const mu_; // Disallow "evil" constructors WriterMutexLock(const WriterMutexLock&); void operator=(const WriterMutexLock&); }; // Catch bug where variable name is omitted, e.g. MutexLock (&mu); #define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name) #define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name) #define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name) } // namespace MUTEX_NAMESPACE using namespace MUTEX_NAMESPACE; #undef MUTEX_NAMESPACE #endif /* #define GFLAGS_MUTEX_H__ */ gflags-2.1.2/src/util.h000066400000000000000000000333631250430723500147050ustar00rootroot00000000000000// 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 #include #ifdef HAVE_INTTYPES_H # include #endif #include // for va_* #include #include #include #include #include #ifdef HAVE_SYS_STAT_H # include // 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 struct CompileAssert {}; #define COMPILE_ASSERT(expr, msg) \ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // 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 g_testlist; /* the tests to run */ \ static int RUN_ALL_TESTS() { \ std::vector::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(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 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 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(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_ gflags-2.1.2/src/windows_port.cc000066400000000000000000000052421250430723500166170ustar00rootroot00000000000000/* Copyright (c) 2009, 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. * * --- * Author: Craig Silverstein */ #ifndef _WIN32 # error You should only be including windows/port.cc in a windows environment! #endif #include // for strlen(), memset(), memcmp() #include #include // for va_list, va_start, va_end #include #include "windows_port.h" // These call the windows _vsnprintf, but always NUL-terminate. #if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */ #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4996) // ignore _vsnprintf security warning #endif int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { if (size == 0) // not even room for a \0? return -1; // not what C99 says to do, but what windows does str[size-1] = '\0'; return _vsnprintf(str, size-1, format, ap); } #ifdef _MSC_VER # pragma warning(pop) #endif int snprintf(char *str, size_t size, const char *format, ...) { int r; va_list ap; va_start(ap, format); r = vsnprintf(str, size, format, ap); va_end(ap); return r; } #endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */ gflags-2.1.2/src/windows_port.h000066400000000000000000000117701250430723500164640ustar00rootroot00000000000000/* Copyright (c) 2009, 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. * * --- * Author: Craig Silverstein * * These are some portability typedefs and defines to make it a bit * easier to compile this code under VC++. * * Several of these are taken from glib: * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html */ #ifndef GFLAGS_WINDOWS_PORT_H_ #define GFLAGS_WINDOWS_PORT_H_ #include "config.h" // This must be defined before the windows.h is included. // It's needed for mutex.h, to give access to the TryLock method. # if !defined(_WIN32_WINNT) && !(defined( __MINGW32__) || defined(__MINGW64__)) # define _WIN32_WINNT 0x0400 # endif // We always want minimal includes #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN #endif #include #include /* for mkdir */ #include /* for _putenv, getenv */ #include /* need this to override stdio's snprintf, also defines _unlink used by unit tests */ #include /* util.h uses va_copy */ #include /* for _stricmp and _strdup */ /* We can't just use _vsnprintf and _snprintf as drop-in-replacements, * because they don't always NUL-terminate. :-( We also can't use the * name vsnprintf, since windows defines that (but not snprintf (!)). */ #if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */ extern GFLAGS_DLL_DECL int snprintf(char *str, size_t size, const char *format, ...); extern int GFLAGS_DLL_DECL safe_vsnprintf(char *str, size_t size, const char *format, va_list ap); #define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap) #define va_copy(dst, src) (dst) = (src) #endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */ #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4996) // ignore getenv security warning #endif inline void setenv(const char* name, const char* value, int) { // In windows, it's impossible to set a variable to the empty string. // We handle this by setting it to "0" and the NUL-ing out the \0. // That is, we putenv("FOO=0") and then find out where in memory the // putenv wrote "FOO=0", and change it in-place to "FOO=\0". // c.f. http://svn.apache.org/viewvc/stdcxx/trunk/tests/src/environ.cpp?r1=611451&r2=637508&pathrev=637508 static const char* const kFakeZero = "0"; if (*value == '\0') value = kFakeZero; // Apparently the semantics of putenv() is that the input // must live forever, so we leak memory here. :-( const size_t nameval_len = strlen(name) + 1 + strlen(value) + 1; char* nameval = reinterpret_cast(malloc(nameval_len)); snprintf(nameval, nameval_len, "%s=%s", name, value); _putenv(nameval); if (value == kFakeZero) { nameval[nameval_len - 2] = '\0'; // works when putenv() makes no copy if (*getenv(name) != '\0') *getenv(name) = '\0'; // works when putenv() copies nameval } } #ifdef _MSC_VER # pragma warning(pop) #endif #define strcasecmp _stricmp #if defined(_MSC_VER) && _MSC_VER >= 1400 #define strdup _strdup #define unlink _unlink #endif #define PRId32 "d" #define PRIu32 "u" #define PRId64 "I64d" #define PRIu64 "I64u" #if !defined(__MINGW32__) && !defined(__MINGW64__) #define strtoq _strtoi64 #define strtouq _strtoui64 #define strtoll _strtoi64 #define strtoull _strtoui64 #define atoll _atoi64 #endif #ifndef PATH_MAX #define PATH_MAX 1024 #endif #endif /* GFLAGS_WINDOWS_PORT_H_ */ gflags-2.1.2/test/000077500000000000000000000000001250430723500137375ustar00rootroot00000000000000gflags-2.1.2/test/CMakeLists.txt000066400000000000000000000241341250430723500165030ustar00rootroot00000000000000## gflags tests # ---------------------------------------------------------------------------- # output directories set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") # set working directory of test commands set (GFLAGS_FLAGFILES_DIR "${CMAKE_CURRENT_SOURCE_DIR}") # ---------------------------------------------------------------------------- # common include directories and link libraries include_directories ("${CMAKE_CURRENT_SOURCE_DIR}") if (BUILD_SHARED_LIBS) set (type shared) else () set (type static) endif () if (BUILD_gflags_LIB) link_libraries (gflags-${type}) else () link_libraries (gflags_nothreads-${type}) endif () # ---------------------------------------------------------------------------- # STRIP_FLAG_HELP add_executable (gflags_strip_flags_test gflags_strip_flags_test.cc) # Make sure the --help output doesn't print the stripped text. add_gflags_test (strip_flags_help 1 "" "This text should be stripped out" gflags_strip_flags_test --help) # Make sure the stripped text isn't in the binary at all. add_test ( NAME strip_flags_binary COMMAND "${CMAKE_COMMAND}" "-DBINARY=$" -P "${CMAKE_CURRENT_SOURCE_DIR}/gflags_strip_flags_test.cmake" ) # ---------------------------------------------------------------------------- # unit tests configure_file (gflags_unittest.cc gflags_unittest-main.cc COPYONLY) configure_file (gflags_unittest.cc gflags_unittest_main.cc COPYONLY) add_executable (gflags_unittest gflags_unittest.cc) add_executable (gflags_unittest-main gflags_unittest-main.cc) add_executable (gflags_unittest_main gflags_unittest_main.cc) if (OS_WINDOWS) set (SLASH "\\\\") else () set (SLASH "/") endif () # First, just make sure the gflags_unittest works as-is add_gflags_test(unittest 0 "" "" gflags_unittest) # --help should show all flags, including flags from gflags_reporting add_gflags_test(help-reporting 1 "${SLASH}gflags_reporting.cc:" "" gflags_unittest --help) # Make sure that --help prints even very long helpstrings. add_gflags_test(long-helpstring 1 "end of a long helpstring" "" gflags_unittest --help) # Make sure --help reflects flag changes made before flag-parsing add_gflags_test(changed_bool1 1 "-changed_bool1 (changed) type: bool default: true" "" gflags_unittest --help) add_gflags_test(changed_bool2 1 "-changed_bool2 (changed) type: bool default: false currently: true" "" gflags_unittest --help) # And on the command-line, too add_gflags_test(changeable_string_var 1 "-changeable_string_var () type: string default: \"1\" currently: \"2\"" "" gflags_unittest --changeable_string_var 2 --help) # --nohelp and --help=false should be as if we didn't say anything add_gflags_test(nohelp 0 "PASS" "" gflags_unittest --nohelp) add_gflags_test(help=false 0 "PASS" "" gflags_unittest --help=false) # --helpfull is the same as help add_gflags_test(helpfull 1 "${SLASH}gflags_reporting.cc:" "" gflags_unittest --helpfull) # --helpshort should show only flags from the gflags_unittest itself add_gflags_test(helpshort 1 "${SLASH}gflags_unittest.cc:" "${SLASH}gflags_reporting.cc:" gflags_unittest --helpshort) # --helpshort should show the tldflag we created in the gflags_unittest dir add_gflags_test(helpshort-tldflag1 1 "tldflag1" "${SLASH}google.cc:" gflags_unittest --helpshort) add_gflags_test(helpshort-tldflag2 1 "tldflag2" "${SLASH}google.cc:" gflags_unittest --helpshort) # --helpshort should work if the main source file is suffixed with [_-]main add_gflags_test(helpshort-main 1 "${SLASH}gflags_unittest-main.cc:" "${SLASH}gflags_reporting.cc:" gflags_unittest-main --helpshort) add_gflags_test(helpshort_main 1 "${SLASH}gflags_unittest_main.cc:" "${SLASH}gflags_reporting.cc:" gflags_unittest_main --helpshort) # --helpon needs an argument add_gflags_test(helpon 1 "'--helpon' is missing its argument; flag description: show help on" "" gflags_unittest --helpon) # --helpon argument indicates what file we'll show args from add_gflags_test(helpon=gflags 1 "${SLASH}gflags.cc:" "${SLASH}gflags_unittest.cc:" gflags_unittest --helpon=gflags) # another way of specifying the argument add_gflags_test(helpon_gflags 1 "${SLASH}gflags.cc:" "${SLASH}gflags_unittest.cc:" gflags_unittest --helpon gflags) # test another argument add_gflags_test(helpon=gflags_unittest 1 "${SLASH}gflags_unittest.cc:" "${SLASH}gflags.cc:" gflags_unittest --helpon=gflags_unittest) # helpmatch is like helpon but takes substrings add_gflags_test(helpmatch_reporting 1 "${SLASH}gflags_reporting.cc:" "${SLASH}gflags_unittest.cc:" gflags_unittest -helpmatch reporting) add_gflags_test(helpmatch=unittest 1 "${SLASH}gflags_unittest.cc:" "${SLASH}gflags.cc:" gflags_unittest -helpmatch=unittest) # if no flags are found with helpmatch or helpon, suggest --help add_gflags_test(helpmatch=nosuchsubstring 1 "No modules matched" "${SLASH}gflags_unittest.cc:" gflags_unittest -helpmatch=nosuchsubstring) add_gflags_test(helpon=nosuchmodule 1 "No modules matched" "${SLASH}gflags_unittest.cc:" gflags_unittest -helpon=nosuchmodule) # helppackage shows all the flags in the same dir as this unittest # --help should show all flags, including flags from google.cc add_gflags_test(helppackage 1 "${SLASH}gflags_reporting.cc:" "" gflags_unittest --helppackage) # xml! add_gflags_test(helpxml 1 "${SLASH}gflags_unittest.cc" "${SLASH}gflags_unittest.cc:" gflags_unittest --helpxml) # just print the version info and exit add_gflags_test(version-1 0 "gflags_unittest" "${SLASH}gflags_unittest.cc:" gflags_unittest --version) add_gflags_test(version-2 0 "version test_version" "${SLASH}gflags_unittest.cc:" gflags_unittest --version) # --undefok is a fun flag... add_gflags_test(undefok-1 1 "unknown command line flag 'foo'" "" gflags_unittest --undefok= --foo --unused_bool) add_gflags_test(undefok-2 0 "PASS" "" gflags_unittest --undefok=foo --foo --unused_bool) # If you say foo is ok to be undefined, we'll accept --nofoo as well add_gflags_test(undefok-3 0 "PASS" "" gflags_unittest --undefok=foo --nofoo --unused_bool) # It's ok if the foo is in the middle add_gflags_test(undefok-4 0 "PASS" "" gflags_unittest --undefok=fee,fi,foo,fum --foo --unused_bool) # But the spelling has to be just right... add_gflags_test(undefok-5 1 "unknown command line flag 'foo'" "" gflags_unittest --undefok=fo --foo --unused_bool) add_gflags_test(undefok-6 1 "unknown command line flag 'foo'" "" gflags_unittest --undefok=foot --foo --unused_bool) # See if we can successfully load our flags from the flagfile add_gflags_test(flagfile.1 0 "gflags_unittest" "${SLASH}gflags_unittest.cc:" gflags_unittest "--flagfile=flagfile.1") add_gflags_test(flagfile.2 0 "PASS" "" gflags_unittest "--flagfile=flagfile.2") add_gflags_test(flagfile.3 0 "PASS" "" gflags_unittest "--flagfile=flagfile.3") # Also try to load flags from the environment add_gflags_test(fromenv=version 0 "gflags_unittest" "${SLASH}gflags_unittest.cc:" gflags_unittest --fromenv=version) add_gflags_test(tryfromenv=version 0 "gflags_unittest" "${SLASH}gflags_unittest.cc:" gflags_unittest --tryfromenv=version) add_gflags_test(fromenv=help 0 "PASS" "" gflags_unittest --fromenv=help) add_gflags_test(tryfromenv=help 0 "PASS" "" gflags_unittest --tryfromenv=help) add_gflags_test(fromenv=helpfull 1 "helpfull not found in environment" "" gflags_unittest --fromenv=helpfull) add_gflags_test(tryfromenv=helpfull 0 "PASS" "" gflags_unittest --tryfromenv=helpfull) add_gflags_test(tryfromenv=undefok 0 "PASS" "" gflags_unittest --tryfromenv=undefok --foo) add_gflags_test(tryfromenv=weirdo 1 "unknown command line flag" "" gflags_unittest --tryfromenv=weirdo) add_gflags_test(tryfromenv-multiple 0 "gflags_unittest" "${SLASH}gflags_unittest.cc:" gflags_unittest --tryfromenv=test_bool,version,unused_bool) add_gflags_test(fromenv=test_bool 1 "not found in environment" "" gflags_unittest --fromenv=test_bool) add_gflags_test(fromenv=test_bool-ok 1 "unknown command line flag" "" gflags_unittest --fromenv=test_bool,ok) # Here, the --version overrides the fromenv add_gflags_test(version-overrides-fromenv 0 "gflags_unittest" "${SLASH}gflags_unittest.cc:" gflags_unittest --fromenv=test_bool,version,ok) # Make sure -- by itself stops argv processing add_gflags_test(dashdash 0 "PASS" "" gflags_unittest -- --help) # And we should die if the flag value doesn't pass the validator add_gflags_test(always_fail 1 "ERROR: failed validation of new value 'true' for flag 'always_fail'" "" gflags_unittest --always_fail) # And if locking in validators fails # TODO(andreas): Worked on Windows 7 Release configuration, but causes # debugger abort() intervention in case of Debug configuration. #add_gflags_test(deadlock_if_cant_lock 0 "PASS" "" gflags_unittest --deadlock_if_cant_lock) # ---------------------------------------------------------------------------- # use gflags_declare.h add_executable (gflags_declare_test gflags_declare_test.cc gflags_declare_flags.cc) add_test(NAME gflags_declare COMMAND gflags_declare_test --message "Hello gflags!") set_tests_properties(gflags_declare PROPERTIES PASS_REGULAR_EXPRESSION "Hello gflags!") # ---------------------------------------------------------------------------- # (negative) compilation tests if (BUILD_NC_TESTS) find_package (PythonInterp) if (NOT PYTHON_EXECUTABLE) message (FATAL_ERROR "No Python installation found! It is required by the negative compilation tests." " Either install Python or set BUILD_NC_TESTS to FALSE and try again.") endif () set (SRCDIR "${CMAKE_CURRENT_SOURCE_DIR}/nc") configure_file (gflags_nc.py.in "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/nc.py" @ONLY) macro (add_gflags_nc_test name) add_test ( NAME nc_${name} COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/nc.py" ${name} ) endmacro () add_gflags_nc_test (sanity) add_gflags_nc_test (swapped_args) add_gflags_nc_test (int_instead_of_bool) add_gflags_nc_test (bool_in_quotes) add_gflags_nc_test (define_string_with_0) endif () gflags-2.1.2/test/config_for_unittests.h000066400000000000000000000063041250430723500203500ustar00rootroot00000000000000// Copyright (c) 2007, 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. // --- // All Rights Reserved. // // // This file is needed for windows -- unittests are not part of the // gflags dll, but still want to include config.h just like the // dll does, so they can use internal tools and APIs for testing. // // The problem is that config.h declares GFLAGS_DLL_DECL to be // for exporting symbols, but the unittest needs to *import* symbols // (since it's not the dll). // // The solution is to have this file, which is just like config.h but // sets GFLAGS_DLL_DECL to do a dllimport instead of a dllexport. // // The reason we need this extra GFLAGS_DLL_DECL_FOR_UNITTESTS // variable is in case people want to set GFLAGS_DLL_DECL explicitly // to something other than __declspec(dllexport). In that case, they // may want to use something other than __declspec(dllimport) for the // unittest case. For that, we allow folks to define both // GFLAGS_DLL_DECL and GFLAGS_DLL_DECL_FOR_UNITTESTS explicitly. // // NOTE: This file is equivalent to config.h on non-windows systems, // which never defined GFLAGS_DLL_DECL_FOR_UNITTESTS and always // define GFLAGS_DLL_DECL to the empty string. #include "config.h" #ifdef GFLAGS_DLL_DECL # undef GFLAGS_DLL_DECL #endif #ifdef GFLAGS_DLL_DEFINE_FLAG # undef GFLAGS_DLL_DEFINE_FLAG #endif #ifdef GFLAGS_DLL_DECLARE_FLAG # undef GFLAGS_DLL_DECLARE_FLAG #endif #ifdef GFLAGS_DLL_DECL_FOR_UNITTESTS # define GFLAGS_DLL_DECL GFLAGS_DLL_DECL_FOR_UNITTESTS #else # define GFLAGS_DLL_DECL // if DLL_DECL_FOR_UNITTESTS isn't defined, use "" #endif // Import flags defined by gflags.cc #if GFLAGS_IS_A_DLL && defined(_MSC_VER) # define GFLAGS_DLL_DECLARE_FLAG __declspec(dllimport) #else # define GFLAGS_DLL_DECLARE_FLAG #endifgflags-2.1.2/test/flagfile.1000066400000000000000000000000111250430723500155620ustar00rootroot00000000000000--versiongflags-2.1.2/test/flagfile.2000066400000000000000000000000311250430723500155650ustar00rootroot00000000000000--foo=bar --nounused_boolgflags-2.1.2/test/flagfile.3000066400000000000000000000000251250430723500155710ustar00rootroot00000000000000--flagfile=flagfile.2gflags-2.1.2/test/gflags_declare_flags.cc000066400000000000000000000002631250430723500203450ustar00rootroot00000000000000#include #include DECLARE_string(message); // in gflags_delcare_test.cc void print_message() { std::cout << FLAGS_message << std::endl; } gflags-2.1.2/test/gflags_declare_test.cc000066400000000000000000000005101250430723500202230ustar00rootroot00000000000000#include DEFINE_string(message, "", "The message to print"); void print_message(); // in gflags_declare_flags.cc int main(int argc, char **argv) { gflags::SetUsageMessage("Test compilation and use of gflags_declare.h"); gflags::ParseCommandLineFlags(&argc, &argv, true); print_message(); return 0; } gflags-2.1.2/test/gflags_nc.py.in000066400000000000000000000021241250430723500166400ustar00rootroot00000000000000#!/usr/bin/env python import os import sys import subprocess import shutil CMAKE = '@CMAKE_COMMAND@' TMPDIR = '@TEMPDIR@' SRCDIR = '@SRCDIR@' GFLAGS_DIR = '@gflags_BINARY_DIR@' if __name__ == "__main__": if len(sys.argv) != 2: sys.stderr.write(' '.join(['usage:', sys.argv[0], '\n'])) sys.exit(1) test_name = sys.argv[1] bindir = os.path.join(TMPDIR, '_'.join(['nc', test_name])) if TMPDIR == '': sys.stderr.write('Temporary directory not set!\n') sys.exit(1) # create build directory if os.path.isdir(bindir): shutil.rmtree(bindir) os.makedirs(bindir) # configure the build tree if subprocess.call([CMAKE, '-Dgflags_DIR:PATH='+GFLAGS_DIR, '-DTEST_NAME:STRING='+test_name, SRCDIR], cwd=bindir) != 0: sys.stderr.write('Failed to configure the build tree!\n') sys.exit(1) # try build, which is supposed to fail (except in case of the sanity check) if subprocess.call([CMAKE, '--build', bindir], cwd=bindir) == 0 and test_name != 'sanity': sys.stderr.write('Build expected to fail, but it succeeded!\n') sys.exit(1) sys.exit(0) gflags-2.1.2/test/gflags_strip_flags_test.cc000066400000000000000000000047371250430723500211600ustar00rootroot00000000000000// 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. // // --- // Author: csilvers@google.com (Craig Silverstein) // // A simple program that uses STRIP_FLAG_HELP. We'll have a shell // script that runs 'strings' over this program and makes sure // that the help string is not in there. #include "config_for_unittests.h" #define STRIP_FLAG_HELP 1 #include #include using GFLAGS_NAMESPACE::SetUsageMessage; using GFLAGS_NAMESPACE::ParseCommandLineFlags; DEFINE_bool(test, true, "This text should be stripped out"); int main(int argc, char** argv) { SetUsageMessage("Usage message"); ParseCommandLineFlags(&argc, &argv, false); // Unfortunately, for us, libtool can replace executables with a shell // script that does some work before calling the 'real' executable // under a different name. We need the 'real' executable name to run // 'strings' on it, so we construct this binary to print the real // name (argv[0]) on stdout when run. puts(argv[0]); return 0; } gflags-2.1.2/test/gflags_strip_flags_test.cmake000066400000000000000000000004151250430723500216400ustar00rootroot00000000000000if (NOT BINARY) message (FATAl_ERROR "BINARY file to check not specified!") endif () file (STRINGS "${BINARY}" strings REGEX "This text should be stripped out") if (strings) message (FATAL_ERROR "Text not stripped from binary like it should be: ${BINARY}") endif ()gflags-2.1.2/test/gflags_unittest.cc000066400000000000000000001452031250430723500174550ustar00rootroot00000000000000// Copyright (c) 2005, 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. // --- // // For now, this unit test does not cover all features of // gflags.cc #include "config_for_unittests.h" #include #include // for isinf() and isnan() #include #include #include #ifdef HAVE_UNISTD_H # include // for unlink() #endif #include #include #include "util.h" TEST_INIT EXPECT_DEATH_INIT // I don't actually use this header file, but #include it under the // old location to make sure that the include-header-forwarding // works. But don't bother on windows; the windows port is so new // it never had the old location-names. #ifndef _MSC_VER #include void (*unused_fn)() = &GFLAGS_NAMESPACE::HandleCommandLineCompletions; #endif using std::string; using std::vector; using GFLAGS_NAMESPACE::int32; using GFLAGS_NAMESPACE::FlagRegisterer; using GFLAGS_NAMESPACE::StringFromEnv; using GFLAGS_NAMESPACE::RegisterFlagValidator; using GFLAGS_NAMESPACE::CommandLineFlagInfo; using GFLAGS_NAMESPACE::GetAllFlags; DEFINE_string(test_tmpdir, "", "Dir we use for temp files"); DEFINE_string(srcdir, StringFromEnv("SRCDIR", "."), "Source-dir root, needed to find gflags_unittest_flagfile"); DECLARE_string(tryfromenv); // in gflags.cc DEFINE_bool(test_bool, false, "tests bool-ness"); DEFINE_int32(test_int32, -1, ""); DEFINE_int64(test_int64, -2, ""); DEFINE_uint64(test_uint64, 2, ""); DEFINE_double(test_double, -1.0, ""); DEFINE_string(test_string, "initial", ""); // // The below ugliness gets some additional code coverage in the -helpxml // and -helpmatch test cases having to do with string lengths and formatting // DEFINE_bool(test_bool_with_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_long_name, false, "extremely_extremely_extremely_extremely_extremely_extremely_extremely_extremely_long_meaning"); DEFINE_string(test_str1, "initial", ""); DEFINE_string(test_str2, "initial", ""); DEFINE_string(test_str3, "initial", ""); // This is used to test setting tryfromenv manually DEFINE_string(test_tryfromenv, "initial", ""); // Don't try this at home! static int changeable_var = 12; DEFINE_int32(changeable_var, ++changeable_var, ""); static int changeable_bool_var = 8008; DEFINE_bool(changeable_bool_var, ++changeable_bool_var == 8009, ""); static int changeable_string_var = 0; static string ChangeableString() { char r[] = {static_cast('0' + ++changeable_string_var), '\0'}; return r; } DEFINE_string(changeable_string_var, ChangeableString(), ""); // These are never used in this unittest, but can be used by // gflags_unittest.sh when it needs to specify flags // that are legal for gflags_unittest but don't need to // be a particular value. DEFINE_bool(unused_bool, true, "unused bool-ness"); DEFINE_int32(unused_int32, -1001, ""); DEFINE_int64(unused_int64, -2001, ""); DEFINE_uint64(unused_uint64, 2000, ""); DEFINE_double(unused_double, -1000.0, ""); DEFINE_string(unused_string, "unused", ""); // These flags are used by gflags_unittest.sh DEFINE_bool(changed_bool1, false, "changed"); DEFINE_bool(changed_bool2, false, "changed"); DEFINE_bool(long_helpstring, false, "This helpstring goes on forever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever and ever and ever and ever and ever and ever and ever and " "ever. This is the end of a long helpstring"); static bool AlwaysFail(const char* flag, bool value) { return value == false; } DEFINE_bool(always_fail, false, "will fail to validate when you set it"); DEFINE_validator(always_fail, AlwaysFail); // See the comment by GetAllFlags in gflags.h static bool DeadlockIfCantLockInValidators(const char* flag, bool value) { if (!value) { return true; } vector dummy; GetAllFlags(&dummy); return true; } DEFINE_bool(deadlock_if_cant_lock, false, "will deadlock if set to true and " "if locking of registry in validators fails."); DEFINE_validator(deadlock_if_cant_lock, DeadlockIfCantLockInValidators); #define MAKEFLAG(x) DEFINE_int32(test_flag_num##x, x, "Test flag") // Define 10 flags #define MAKEFLAG10(x) \ MAKEFLAG(x##0); \ MAKEFLAG(x##1); \ MAKEFLAG(x##2); \ MAKEFLAG(x##3); \ MAKEFLAG(x##4); \ MAKEFLAG(x##5); \ MAKEFLAG(x##6); \ MAKEFLAG(x##7); \ MAKEFLAG(x##8); \ MAKEFLAG(x##9) // Define 100 flags #define MAKEFLAG100(x) \ MAKEFLAG10(x##0); \ MAKEFLAG10(x##1); \ MAKEFLAG10(x##2); \ MAKEFLAG10(x##3); \ MAKEFLAG10(x##4); \ MAKEFLAG10(x##5); \ MAKEFLAG10(x##6); \ MAKEFLAG10(x##7); \ MAKEFLAG10(x##8); \ MAKEFLAG10(x##9) // Define a bunch of command-line flags. Each occurrence of the MAKEFLAG100 // macro defines 100 integer flags. This lets us test the effect of having // many flags on startup time. MAKEFLAG100(1); MAKEFLAG100(2); MAKEFLAG100(3); MAKEFLAG100(4); MAKEFLAG100(5); MAKEFLAG100(6); MAKEFLAG100(7); MAKEFLAG100(8); MAKEFLAG100(9); MAKEFLAG100(10); MAKEFLAG100(11); MAKEFLAG100(12); MAKEFLAG100(13); MAKEFLAG100(14); MAKEFLAG100(15); #undef MAKEFLAG100 #undef MAKEFLAG10 #undef MAKEFLAG // This is a pseudo-flag -- we want to register a flag with a filename // at the top level, but there is no way to do this except by faking // the filename. namespace fLI { static const int32 FLAGS_nonotldflag1 = 12; int32 FLAGS_tldflag1 = FLAGS_nonotldflag1; int32 FLAGS_notldflag1 = FLAGS_nonotldflag1; static FlagRegisterer o_tldflag1( "tldflag1", "int32", "should show up in --helpshort", "gflags_unittest.cc", &FLAGS_tldflag1, &FLAGS_notldflag1); } using fLI::FLAGS_tldflag1; namespace fLI { static const int32 FLAGS_nonotldflag2 = 23; int32 FLAGS_tldflag2 = FLAGS_nonotldflag2; int32 FLAGS_notldflag2 = FLAGS_nonotldflag2; static FlagRegisterer o_tldflag2( "tldflag2", "int32", "should show up in --helpshort", "gflags_unittest.", &FLAGS_tldflag2, &FLAGS_notldflag2); } using fLI::FLAGS_tldflag2; namespace GFLAGS_NAMESPACE { namespace { static string TmpFile(const string& basename) { #ifdef _MSC_VER return FLAGS_test_tmpdir + "\\" + basename; #else return FLAGS_test_tmpdir + "/" + basename; #endif } // Returns the definition of the --flagfile flag to be used in the tests. // Must be called after ParseCommandLineFlags(). static const char* GetFlagFileFlag() { #ifdef _MSC_VER static const string flagfile = FLAGS_srcdir + "\\gflags_unittest_flagfile"; #else static const string flagfile = FLAGS_srcdir + "/gflags_unittest_flagfile"; #endif static const string flagfile_flag = string("--flagfile=") + flagfile; return flagfile_flag.c_str(); } // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template struct CompileAssertTypesEqual; template struct CompileAssertTypesEqual { }; template void AssertIsType(Actual& x) { CompileAssertTypesEqual(); } // Verify all the flags are the right type. TEST(FlagTypes, FlagTypes) { AssertIsType(FLAGS_test_bool); AssertIsType(FLAGS_test_int32); AssertIsType(FLAGS_test_int64); AssertIsType(FLAGS_test_uint64); AssertIsType(FLAGS_test_double); AssertIsType(FLAGS_test_string); } #ifdef GTEST_HAS_DEATH_TEST // Death tests for "help" options. // // The help system automatically calls gflags_exitfunc(1) when you specify any of // the help-related flags ("-helpmatch", "-helpxml") so we can't test // those mainline. // Tests that "-helpmatch" causes the process to die. TEST(ReadFlagsFromStringDeathTest, HelpMatch) { EXPECT_DEATH(ReadFlagsFromString("-helpmatch=base", GetArgv0(), true), ""); } // Tests that "-helpxml" causes the process to die. TEST(ReadFlagsFromStringDeathTest, HelpXml) { EXPECT_DEATH(ReadFlagsFromString("-helpxml", GetArgv0(), true), ""); } #endif // A subroutine needed for testing reading flags from a string. void TestFlagString(const string& flags, const string& expected_string, bool expected_bool, int32 expected_int32, double expected_double) { EXPECT_TRUE(ReadFlagsFromString(flags, GetArgv0(), // errors are fatal true)); EXPECT_EQ(expected_string, FLAGS_test_string); EXPECT_EQ(expected_bool, FLAGS_test_bool); EXPECT_EQ(expected_int32, FLAGS_test_int32); EXPECT_DOUBLE_EQ(expected_double, FLAGS_test_double); } // Tests reading flags from a string. TEST(FlagFileTest, ReadFlagsFromString) { TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "-test_bool=true\n" " -test_int32=1\n" "-test_double=0.0\n", // Expected values "continued", true, 1, 0.0); TestFlagString( // Flag string "# let's make sure it can update values\n" "-test_string=initial\n" "-test_bool=false\n" "-test_int32=123\n" "-test_double=123.0\n", // Expected values "initial", false, 123, 123.0); } // Tests the filename part of the flagfile TEST(FlagFileTest, FilenamesOurfileLast) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "not_our_filename\n" "-test_bool=true\n" " -test_int32=1\n" "gflags_unittest\n" "-test_double=1000.0\n", // Expected values "continued", false, -1, 1000.0); } TEST(FlagFileTest, FilenamesOurfileFirst) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "gflags_unittest\n" "-test_bool=true\n" " -test_int32=1\n" "not_our_filename\n" "-test_double=1000.0\n", // Expected values "continued", true, 1, -1.0); } #if defined(HAVE_FNMATCH_H) || defined(HAVE_SHLWAPI_H) // otherwise glob isn't supported TEST(FlagFileTest, FilenamesOurfileGlob) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "*flags*\n" "-test_bool=true\n" " -test_int32=1\n" "flags\n" "-test_double=1000.0\n", // Expected values "continued", true, 1, -1.0); } TEST(FlagFileTest, FilenamesOurfileInBigList) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "*first* *flags* *third*\n" "-test_bool=true\n" " -test_int32=1\n" "flags\n" "-test_double=1000.0\n", // Expected values "continued", true, 1, -1.0); } #endif // defined(HAVE_FNMATCH_H) || defined(HAVE_SHLWAPI_H) // Tests that a failed flag-from-string read keeps flags at default values TEST(FlagFileTest, FailReadFlagsFromString) { FLAGS_test_int32 = 119; string flags("# let's make sure it can update values\n" "-test_string=non_initial\n" "-test_bool=false\n" "-test_int32=123\n" "-test_double=illegal\n"); EXPECT_FALSE(ReadFlagsFromString(flags, GetArgv0(), // errors are fatal false)); EXPECT_EQ(119, FLAGS_test_int32); EXPECT_EQ("initial", FLAGS_test_string); } // Tests that flags can be set to ordinary values. TEST(SetFlagValueTest, OrdinaryValues) { EXPECT_EQ("initial", FLAGS_test_str1); SetCommandLineOptionWithMode("test_str1", "second", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str1); // set; was default SetCommandLineOptionWithMode("test_str1", "third", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str1); // already set once FLAGS_test_str1 = "initial"; SetCommandLineOptionWithMode("test_str1", "third", SET_FLAG_IF_DEFAULT); EXPECT_EQ("initial", FLAGS_test_str1); // still already set before SetCommandLineOptionWithMode("test_str1", "third", SET_FLAGS_VALUE); EXPECT_EQ("third", FLAGS_test_str1); // changed value SetCommandLineOptionWithMode("test_str1", "fourth", SET_FLAGS_DEFAULT); EXPECT_EQ("third", FLAGS_test_str1); // value not changed (already set before) EXPECT_EQ("initial", FLAGS_test_str2); SetCommandLineOptionWithMode("test_str2", "second", SET_FLAGS_DEFAULT); EXPECT_EQ("second", FLAGS_test_str2); // changed (was default) FLAGS_test_str2 = "extra"; EXPECT_EQ("extra", FLAGS_test_str2); FLAGS_test_str2 = "second"; SetCommandLineOptionWithMode("test_str2", "third", SET_FLAGS_DEFAULT); EXPECT_EQ("third", FLAGS_test_str2); // still changed (was equal to default) SetCommandLineOptionWithMode("test_str2", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("fourth", FLAGS_test_str2); // changed (was default) EXPECT_EQ("initial", FLAGS_test_str3); SetCommandLineOptionWithMode("test_str3", "second", SET_FLAGS_DEFAULT); EXPECT_EQ("second", FLAGS_test_str3); // changed FLAGS_test_str3 = "third"; SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAGS_DEFAULT); EXPECT_EQ("third", FLAGS_test_str3); // not changed (was set) SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("third", FLAGS_test_str3); // not changed (was set) SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAGS_VALUE); EXPECT_EQ("fourth", FLAGS_test_str3); // changed value } // Tests that flags can be set to exceptional values. // Note: apparently MINGW doesn't parse inf and nan correctly: // http://www.mail-archive.com/bug-gnulib@gnu.org/msg09573.html // This url says FreeBSD also has a problem, but I didn't see that. TEST(SetFlagValueTest, ExceptionalValues) { #if defined(isinf) && !defined(__MINGW32__) EXPECT_EQ("test_double set to inf\n", SetCommandLineOption("test_double", "inf")); EXPECT_INF(FLAGS_test_double); EXPECT_EQ("test_double set to inf\n", SetCommandLineOption("test_double", "INF")); EXPECT_INF(FLAGS_test_double); #endif // set some bad values EXPECT_EQ("", SetCommandLineOption("test_double", "0.1xxx")); EXPECT_EQ("", SetCommandLineOption("test_double", " ")); EXPECT_EQ("", SetCommandLineOption("test_double", "")); #if defined(isinf) && !defined(__MINGW32__) EXPECT_EQ("test_double set to -inf\n", SetCommandLineOption("test_double", "-inf")); EXPECT_INF(FLAGS_test_double); EXPECT_GT(0, FLAGS_test_double); #endif #if defined(isnan) && !defined(__MINGW32__) EXPECT_EQ("test_double set to nan\n", SetCommandLineOption("test_double", "NaN")); EXPECT_NAN(FLAGS_test_double); #endif } // Tests that integer flags can be specified in many ways TEST(SetFlagValueTest, DifferentRadices) { EXPECT_EQ("test_int32 set to 12\n", SetCommandLineOption("test_int32", "12")); EXPECT_EQ("test_int32 set to 16\n", SetCommandLineOption("test_int32", "0x10")); EXPECT_EQ("test_int32 set to 34\n", SetCommandLineOption("test_int32", "0X22")); // Leading 0 is *not* octal; it's still decimal EXPECT_EQ("test_int32 set to 10\n", SetCommandLineOption("test_int32", "010")); } // Tests what happens when you try to set a flag to an illegal value TEST(SetFlagValueTest, IllegalValues) { FLAGS_test_bool = true; FLAGS_test_int32 = 119; FLAGS_test_int64 = 1191; FLAGS_test_uint64 = 11911; EXPECT_EQ("", SetCommandLineOption("test_bool", "12")); EXPECT_EQ("", SetCommandLineOption("test_int32", "7000000000000")); EXPECT_EQ("", SetCommandLineOption("test_uint64", "-1")); EXPECT_EQ("", SetCommandLineOption("test_int64", "not a number!")); // Test the empty string with each type of input EXPECT_EQ("", SetCommandLineOption("test_bool", "")); EXPECT_EQ("", SetCommandLineOption("test_int32", "")); EXPECT_EQ("", SetCommandLineOption("test_int64", "")); EXPECT_EQ("", SetCommandLineOption("test_uint64", "")); EXPECT_EQ("", SetCommandLineOption("test_double", "")); EXPECT_EQ("test_string set to \n", SetCommandLineOption("test_string", "")); EXPECT_TRUE(FLAGS_test_bool); EXPECT_EQ(119, FLAGS_test_int32); EXPECT_EQ(1191, FLAGS_test_int64); EXPECT_EQ(11911, FLAGS_test_uint64); } // Tests that we only evaluate macro args once TEST(MacroArgs, EvaluateOnce) { EXPECT_EQ(13, FLAGS_changeable_var); // Make sure we don't ++ the value somehow, when evaluating the flag. EXPECT_EQ(13, FLAGS_changeable_var); // Make sure the macro only evaluated this var once. EXPECT_EQ(13, changeable_var); // Make sure the actual value and default value are the same SetCommandLineOptionWithMode("changeable_var", "21", SET_FLAG_IF_DEFAULT); EXPECT_EQ(21, FLAGS_changeable_var); } TEST(MacroArgs, EvaluateOnceBool) { EXPECT_TRUE(FLAGS_changeable_bool_var); EXPECT_TRUE(FLAGS_changeable_bool_var); EXPECT_EQ(8009, changeable_bool_var); SetCommandLineOptionWithMode("changeable_bool_var", "false", SET_FLAG_IF_DEFAULT); EXPECT_FALSE(FLAGS_changeable_bool_var); } TEST(MacroArgs, EvaluateOnceStrings) { EXPECT_EQ("1", FLAGS_changeable_string_var); EXPECT_EQ("1", FLAGS_changeable_string_var); EXPECT_EQ(1, changeable_string_var); SetCommandLineOptionWithMode("changeable_string_var", "different", SET_FLAG_IF_DEFAULT); EXPECT_EQ("different", FLAGS_changeable_string_var); } // Tests that the FooFromEnv does the right thing TEST(FromEnvTest, LegalValues) { setenv("BOOL_VAL1", "true", 1); setenv("BOOL_VAL2", "false", 1); setenv("BOOL_VAL3", "1", 1); setenv("BOOL_VAL4", "F", 1); EXPECT_TRUE(BoolFromEnv("BOOL_VAL1", false)); EXPECT_FALSE(BoolFromEnv("BOOL_VAL2", true)); EXPECT_TRUE(BoolFromEnv("BOOL_VAL3", false)); EXPECT_FALSE(BoolFromEnv("BOOL_VAL4", true)); EXPECT_TRUE(BoolFromEnv("BOOL_VAL_UNKNOWN", true)); EXPECT_FALSE(BoolFromEnv("BOOL_VAL_UNKNOWN", false)); setenv("INT_VAL1", "1", 1); setenv("INT_VAL2", "-1", 1); EXPECT_EQ(1, Int32FromEnv("INT_VAL1", 10)); EXPECT_EQ(-1, Int32FromEnv("INT_VAL2", 10)); EXPECT_EQ(10, Int32FromEnv("INT_VAL_UNKNOWN", 10)); setenv("INT_VAL3", "1099511627776", 1); EXPECT_EQ(1, Int64FromEnv("INT_VAL1", 20)); EXPECT_EQ(-1, Int64FromEnv("INT_VAL2", 20)); EXPECT_EQ(1099511627776LL, Int64FromEnv("INT_VAL3", 20)); EXPECT_EQ(20, Int64FromEnv("INT_VAL_UNKNOWN", 20)); EXPECT_EQ(1, Uint64FromEnv("INT_VAL1", 30)); EXPECT_EQ(1099511627776ULL, Uint64FromEnv("INT_VAL3", 30)); EXPECT_EQ(30, Uint64FromEnv("INT_VAL_UNKNOWN", 30)); // I pick values here that can be easily represented exactly in floating-point setenv("DOUBLE_VAL1", "0.0", 1); setenv("DOUBLE_VAL2", "1.0", 1); setenv("DOUBLE_VAL3", "-1.0", 1); EXPECT_EQ(0.0, DoubleFromEnv("DOUBLE_VAL1", 40.0)); EXPECT_EQ(1.0, DoubleFromEnv("DOUBLE_VAL2", 40.0)); EXPECT_EQ(-1.0, DoubleFromEnv("DOUBLE_VAL3", 40.0)); EXPECT_EQ(40.0, DoubleFromEnv("DOUBLE_VAL_UNKNOWN", 40.0)); setenv("STRING_VAL1", "", 1); setenv("STRING_VAL2", "my happy string!", 1); EXPECT_STREQ("", StringFromEnv("STRING_VAL1", "unknown")); EXPECT_STREQ("my happy string!", StringFromEnv("STRING_VAL2", "unknown")); EXPECT_STREQ("unknown", StringFromEnv("STRING_VAL_UNKNOWN", "unknown")); } #ifdef GTEST_HAS_DEATH_TEST // Tests that the FooFromEnv dies on parse-error TEST(FromEnvDeathTest, IllegalValues) { setenv("BOOL_BAD1", "so true!", 1); setenv("BOOL_BAD2", "", 1); EXPECT_DEATH(BoolFromEnv("BOOL_BAD1", false), "error parsing env variable"); EXPECT_DEATH(BoolFromEnv("BOOL_BAD2", true), "error parsing env variable"); setenv("INT_BAD1", "one", 1); setenv("INT_BAD2", "100000000000000000", 1); setenv("INT_BAD3", "0xx10", 1); setenv("INT_BAD4", "", 1); EXPECT_DEATH(Int32FromEnv("INT_BAD1", 10), "error parsing env variable"); EXPECT_DEATH(Int32FromEnv("INT_BAD2", 10), "error parsing env variable"); EXPECT_DEATH(Int32FromEnv("INT_BAD3", 10), "error parsing env variable"); EXPECT_DEATH(Int32FromEnv("INT_BAD4", 10), "error parsing env variable"); setenv("BIGINT_BAD1", "18446744073709551616000", 1); EXPECT_DEATH(Int64FromEnv("INT_BAD1", 20), "error parsing env variable"); EXPECT_DEATH(Int64FromEnv("INT_BAD3", 20), "error parsing env variable"); EXPECT_DEATH(Int64FromEnv("INT_BAD4", 20), "error parsing env variable"); EXPECT_DEATH(Int64FromEnv("BIGINT_BAD1", 200), "error parsing env variable"); setenv("BIGINT_BAD2", "-1", 1); EXPECT_DEATH(Uint64FromEnv("INT_BAD1", 30), "error parsing env variable"); EXPECT_DEATH(Uint64FromEnv("INT_BAD3", 30), "error parsing env variable"); EXPECT_DEATH(Uint64FromEnv("INT_BAD4", 30), "error parsing env variable"); EXPECT_DEATH(Uint64FromEnv("BIGINT_BAD1", 30), "error parsing env variable"); // TODO(csilvers): uncomment this when we disallow negative numbers for uint64 #if 0 EXPECT_DEATH(Uint64FromEnv("BIGINT_BAD2", 30), "error parsing env variable"); #endif setenv("DOUBLE_BAD1", "0.0.0", 1); setenv("DOUBLE_BAD2", "", 1); EXPECT_DEATH(DoubleFromEnv("DOUBLE_BAD1", 40.0), "error parsing env variable"); EXPECT_DEATH(DoubleFromEnv("DOUBLE_BAD2", 40.0), "error parsing env variable"); } #endif // Tests that FlagSaver can save the states of string flags. TEST(FlagSaverTest, CanSaveStringFlagStates) { // 1. Initializes the flags. // State of flag test_str1: // default value - "initial" // current value - "initial" // not set - true SetCommandLineOptionWithMode("test_str2", "second", SET_FLAGS_VALUE); // State of flag test_str2: // default value - "initial" // current value - "second" // not set - false SetCommandLineOptionWithMode("test_str3", "second", SET_FLAGS_DEFAULT); // State of flag test_str3: // default value - "second" // current value - "second" // not set - true // 2. Saves the flag states. { FlagSaver fs; // 3. Modifies the flag states. SetCommandLineOptionWithMode("test_str1", "second", SET_FLAGS_VALUE); EXPECT_EQ("second", FLAGS_test_str1); // State of flag test_str1: // default value - "second" // current value - "second" // not set - true SetCommandLineOptionWithMode("test_str2", "third", SET_FLAGS_DEFAULT); EXPECT_EQ("second", FLAGS_test_str2); // State of flag test_str2: // default value - "third" // current value - "second" // not set - false SetCommandLineOptionWithMode("test_str3", "third", SET_FLAGS_VALUE); EXPECT_EQ("third", FLAGS_test_str3); // State of flag test_str1: // default value - "second" // current value - "third" // not set - false // 4. Restores the flag states. } // 5. Verifies that the states were restored. // Verifies that the value of test_str1 was restored. EXPECT_EQ("initial", FLAGS_test_str1); // Verifies that the "not set" attribute of test_str1 was restored to true. SetCommandLineOptionWithMode("test_str1", "second", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str1); // Verifies that the value of test_str2 was restored. EXPECT_EQ("second", FLAGS_test_str2); // Verifies that the "not set" attribute of test_str2 was restored to false. SetCommandLineOptionWithMode("test_str2", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str2); // Verifies that the value of test_str3 was restored. EXPECT_EQ("second", FLAGS_test_str3); // Verifies that the "not set" attribute of test_str3 was restored to true. SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("fourth", FLAGS_test_str3); } // Tests that FlagSaver can save the values of various-typed flags. TEST(FlagSaverTest, CanSaveVariousTypedFlagValues) { // Initializes the flags. FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_int64 = -2; FLAGS_test_uint64 = 3; FLAGS_test_double = 4.0; FLAGS_test_string = "good"; // Saves the flag states. { FlagSaver fs; // Modifies the flags. FLAGS_test_bool = true; FLAGS_test_int32 = -5; FLAGS_test_int64 = -6; FLAGS_test_uint64 = 7; FLAGS_test_double = 8.0; FLAGS_test_string = "bad"; // Restores the flag states. } // Verifies the flag values were restored. EXPECT_FALSE(FLAGS_test_bool); EXPECT_EQ(-1, FLAGS_test_int32); EXPECT_EQ(-2, FLAGS_test_int64); EXPECT_EQ(3, FLAGS_test_uint64); EXPECT_DOUBLE_EQ(4.0, FLAGS_test_double); EXPECT_EQ("good", FLAGS_test_string); } TEST(GetAllFlagsTest, BaseTest) { vector flags; GetAllFlags(&flags); bool found_test_bool = false; vector::const_iterator i; for (i = flags.begin(); i != flags.end(); ++i) { if (i->name == "test_bool") { found_test_bool = true; EXPECT_EQ(i->type, "bool"); EXPECT_EQ(i->default_value, "false"); EXPECT_EQ(i->flag_ptr, &FLAGS_test_bool); break; } } EXPECT_TRUE(found_test_bool); } TEST(ShowUsageWithFlagsTest, BaseTest) { // TODO(csilvers): test this by allowing output other than to stdout. // Not urgent since this functionality is tested via // gflags_unittest.sh, though only through use of --help. } TEST(ShowUsageWithFlagsRestrictTest, BaseTest) { // TODO(csilvers): test this by allowing output other than to stdout. // Not urgent since this functionality is tested via // gflags_unittest.sh, though only through use of --helpmatch. } // Note: all these argv-based tests depend on SetArgv being called // before ParseCommandLineFlags() in main(), below. TEST(GetArgvsTest, BaseTest) { vector argvs = GetArgvs(); EXPECT_EQ(4, argvs.size()); EXPECT_EQ("/test/argv/for/gflags_unittest", argvs[0]); EXPECT_EQ("argv 2", argvs[1]); EXPECT_EQ("3rd argv", argvs[2]); EXPECT_EQ("argv #4", argvs[3]); } TEST(GetArgvTest, BaseTest) { EXPECT_STREQ("/test/argv/for/gflags_unittest " "argv 2 3rd argv argv #4", GetArgv()); } TEST(GetArgv0Test, BaseTest) { EXPECT_STREQ("/test/argv/for/gflags_unittest", GetArgv0()); } TEST(GetArgvSumTest, BaseTest) { // This number is just the sum of the ASCII values of all the chars // in GetArgv(). EXPECT_EQ(4904, GetArgvSum()); } TEST(ProgramInvocationNameTest, BaseTest) { EXPECT_STREQ("/test/argv/for/gflags_unittest", ProgramInvocationName()); } TEST(ProgramInvocationShortNameTest, BaseTest) { EXPECT_STREQ("gflags_unittest", ProgramInvocationShortName()); } TEST(ProgramUsageTest, BaseTest) { // Depends on 1st arg to ParseCommandLineFlags() EXPECT_STREQ("/test/argv/for/gflags_unittest: " " [...]\nDoes something useless.\n", ProgramUsage()); } TEST(GetCommandLineOptionTest, NameExistsAndIsDefault) { string value("will be changed"); bool r = GetCommandLineOption("test_bool", &value); EXPECT_TRUE(r); EXPECT_EQ("false", value); r = GetCommandLineOption("test_int32", &value); EXPECT_TRUE(r); EXPECT_EQ("-1", value); } TEST(GetCommandLineOptionTest, NameExistsAndWasAssigned) { FLAGS_test_int32 = 400; string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_TRUE(r); EXPECT_EQ("400", value); } TEST(GetCommandLineOptionTest, NameExistsAndWasSet) { SetCommandLineOption("test_int32", "700"); string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_TRUE(r); EXPECT_EQ("700", value); } TEST(GetCommandLineOptionTest, NameExistsAndWasNotSet) { // This doesn't set the flag's value, but rather its default value. // is_default is still true, but the 'default' value returned has changed! SetCommandLineOptionWithMode("test_int32", "800", SET_FLAGS_DEFAULT); string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_TRUE(r); EXPECT_EQ("800", value); EXPECT_TRUE(GetCommandLineFlagInfoOrDie("test_int32").is_default); } TEST(GetCommandLineOptionTest, NameExistsAndWasConditionallySet) { SetCommandLineOptionWithMode("test_int32", "900", SET_FLAG_IF_DEFAULT); string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_TRUE(r); EXPECT_EQ("900", value); } TEST(GetCommandLineOptionTest, NameDoesNotExist) { string value("will not be changed"); const bool r = GetCommandLineOption("test_int3210", &value); EXPECT_FALSE(r); EXPECT_EQ("will not be changed", value); } TEST(GetCommandLineFlagInfoTest, FlagExists) { CommandLineFlagInfo info; bool r = GetCommandLineFlagInfo("test_int32", &info); EXPECT_TRUE(r); EXPECT_EQ("test_int32", info.name); EXPECT_EQ("int32", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("-1", info.current_value); EXPECT_EQ("-1", info.default_value); EXPECT_TRUE(info.is_default); EXPECT_FALSE(info.has_validator_fn); EXPECT_EQ(&FLAGS_test_int32, info.flag_ptr); FLAGS_test_bool = true; r = GetCommandLineFlagInfo("test_bool", &info); EXPECT_TRUE(r); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("true", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_FALSE(info.is_default); EXPECT_FALSE(info.has_validator_fn); EXPECT_EQ(&FLAGS_test_bool, info.flag_ptr); FLAGS_test_bool = false; r = GetCommandLineFlagInfo("test_bool", &info); EXPECT_TRUE(r); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("false", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_FALSE(info.is_default); // value is same, but flag *was* modified EXPECT_FALSE(info.has_validator_fn); EXPECT_EQ(&FLAGS_test_bool, info.flag_ptr); } TEST(GetCommandLineFlagInfoTest, FlagDoesNotExist) { CommandLineFlagInfo info; // Set to some random values that GetCommandLineFlagInfo should not change info.name = "name"; info.type = "type"; info.current_value = "curr"; info.default_value = "def"; info.filename = "/"; info.is_default = false; info.has_validator_fn = true; info.flag_ptr = NULL; bool r = GetCommandLineFlagInfo("test_int3210", &info); EXPECT_FALSE(r); EXPECT_EQ("name", info.name); EXPECT_EQ("type", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("curr", info.current_value); EXPECT_EQ("def", info.default_value); EXPECT_EQ("/", info.filename); EXPECT_FALSE(info.is_default); EXPECT_TRUE(info.has_validator_fn); EXPECT_EQ(NULL, info.flag_ptr); } TEST(GetCommandLineFlagInfoOrDieTest, FlagExistsAndIsDefault) { CommandLineFlagInfo info; info = GetCommandLineFlagInfoOrDie("test_int32"); EXPECT_EQ("test_int32", info.name); EXPECT_EQ("int32", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("-1", info.current_value); EXPECT_EQ("-1", info.default_value); EXPECT_TRUE(info.is_default); EXPECT_EQ(&FLAGS_test_int32, info.flag_ptr); info = GetCommandLineFlagInfoOrDie("test_bool"); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("false", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_TRUE(info.is_default); EXPECT_FALSE(info.has_validator_fn); EXPECT_EQ(&FLAGS_test_bool, info.flag_ptr); } TEST(GetCommandLineFlagInfoOrDieTest, FlagExistsAndWasAssigned) { FLAGS_test_int32 = 400; CommandLineFlagInfo info; info = GetCommandLineFlagInfoOrDie("test_int32"); EXPECT_EQ("test_int32", info.name); EXPECT_EQ("int32", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("400", info.current_value); EXPECT_EQ("-1", info.default_value); EXPECT_FALSE(info.is_default); EXPECT_EQ(&FLAGS_test_int32, info.flag_ptr); FLAGS_test_bool = true; info = GetCommandLineFlagInfoOrDie("test_bool"); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("true", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_FALSE(info.is_default); EXPECT_FALSE(info.has_validator_fn); EXPECT_EQ(&FLAGS_test_bool, info.flag_ptr); } #ifdef GTEST_HAS_DEATH_TEST TEST(GetCommandLineFlagInfoOrDieDeathTest, FlagDoesNotExist) { EXPECT_DEATH(GetCommandLineFlagInfoOrDie("test_int3210"), ".*: flag test_int3210 does not exist"); } #endif // These are lightly tested because they're deprecated. Basically, // the tests are meant to cover how existing users use these functions, // but not necessarily how new users could use them. TEST(DeprecatedFunctionsTest, CommandlineFlagsIntoString) { string s = CommandlineFlagsIntoString(); EXPECT_NE(string::npos, s.find("--test_bool=")); } TEST(DeprecatedFunctionsTest, AppendFlagsIntoFile) { FLAGS_test_int32 = 10; // just to make the test more interesting string filename(TmpFile("flagfile")); unlink(filename.c_str()); // just to be safe const bool r = AppendFlagsIntoFile(filename, "not the real argv0"); EXPECT_TRUE(r); FILE* fp; EXPECT_EQ(0, SafeFOpen(&fp, filename.c_str(), "r")); EXPECT_TRUE(fp != NULL); char line[8192]; EXPECT_TRUE(fgets(line, sizeof(line)-1, fp) != NULL); // get the first line // First line should be progname. EXPECT_STREQ("not the real argv0\n", line); bool found_bool = false, found_int32 = false; while (fgets(line, sizeof(line)-1, fp)) { line[sizeof(line)-1] = '\0'; // just to be safe if (strcmp(line, "--test_bool=false\n") == 0) found_bool = true; if (strcmp(line, "--test_int32=10\n") == 0) found_int32 = true; } EXPECT_TRUE(found_int32); EXPECT_TRUE(found_bool); fclose(fp); } TEST(DeprecatedFunctionsTest, ReadFromFlagsFile) { FLAGS_test_int32 = -10; // just to make the test more interesting string filename(TmpFile("flagfile2")); unlink(filename.c_str()); // just to be safe bool r = AppendFlagsIntoFile(filename, GetArgv0()); EXPECT_TRUE(r); FLAGS_test_int32 = -11; r = ReadFromFlagsFile(filename, GetArgv0(), true); EXPECT_TRUE(r); EXPECT_EQ(-10, FLAGS_test_int32); } // unnamed namespace TEST(DeprecatedFunctionsTest, ReadFromFlagsFileFailure) { FLAGS_test_int32 = -20; string filename(TmpFile("flagfile3")); FILE* fp; EXPECT_EQ(0, SafeFOpen(&fp, filename.c_str(), "w")); EXPECT_TRUE(fp != NULL); // Note the error in the bool assignment below... fprintf(fp, "%s\n--test_int32=-21\n--test_bool=not_a_bool!\n", GetArgv0()); fclose(fp); FLAGS_test_int32 = -22; const bool r = ReadFromFlagsFile(filename, GetArgv0(), false); EXPECT_FALSE(r); EXPECT_EQ(-22, FLAGS_test_int32); // the -21 from the flagsfile didn't take } TEST(FlagsSetBeforeInitTest, TryFromEnv) { EXPECT_EQ("pre-set", FLAGS_test_tryfromenv); } // The following test case verifies that ParseCommandLineFlags() and // ParseCommandLineNonHelpFlags() uses the last definition of a flag // in case it's defined more than once. DEFINE_int32(test_flag, -1, "used for testing gflags.cc"); // Parses and returns the --test_flag flag. // If with_help is true, calls ParseCommandLineFlags; otherwise calls // ParseCommandLineNonHelpFlags. int32 ParseTestFlag(bool with_help, int argc, const char** const_argv) { FlagSaver fs; // Restores the flags before returning. // Makes a copy of the input array s.t. it can be reused // (ParseCommandLineFlags() will alter the array). char** const argv_save = new char*[argc + 1]; char** argv = argv_save; memcpy(argv, const_argv, sizeof(*argv)*(argc + 1)); if (with_help) { ParseCommandLineFlags(&argc, &argv, true); } else { ParseCommandLineNonHelpFlags(&argc, &argv, true); } delete[] argv_save; return FLAGS_test_flag; } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedTwiceOnCommandLine) { const char* argv[] = { "my_test", "--test_flag=1", "--test_flag=2", NULL, }; EXPECT_EQ(2, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(2, ParseTestFlag(false, arraysize(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedTwiceInFlagFile) { const char* argv[] = { "my_test", GetFlagFileFlag(), NULL, }; EXPECT_EQ(2, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(2, ParseTestFlag(false, arraysize(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedInCommandLineAndThenFlagFile) { const char* argv[] = { "my_test", "--test_flag=0", GetFlagFileFlag(), NULL, }; EXPECT_EQ(2, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(2, ParseTestFlag(false, arraysize(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedInFlagFileAndThenCommandLine) { const char* argv[] = { "my_test", GetFlagFileFlag(), "--test_flag=3", NULL, }; EXPECT_EQ(3, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(3, ParseTestFlag(false, arraysize(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedInCommandLineAndFlagFileAndThenCommandLine) { const char* argv[] = { "my_test", "--test_flag=0", GetFlagFileFlag(), "--test_flag=3", NULL, }; EXPECT_EQ(3, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(3, ParseTestFlag(false, arraysize(argv) - 1, argv)); } TEST(ParseCommandLineFlagsAndDashArgs, TwoDashArgFirst) { const char* argv[] = { "my_test", "--", "--test_flag=0", NULL, }; EXPECT_EQ(-1, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(-1, ParseTestFlag(false, arraysize(argv) - 1, argv)); } TEST(ParseCommandLineFlagsAndDashArgs, TwoDashArgMiddle) { const char* argv[] = { "my_test", "--test_flag=7", "--", "--test_flag=0", NULL, }; EXPECT_EQ(7, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(7, ParseTestFlag(false, arraysize(argv) - 1, argv)); } TEST(ParseCommandLineFlagsAndDashArgs, OneDashArg) { const char* argv[] = { "my_test", "-", "--test_flag=0", NULL, }; EXPECT_EQ(0, ParseTestFlag(true, arraysize(argv) - 1, argv)); EXPECT_EQ(0, ParseTestFlag(false, arraysize(argv) - 1, argv)); } #ifdef GTEST_HAS_DEATH_TEST TEST(ParseCommandLineFlagsUnknownFlagDeathTest, FlagIsCompletelyUnknown) { const char* argv[] = { "my_test", "--this_flag_does_not_exist", NULL, }; EXPECT_DEATH(ParseTestFlag(true, arraysize(argv) - 1, argv), "unknown command line flag.*"); EXPECT_DEATH(ParseTestFlag(false, arraysize(argv) - 1, argv), "unknown command line flag.*"); } TEST(ParseCommandLineFlagsUnknownFlagDeathTest, BoolFlagIsCompletelyUnknown) { const char* argv[] = { "my_test", "--nothis_flag_does_not_exist", NULL, }; EXPECT_DEATH(ParseTestFlag(true, arraysize(argv) - 1, argv), "unknown command line flag.*"); EXPECT_DEATH(ParseTestFlag(false, arraysize(argv) - 1, argv), "unknown command line flag.*"); } TEST(ParseCommandLineFlagsUnknownFlagDeathTest, FlagIsNotABool) { const char* argv[] = { "my_test", "--notest_string", NULL, }; EXPECT_DEATH(ParseTestFlag(true, arraysize(argv) - 1, argv), "boolean value .* specified for .* command line flag"); EXPECT_DEATH(ParseTestFlag(false, arraysize(argv) - 1, argv), "boolean value .* specified for .* command line flag"); } #endif TEST(ParseCommandLineFlagsWrongFields, DescriptionIsInvalid) { // These must not be automatic variables, since command line flags // aren't unregistered and gUnit uses FlagSaver to save and restore // command line flags' values. If these are on the stack, then when // later tests attempt to save and restore their values, the stack // addresses of these variables will be overwritten... Stack smash! static bool current_storage; static bool defvalue_storage; FlagRegisterer fr("flag_name", "bool", 0, "filename", ¤t_storage, &defvalue_storage); CommandLineFlagInfo fi; EXPECT_TRUE(GetCommandLineFlagInfo("flag_name", &fi)); EXPECT_EQ("", fi.description); EXPECT_EQ(¤t_storage, fi.flag_ptr); } static bool ValidateTestFlagIs5(const char* flagname, int32 flagval) { if (flagval == 5) return true; printf("%s isn't 5!\n", flagname); return false; } static bool ValidateTestFlagIs10(const char* flagname, int32 flagval) { return flagval == 10; } TEST(FlagsValidator, ValidFlagViaArgv) { const char* argv[] = { "my_test", "--test_flag=5", NULL, }; EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); EXPECT_EQ(5, ParseTestFlag(true, arraysize(argv) - 1, argv)); // Undo the flag validator setting EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); } TEST(FlagsValidator, ValidFlagViaSetDefault) { EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); // SetCommandLineOptionWithMode returns the empty string on error. EXPECT_NE("", SetCommandLineOptionWithMode("test_flag", "5", SET_FLAG_IF_DEFAULT)); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); } TEST(FlagsValidator, ValidFlagViaSetValue) { EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); FLAGS_test_flag = 100; // doesn't trigger the validator // SetCommandLineOptionWithMode returns the empty string on error. EXPECT_NE("", SetCommandLineOptionWithMode("test_flag", "5", SET_FLAGS_VALUE)); EXPECT_NE("", SetCommandLineOptionWithMode("test_flag", "5", SET_FLAGS_DEFAULT)); EXPECT_NE("", SetCommandLineOption("test_flag", "5")); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); } #ifdef GTEST_HAS_DEATH_TEST TEST(FlagsValidatorDeathTest, InvalidFlagViaArgv) { const char* argv[] = { "my_test", "--test_flag=50", NULL, }; EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); EXPECT_DEATH(ParseTestFlag(true, arraysize(argv) - 1, argv), "ERROR: failed validation of new value '50' for flag 'test_flag'"); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); } #endif TEST(FlagsValidator, InvalidFlagViaSetDefault) { EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); // SetCommandLineOptionWithMode returns the empty string on error. EXPECT_EQ("", SetCommandLineOptionWithMode("test_flag", "50", SET_FLAG_IF_DEFAULT)); EXPECT_EQ(-1, FLAGS_test_flag); // the setting-to-50 should have failed EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); } TEST(FlagsValidator, InvalidFlagViaSetValue) { EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); FLAGS_test_flag = 100; // doesn't trigger the validator // SetCommandLineOptionWithMode returns the empty string on error. EXPECT_EQ("", SetCommandLineOptionWithMode("test_flag", "50", SET_FLAGS_VALUE)); EXPECT_EQ("", SetCommandLineOptionWithMode("test_flag", "50", SET_FLAGS_DEFAULT)); EXPECT_EQ("", SetCommandLineOption("test_flag", "50")); EXPECT_EQ(100, FLAGS_test_flag); // the setting-to-50 should have failed EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); } #ifdef GTEST_HAS_DEATH_TEST TEST(FlagsValidatorDeathTest, InvalidFlagNeverSet) { // If a flag keeps its default value, and that default value is // invalid, we should die at argv-parse time. const char* argv[] = { "my_test", NULL, }; EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); EXPECT_DEATH(ParseTestFlag(true, arraysize(argv) - 1, argv), "ERROR: --test_flag must be set on the commandline"); } #endif TEST(FlagsValidator, InvalidFlagPtr) { int32 dummy; EXPECT_FALSE(RegisterFlagValidator(NULL, &ValidateTestFlagIs5)); EXPECT_FALSE(RegisterFlagValidator(&dummy, &ValidateTestFlagIs5)); } TEST(FlagsValidator, RegisterValidatorTwice) { EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); EXPECT_FALSE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs10)); EXPECT_FALSE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs10)); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs10)); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); } TEST(FlagsValidator, CommandLineFlagInfo) { CommandLineFlagInfo info; info = GetCommandLineFlagInfoOrDie("test_flag"); EXPECT_FALSE(info.has_validator_fn); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); info = GetCommandLineFlagInfoOrDie("test_flag"); EXPECT_TRUE(info.has_validator_fn); EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); info = GetCommandLineFlagInfoOrDie("test_flag"); EXPECT_FALSE(info.has_validator_fn); } TEST(FlagsValidator, FlagSaver) { { FlagSaver fs; EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); EXPECT_EQ("", SetCommandLineOption("test_flag", "50")); // fails validation } EXPECT_NE("", SetCommandLineOption("test_flag", "50")); // validator is gone EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, &ValidateTestFlagIs5)); { FlagSaver fs; EXPECT_TRUE(RegisterFlagValidator(&FLAGS_test_flag, NULL)); EXPECT_NE("", SetCommandLineOption("test_flag", "50")); // no validator } EXPECT_EQ("", SetCommandLineOption("test_flag", "50")); // validator is back } } // unnamed namespace int main(int argc, char **argv) { // Run unit tests only if called without arguments, otherwise this program // is used by an "external" usage test const bool run_tests = (argc == 1); // We need to call SetArgv before parsing flags, so our "test" argv will // win out over this executable's real argv. That makes running this // test with a real --help flag kinda annoying, unfortunately. const char* test_argv[] = { "/test/argv/for/gflags_unittest", "argv 2", "3rd argv", "argv #4" }; SetArgv(arraysize(test_argv), test_argv); // The first arg is the usage message, also important for testing. string usage_message = (string(GetArgv0()) + ": [...]\nDoes something useless.\n"); // We test setting tryfromenv manually, and making sure // ParseCommandLineFlags still evaluates it. FLAGS_tryfromenv = "test_tryfromenv"; setenv("FLAGS_test_tryfromenv", "pre-set", 1); // Modify flag values from declared default value in two ways. // The recommended way: SetCommandLineOptionWithMode("changed_bool1", "true", SET_FLAGS_DEFAULT); // The non-recommended way: FLAGS_changed_bool2 = true; SetUsageMessage(usage_message.c_str()); SetVersionString("test_version"); ParseCommandLineFlags(&argc, &argv, true); MakeTmpdir(&FLAGS_test_tmpdir); int exit_status = 0; if (run_tests) { fprintf(stdout, "Running the unit tests now...\n\n"); fflush(stdout); exit_status = RUN_ALL_TESTS(); } else fprintf(stderr, "\n\nPASS\n"); ShutDownCommandLineFlags(); return exit_status; } } // GFLAGS_NAMESPACE int main(int argc, char** argv) { return GFLAGS_NAMESPACE::main(argc, argv); } gflags-2.1.2/test/gflags_unittest_flagfile000066400000000000000000000000341250430723500207120ustar00rootroot00000000000000--test_flag=1 --test_flag=2 gflags-2.1.2/test/nc/000077500000000000000000000000001250430723500143375ustar00rootroot00000000000000gflags-2.1.2/test/nc/CMakeLists.txt000066400000000000000000000007371250430723500171060ustar00rootroot00000000000000## gflags negative compilation tests cmake_minimum_required (VERSION 2.8) if (NOT TEST_NAME) message (FATAL_ERROR "Missing TEST_NAME CMake flag") endif () string (TOUPPER ${TEST_NAME} TEST_NAME_UPPER) project (gflags_nc_${TEST_NAME}) find_package (gflags REQUIRED) include_directories (${gflags_INCLUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/..") link_libraries (gflags_nothreads) add_definitions (-DTEST_${TEST_NAME_UPPER}) add_executable (gflags_nc_${TEST_NAME} gflags_nc.cc) gflags-2.1.2/test/nc/gflags_nc.cc000066400000000000000000000046231250430723500165760ustar00rootroot00000000000000// Copyright (c) 2009, 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. // --- // // A negative comiple test for gflags. #include #if defined(TEST_SWAPPED_ARGS) DEFINE_bool(some_bool_flag, "the default value should go here, not the description", false); #elif defined(TEST_INT_INSTEAD_OF_BOOL) DEFINE_bool(some_bool_flag_2, 0, "should have been an int32 flag but mistakenly used bool instead"); #elif defined(TEST_BOOL_IN_QUOTES) DEFINE_bool(some_bool_flag_3, "false", "false in in quotes, which is wrong"); #elif defined(TEST_SANITY) DEFINE_bool(some_bool_flag_4, true, "this is the correct usage of DEFINE_bool"); #elif defined(TEST_DEFINE_STRING_WITH_0) DEFINE_string(some_string_flag, 0, "Trying to construct a string by passing 0 would cause a crash."); #endif int main(int, char **) { return 0; }