Move GLog/GFlags to extern/

This is where the libraries belongs to actually, they are not only used by
Libmv now, but also by tests and Cycles.
This commit is contained in:
Sergey Sharybin
2016-01-04 16:47:36 +05:00
parent 69f4080839
commit 0b856dd97e
71 changed files with 78 additions and 114 deletions

2
extern/gflags/AUTHORS.txt vendored Normal file
View File

@@ -0,0 +1,2 @@
google-gflags@googlegroups.com

56
extern/gflags/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,56 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2016, Blender Foundation
# All rights reserved.
#
# Contributor(s): Blender Foundation,
# Sergey Sharybin
#
# ***** END GPL LICENSE BLOCK *****
set(INC
src
src/gflags
)
set(INC_SYS
)
set(SRC
src/gflags.cc
src/gflags_completions.cc
src/gflags_reporting.cc
src/config.h
src/gflags/gflags_completions.h
src/gflags/gflags_declare.h
src/gflags/gflags_gflags.h
src/gflags/gflags.h
src/mutex.h
src/util.h
)
if(WIN32)
list(APPEND SRC
src/windows_port.cc
src/windows_port.h
)
endif()
add_definitions(${GFLAGS_DEFINES})
blender_add_lib(extern_gflags "${SRC}" "${INC}" "${INC_SYS}")

28
extern/gflags/COPYING.txt vendored Normal file
View File

@@ -0,0 +1,28 @@
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.

218
extern/gflags/ChangeLog.txt vendored Normal file
View File

@@ -0,0 +1,218 @@
* Tue Mar 24 2014 - Andreas Schuh <andreas.schuh.84@gmail.com>
- 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 <google-gflags@googlegroups.com>
- 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 <google-gflags@googlegroups.com>
- 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. <google-gflags@googlegroups.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- 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. <opensource@google.com>
- google-gflags: version 0.1

240
extern/gflags/NEWS.txt vendored Normal file
View File

@@ -0,0 +1,240 @@
=== 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
[https://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control described here].
For the further development, I am following the
[http://nvie.com/posts/a-successful-git-branching-model/ Git branching model]
with feature branch names prefixed by "feature/" and bugfix branch names
prefixed by "bugfix/", respectively.
Binary and source [https://github.com/schuhschuh/gflags/releases packages] 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
[https://github.com/schuhschuh/gflags/tree/cmake-migration 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
[https://github.com/schuhschuh/gflags GitHub].
I believe that the strengths of [http://git-scm.com/ Git] 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 [http://www.cmake.org/ CMake].
Check out the (unstable!)
[https://github.com/schuhschuh/gflags/tree/cmake-migration 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
[http://gflags.googlecode.com/svn/tags/gflags-2.0/ChangeLog changes]
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
[http://code.google.com/p/google-gflags/source/browse/tags/gflags-1.7/ChangeLog changes].
=== 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
[http://code.google.com/p/google-gflags/source/browse/tags/gflags-1.6/ChangeLog ChangeLog]
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
[http://code.google.com/p/google-gflags/source/browse/tags/gflags-1.5/ChangeLog ChangeLog]
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, [http://code.google.com/p/python-gflags 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
[http://code.google.com/p/google-gflags/source/browse/tags/gflags-1.1/ChangeLog ChangeLog]
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
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 <gflags/gflags.h>
}}}
instead of
{{{
#include <google/gflags.h>
}}}
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
[http://code.google.com/p/google-gflags/source/browse/tags/gflags-1.0rc2/ChangeLog
ChangeLog] for more details.
If I don't hear any bad news for a few weeks, I'll release 1.0-final.

19
extern/gflags/README.libmv vendored Normal file
View File

@@ -0,0 +1,19 @@
Project: Google Flags
URL: http://code.google.com/p/google-gflags/
License: New BSD
Upstream version: 2.2.0 (9db82895)
Local modifications:
- Flattened the tree and only included files needed for libmv.
- config.h was originally generated on linux machine with some
further tweaks:
* OS_WINDOWS need to be conditinally defined from inside #ifdef WIN32
* Same applies yo HAVE_SHLWAPI_H
* Disabeld HAVE_FNMATCH_H
- Removed attribute(unused) from FlagSaver.
- Applied some modifications from fork https://github.com/Nazg-Gul/gflags.git
(see https://github.com/gflags/gflags/pull/129)

270
extern/gflags/README.md vendored Normal file
View File

@@ -0,0 +1,270 @@
24 March 2015
-------------
I've just released gflags 2.1.2.
This release completes the namespace change fixes. In particular,
it restores binary ABI compatibility with release version 2.0.
The deprecated "google" namespace is by default still kept as
primary namespace while symbols are imported into the new "gflags" namespace.
This can be overridden using the CMake variable GFLAGS_NAMESPACE.
Other fixes of the build configuration are related to the (patched)
CMake modules FindThreads.cmake and CheckTypeSize.cmake. These have
been removed and instead the C language is enabled again even though
gflags is written in C++ only.
This release also marks the complete move of the 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 negligable.
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 2014
---------------
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 <gflags/gflags.h>
```
instead of
```
#include <google/gflags.h>
```
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.

114
extern/gflags/src/config.h vendored Normal file
View File

@@ -0,0 +1,114 @@
/* 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.
#ifdef WIN32
# define OS_WINDOWS
#endif
// Define if you have the <stdint.h> header file.
#define HAVE_STDINT_H
// Define if you have the <sys/types.h> header file.
#define HAVE_SYS_TYPES_H
// Define if you have the <inttypes.h> header file.
#define HAVE_INTTYPES_H
// Define if you have the <sys/stat.h> header file.
#define HAVE_SYS_STAT_H
// Define if you have the <unistd.h> header file.
#define HAVE_UNISTD_H
// Define if you have the <fnmatch.h> header file.
/* #undef HAVE_FNMATCH_H */
// Define if you have the <shlwapi.h> header file (Windows 2000/XP).
/* #undef HAVE_SHLWAPI_H */
// Define if you have the strtoll function.
#define HAVE_STRTOLL
// Define if you have the strtoq function.
/* #undef HAVE_STRTOQ */
// Define if you have the <pthread.h> header file.
#define HAVE_PTHREAD
// Define if your pthread library defines the type pthread_rwlock_t
#define 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 gflags
// Define to the full name of this package.
#define PACKAGE_NAME gflags
// Define to the full name and version of this package.
#define PACKAGE_STRING gflags 2.2.0
// Define to the one symbol short name of this package.
#define PACKAGE_TARNAME gflags-2.2.0
// Define to the version of this package.
#define PACKAGE_VERSION 2.2.0
// Version number of package.
#define VERSION PACKAGE_VERSION
// Define to the address where bug reports for this package should be sent.
#define PACKAGE_BUGREPORT https://github.com/schuhschuh/gflags/issues
// ---------------------------------------------------------------------------
// 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

1960
extern/gflags/src/gflags.cc vendored Normal file
View File

@@ -0,0 +1,1960 @@
// 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 <assert.h>
#include <ctype.h>
#include <errno.h>
#if defined(HAVE_FNMATCH_H)
# include <fnmatch.h>
#elif defined(HAVE_SHLWAPI_H)
# include <shlwapi.h>
#endif
#include <stdarg.h> // For va_list and related operations
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <string>
#include <utility> // for pair<>
#include <vector>
#include "mutex.h"
#include "util.h"
using namespace MUTEX_NAMESPACE;
// 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 <typename T> 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<type*>(value_buffer_)
#define OTHER_VALUE_AS(fv, type) *reinterpret_cast<type*>(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<bool*>(value_buffer_); break;
case FV_INT32: delete reinterpret_cast<int32*>(value_buffer_); break;
case FV_INT64: delete reinterpret_cast<int64*>(value_buffer_); break;
case FV_UINT64: delete reinterpret_cast<uint64*>(value_buffer_); break;
case FV_DOUBLE: delete reinterpret_cast<double*>(value_buffer_); break;
case FV_STRING: delete reinterpret_cast<string*>(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<int32>(r) != r) // worked, but number out of range
return false;
SET_VALUE_AS(int32, static_cast<int32>(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<bool (*)(const char*, bool)>(
validate_fn_proto)(flagname, VALUE_AS(bool));
case FV_INT32:
return reinterpret_cast<bool (*)(const char*, int32)>(
validate_fn_proto)(flagname, VALUE_AS(int32));
case FV_INT64:
return reinterpret_cast<bool (*)(const char*, int64)>(
validate_fn_proto)(flagname, VALUE_AS(int64));
case FV_UINT64:
return reinterpret_cast<bool (*)(const char*, uint64)>(
validate_fn_proto)(flagname, VALUE_AS(uint64));
case FV_DOUBLE:
return reinterpret_cast<bool (*)(const char*, double)>(
validate_fn_proto)(flagname, VALUE_AS(double));
case FV_STRING:
return reinterpret_cast<bool (*)(const char*, const string&)>(
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<CommandLineFlagInfo>*);
// The map from name to flag, for FindFlagLocked().
typedef map<const char*, CommandLineFlag*, StringCmp> FlagMap;
typedef FlagMap::iterator FlagIterator;
typedef FlagMap::const_iterator FlagConstIterator;
FlagMap flags_;
// The map from current-value pointer to flag, fo FindFlagViaPtrLocked().
typedef map<const void*, CommandLineFlag*> 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<FlagIterator, bool> ins =
flags_.insert(pair<const char*, CommandLineFlag*>(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<string, string> error_flags_; // map from name to error message
// This could be a set<string>, but we reuse the map to minimize the .o size
map<string, string> undefined_names_; // --[flag] name was not registered
};
// Parse a list of (comma-separated) flags.
static void ParseFlagList(const char* value, vector<string>* 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<string> 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<string> 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<string> flaglist;
ParseFlagList(FLAGS_undefok.c_str(), &flaglist);
for (size_t i = 0; i < flaglist.size(); ++i) {
// We also deal with --no<flag>, 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<string, string>::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<string, string>::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<typename T>
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<CommandLineFlagInfo>* 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<string> 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<string>& 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<CommandLineFlag*>::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<CommandLineFlag*>::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<CommandLineFlag*> 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<CommandLineFlagInfo>& flags) {
vector<CommandLineFlagInfo>::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<CommandLineFlagInfo> 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<CommandLineFlagInfo> flags;
GetAllFlags(&flags);
// But we don't want --flagfile, which leads to weird recursion issues
vector<CommandLineFlagInfo>::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<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const int32* flag,
bool (*validate_fn)(const char*, int32)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const int64* flag,
bool (*validate_fn)(const char*, int64)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const uint64* flag,
bool (*validate_fn)(const char*, uint64)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const double* flag,
bool (*validate_fn)(const char*, double)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const string* flag,
bool (*validate_fn)(const char*, const string&)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(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<const char**>(*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<string>& argvs = GetArgvs();
int tmp_argc = static_cast<int>(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

573
extern/gflags/src/gflags/gflags.h vendored Normal file
View File

@@ -0,0 +1,573 @@
// 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 <string>
#include <vector>
#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<CommandLineFlagInfo>* 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<std::string>& 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&);
};
// --------------------------------------------------------------------
// 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] + " <uselessarg1> <uselessarg2>";
// 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_<name>, we also
// preemptively define a junk variable, FLAGS_no<name>. 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<name>. This serves the second purpose of assuring a
// compile error if someone tries to define a flag named no<name>
// 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<typename From> 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
// Import gflags library symbols into alternative/deprecated namespace(s)
#include "gflags_gflags.h"
#endif // GFLAGS_GFLAGS_H_

View File

@@ -0,0 +1,121 @@
// 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 <TAB> 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<TAB> Show me all flags with names prefixed by 'foo'
// --foo?<TAB> Show me all flags with 'foo' somewhere in the name
// --foo??<TAB> Same as prior case, but also search in module
// definition path for 'foo'
// --foo???<TAB> 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<TAB>
// Or:
// $ ./bin/path/another_binary --gfs_u<TAB>
// (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<TAB>
// 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 google {
extern void HandleCommandLineCompletions(void);
}
#endif // GFLAGS_COMPLETIONS_H_

View File

@@ -0,0 +1,141 @@
// 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 google
// ---------------------------------------------------------------------------
// Windows DLL import/export.
// We always want to import the symbols of the gflags library
#ifndef GFLAGS_DLL_DECL
# if 1 && 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 <string>
#if 1
# include <stdint.h> // the normal place uint32_t is defined
#elif 1
# include <sys/types.h> // the normal place u_int32_t is defined
#elif 1
# include <inttypes.h> // a third place for uint32_t or u_int32_t
#endif
namespace GFLAGS_NAMESPACE {
#if 1 // C99
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
#elif 0 // BSD
typedef int32_t int32;
typedef u_int32_t uint32;
typedef int64_t int64;
typedef u_int64_t uint64;
#elif 0 // 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_

101
extern/gflags/src/gflags/gflags_gflags.h vendored Normal file
View File

@@ -0,0 +1,101 @@
// 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_gflags.h may only be included by gflags.h
#endif
#ifndef GFLAGS_NS_GFLAGS_H_
#define GFLAGS_NS_GFLAGS_H_
namespace gflags {
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 gflags
#endif // GFLAGS_NS_GFLAGS_H_

771
extern/gflags/src/gflags_completions.cc vendored Normal file
View File

@@ -0,0 +1,771 @@
// 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 "gflags_completions.h"
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for strlen
#include <set>
#include <string>
#include <utility>
#include <vector>
#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<CommandLineFlagInfo> &all_flags,
const CompletionOptions &options,
const string &match_token,
set<const CommandLineFlagInfo *> *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<const CommandLineFlagInfo *> &all_matches,
const string &search_token,
const string &module,
const string &package_dir,
NotableFlags *notable_flags);
static void TryFindModuleAndPackageDir(
const vector<CommandLineFlagInfo> all_flags,
string *module,
string *package_dir);
// 4) Decide which flags to use
static void FinalizeCompletionOutput(
const set<const CommandLineFlagInfo *> &matching_flags,
CompletionOptions *options,
NotableFlags *notable_flags,
vector<string> *completions);
static void RetrieveUnusedFlags(
const set<const CommandLineFlagInfo *> &matching_flags,
const NotableFlags &notable_flags,
set<const CommandLineFlagInfo *> *unused_flags);
// 5) Output matches
static void OutputSingleGroupWithLimit(
const set<const CommandLineFlagInfo *> &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<string> *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<const CommandLineFlagInfo *> 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<CommandLineFlagInfo> all_flags;
set<const CommandLineFlagInfo *> 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,
&notable_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<string> completions;
FinalizeCompletionOutput(
matching_flags,
&options,
&notable_flags,
&completions);
if (options.force_no_update)
completions.push_back("~");
DVLOG(1) << "Finalized with " << completions.size()
<< " chosen completions";
for (vector<string>::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<CommandLineFlagInfo> &all_flags,
const CompletionOptions &options,
const string &match_token,
set<const CommandLineFlagInfo *> *all_matches,
string *longest_common_prefix) {
all_matches->clear();
bool first_match = true;
for (vector<CommandLineFlagInfo>::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<const CommandLineFlagInfo *> &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 CommandLineFlagInfo *>::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<string>* suffixes, const char* suffix) {
suffixes->push_back(
StringPrintf("/%s%s", ProgramInvocationShortName(), suffix));
}
static void TryFindModuleAndPackageDir(
const vector<CommandLineFlagInfo> all_flags,
string *module,
string *package_dir) {
module->clear();
package_dir->clear();
vector<string> 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<CommandLineFlagInfo>::const_iterator it = all_flags.begin();
it != all_flags.end();
++it) {
for (vector<string>::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<const CommandLineFlagInfo *> *group;
int SizeInLines() const {
int size_in_lines = static_cast<int>(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<const CommandLineFlagInfo *> &matching_flags,
CompletionOptions *options,
NotableFlags *notable_flags,
vector<string> *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<DisplayInfoGroup> 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 =
{ "",
"==========",
&notable_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 *-",
"===========================",
&notable_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 *-",
"============================",
&notable_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 *-",
"=========================",
&notable_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 *-",
"================================",
&notable_flags->subpackage_flags };
lines_so_far += group.SizeInLines();
output_groups.push_back(group);
}
set<const CommandLineFlagInfo *> 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<int>(output_groups.size()) - 1;
for (vector<DisplayInfoGroup>::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<const CommandLineFlagInfo *> &matching_flags,
const NotableFlags &notable_flags,
set<const CommandLineFlagInfo *> *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 CommandLineFlagInfo *>::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<const CommandLineFlagInfo *> &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<string> *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 CommandLineFlagInfo *>::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<int>(prefix.size());
string suffix;
if (remainder > 0)
suffix =
(static_cast<int>(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<int>(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

441
extern/gflags/src/gflags_reporting.cc vendored Normal file
View File

@@ -0,0 +1,441 @@
// 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 <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <string>
#include <vector>
#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<int>(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<int>(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<int>(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, "&amp;");
for (string::size_type pos = 0; (pos = ans.find("<", pos)) != string::npos; )
ans.replace(pos++, 1, "&lt;");
return ans;
}
static void AddXMLTag(string* r, const char* tag, const string& txt) {
StringAppendF(r, "<%s>%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("<flag>");
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 += "</flag>";
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<string>& substrings) {
for (vector<string>::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<string> &substrings) {
fprintf(stdout, "%s: %s\n", Basename(argv0), ProgramUsage());
vector<CommandLineFlagInfo> 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<CommandLineFlagInfo>::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<string> 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<CommandLineFlagInfo> flags;
GetAllFlags(&flags); // flags are sorted: by filename, then flagname
// XML. There is no corresponding schema yet
fprintf(stdout, "<?xml version=\"1.0\"?>\n");
// The document
fprintf(stdout, "<AllFlags>\n");
// the program name and usage
fprintf(stdout, "<program>%s</program>\n",
XMLText(Basename(prog_name)).c_str());
fprintf(stdout, "<usage>%s</usage>\n",
XMLText(ProgramUsage()).c_str());
// All the flags
for (vector<CommandLineFlagInfo>::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, "</AllFlags>\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<string>* 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<string> 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<CommandLineFlagInfo> flags;
GetAllFlags(&flags);
string last_package;
for (vector<CommandLineFlagInfo>::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

348
extern/gflags/src/mutex.h vendored Normal file
View File

@@ -0,0 +1,348 @@
// 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 <windows.h>
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 <pthread.h>
typedef pthread_rwlock_t MutexType;
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
typedef pthread_mutex_t MutexType;
#else
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
#include <assert.h>
#include <stdlib.h> // 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
#endif /* #define GFLAGS_MUTEX_H__ */

374
extern/gflags/src/util.h vendored Normal file
View File

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

73
extern/gflags/src/windows_port.cc vendored Normal file
View File

@@ -0,0 +1,73 @@
/* 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 <string.h> // for strlen(), memset(), memcmp()
#include <assert.h>
#include <stdarg.h> // for va_list, va_start, va_end
#include <windows.h>
#include "windows_port.h"
// These call the windows _vsnprintf, but always NUL-terminate.
#if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */
#if !(defined(_MSC_VER) && _MSC_VER >= 1900) /* msvc 2015 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(_MSC_VER) && _MSC_VER >= 1900) */
#endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */

131
extern/gflags/src/windows_port.h vendored Normal file
View File

@@ -0,0 +1,131 @@
/* 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 <windows.h>
#include <direct.h> /* for mkdir */
#include <stdlib.h> /* for _putenv, getenv */
#include <stdio.h> /* need this to override stdio's snprintf, also defines _unlink used by unit tests */
#include <stdarg.h> /* util.h uses va_copy */
#include <string.h> /* 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 */
#if !(defined(_MSC_VER) && _MSC_VER >= 1900) /* msvc 2015 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
#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<char*>(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
#if !(defined(_MSC_VER) && _MSC_VER >= 1900)
#define PRId32 "d"
#define PRIu32 "u"
#define PRId64 "I64d"
#define PRIu64 "I64u"
#endif
#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_ */