├── src ├── gflags │ ├── CMakeLists.txt │ ├── config.hpp │ ├── gflags_completions.hpp │ ├── mutex.hpp │ ├── gflags_reporting.cpp │ ├── gflags_completions.cpp │ ├── gflags.hpp │ └── gflags.cpp ├── types.hpp ├── config.hpp ├── CMakeLists.txt ├── plot.hpp ├── plot.cpp ├── config.cpp ├── utils.hpp ├── main.cpp └── utils.cpp ├── CMakeLists.txt ├── README.md └── LICENSE /src/gflags/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Cloned from https://github.com/libmv/libmv.git and edited 2 | 3 | #IF(WIN32) 4 | # include_directories( 5 | # ../msinttypes 6 | # ../pthreads-w32/include 7 | # ) 8 | #ENDIF(WIN32) 9 | 10 | add_library(gflags gflags.cpp gflags_reporting.cpp gflags_completions.cpp) 11 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.4) 2 | project(normalizer) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 5 | 6 | # add_definitions(-DPYPLOT) 7 | 8 | add_subdirectory(${PROJECT_SOURCE_DIR}/src) 9 | add_executable(Normalizer ${SOURCE_FILES} ${HEADER_FILES}) 10 | 11 | target_link_libraries(Normalizer gflags) 12 | -------------------------------------------------------------------------------- /src/types.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | typedef vector list; 13 | 14 | double const EXCEL_SECOND = 1.0 / (24 * 60 * 60); 15 | double const EXCEL_MILLIS = EXCEL_SECOND * 0.001; 16 | 17 | double const EPSILON = 1e-17; 18 | -------------------------------------------------------------------------------- /src/config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "gflags/gflags.hpp" 9 | 10 | DECLARE_double(block_diff_thres); 11 | 12 | DECLARE_double(block_time_thres); 13 | 14 | DECLARE_bool(adjacent); 15 | 16 | DECLARE_double(sm_radius); 17 | 18 | DECLARE_double(sm_range_part); 19 | 20 | DECLARE_double(z_range_part); 21 | 22 | DECLARE_double(speed_detection_thres); 23 | 24 | DECLARE_string(output); 25 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(gflags) 2 | 3 | set(SOURCE_FILES 4 | ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp 5 | ${CMAKE_CURRENT_SOURCE_DIR}/plot.cpp 6 | ${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp 7 | ${CMAKE_CURRENT_SOURCE_DIR}/config.cpp 8 | PARENT_SCOPE 9 | ) 10 | 11 | set(HEADER_FILES 12 | ${CMAKE_CURRENT_SOURCE_DIR}/plot.hpp 13 | ${CMAKE_CURRENT_SOURCE_DIR}/types.hpp 14 | ${CMAKE_CURRENT_SOURCE_DIR}/utils.hpp 15 | ${CMAKE_CURRENT_SOURCE_DIR}/config.hpp 16 | PARENT_SCOPE 17 | ) 18 | -------------------------------------------------------------------------------- /src/plot.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "types.hpp" 9 | 10 | using namespace std; 11 | 12 | /* 13 | * Uses python2.7 to show plots. 'pylab' and 'numpy' libraries are used. 14 | */ 15 | struct PyPlot { 16 | PyPlot(); 17 | 18 | ~PyPlot(); 19 | 20 | void plot(list const &x, list const &y, string const &add = ""); 21 | 22 | void show() const; 23 | 24 | void custom_method(string const &f) const; 25 | 26 | private: 27 | FILE *p = NULL; 28 | int counter = 0; 29 | 30 | void save(string const &filename, list const &x, list const &y) const; 31 | 32 | string get_temp_name(int i) const; 33 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | normalizer 2 | ========== 3 | 4 | A library that normalizes sensors values as recording device is always in the same orientation 5 | 6 | ## Input format 7 | Currently normalizer accepts only file with data, which format is described [here](https://github.com/blindmotion/docs/wiki/Csv-file-format). But its code can be easily changed to handle online incoming data. 8 | 9 | ## Output format 10 | Same as input. 11 | 12 | ## Command line arguments 13 | First argument is always an input filename. Other arguments are optional: 14 | * `-block_diff_thres ` 15 | * `-block_time_thres ` 16 | * `-sm_radius ` 17 | * `-sm_range_part ` 18 | * `-z_range_part ` 19 | * `-speed_detection_thres ` 20 | * `-adjacent` & `-noadjacent` 21 | * `-output ` by default: ` = "norm_" + input_name` (default doesn't assume that `input_name` can be a path to file)
22 | Descriptions and default values of arguments are available in config.cpp file or by `-help` argument. 23 | -------------------------------------------------------------------------------- /src/plot.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "types.hpp" 12 | #include "plot.hpp" 13 | 14 | using namespace std; 15 | 16 | 17 | PyPlot::PyPlot() { 18 | p = popen("python", "w"); 19 | fprintf(p, "from pylab import *\nimport numpy as np\n"); 20 | } 21 | 22 | PyPlot::~PyPlot() { 23 | pclose(p); 24 | p = NULL; 25 | for (int i = 0; i < counter; ++i) { 26 | remove(get_temp_name(i).c_str()); 27 | } 28 | } 29 | 30 | void PyPlot::plot(list const &x, list const &y, string const &add) { 31 | string filename = get_temp_name(counter++); 32 | save(filename, x, y); 33 | fprintf(p, "xx = np.loadtxt('%s', delimiter=',')\n" 34 | "plot(xx[:, 0], xx[:, 1] %s)\n", filename.c_str(), add.c_str()); 35 | } 36 | 37 | void PyPlot::show() const { 38 | fprintf(p, "show(True)\n"); 39 | } 40 | 41 | void PyPlot::custom_method(string const &f) const { 42 | fprintf(p, "%s\n", f.c_str()); 43 | } 44 | 45 | void PyPlot::save(string const &filename, list const &x, list const &y) const { 46 | ofstream output(filename.c_str()); 47 | output << setprecision(13); 48 | for (int i = 0; i < (int) x.size(); ++i) { 49 | output << x[i] << "," << y[i] << endl; 50 | } 51 | output.close(); 52 | } 53 | 54 | string PyPlot::get_temp_name(int i) const { 55 | return "tmpplotdata" + to_string(i) + ".txt"; 56 | } -------------------------------------------------------------------------------- /src/config.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #include "config.hpp" 7 | #include "types.hpp" 8 | 9 | DEFINE_double(block_diff_thres, 100.0, "Threshold for detecting when the phone was moved inside the vehicle. " 10 | "Shows maximal difference between vectors of acceleration when they are considered from the same interval."); 11 | 12 | DEFINE_double(block_time_thres, 3.0 * EXCEL_SECOND, "Threshold for detecting when the phone was moved inside the vehicle. " 13 | "Shows maximal difference between time of neighboring vectors of acceleration " 14 | "when they are considered from the same interval."); 15 | 16 | DEFINE_bool(adjacent, false, "Type of the algorithm for detecting when the phone was moved inside the vehicle."); 17 | 18 | DEFINE_double(sm_radius, 0.5 * EXCEL_SECOND, "Radius in excel time, used in acceleration data smoothing."); 19 | 20 | DEFINE_double(sm_range_part, 0.5, "Shows how many values will be taken for smoothing, " 21 | "very small and large ones will be thrown aside."); 22 | 23 | DEFINE_double(z_range_part, 0.3, "Shows how many acceleration vectors will be taken for counting mean acceleration vector, " 24 | "very small and large ones will be thrown aside."); 25 | 26 | DEFINE_double(speed_detection_thres, 3.0 * EXCEL_SECOND, "Sets maximal time length (in excel time) " 27 | "between two speed values for which speed derivative can be calculated."); 28 | 29 | DEFINE_string(output, "", "Output file name, if nothing passed, will be \"norm_\""); 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Blind Motion Project 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of Blind Motion Project nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /src/utils.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #pragma once 7 | 8 | #include "types.hpp" 9 | #include "config.hpp" 10 | 11 | using namespace std; 12 | 13 | inline double sqr(double x) { 14 | return x * x; 15 | } 16 | 17 | /* 18 | * As points are not equidistant in ta, this mean is calculated by dividing integral in some neighbourhood 19 | * by the length of ta interval. 20 | */ 21 | double integrating_mean(double time, double radius, list const &t, list const &x); 22 | 23 | /* 24 | * Mean is calculated by throwing aside boundary values and taking regular mean value of the rest. 25 | */ 26 | double quantile_mean(double time, double radius, list const &t, list const &x, double percent); 27 | 28 | /* 29 | * Median in some neighbourhood with given radius. 30 | */ 31 | double median(double time, double radius, list const &t, list const &x); 32 | 33 | /* 34 | * Mean function is applied to each element in array. 35 | */ 36 | void to_mean(list const &t, list const &x, list &res, double radius = FLAGS_sm_radius, double percent = FLAGS_sm_range_part); 37 | 38 | double difference(int i, int j, list const &x, list const &y, list const &z); 39 | 40 | /* 41 | * Returns division of the given array on different blocks. 42 | * New block is started if the current difference is bigger than the given threshold. 43 | * 'adjacent' parameter determines used algorithm for which points to use to count the current difference. 44 | */ 45 | vector get_block_indices(list const &t, list const &x, list const &y, list const &z, 46 | double threshold = FLAGS_block_diff_thres, double time_thres = FLAGS_block_time_thres, 47 | bool adjacent = FLAGS_adjacent); 48 | 49 | /* 50 | * Returns a rotation matrix which changes coordinates so that the Z axis points to the ground. 51 | */ 52 | vector> get_z_rotation_matrix(int start, int end, list const &x, list const &y, list const &z, 53 | double part = FLAGS_z_range_part); 54 | 55 | /* 56 | * Returns a rotation matrix which changes coordinates so that the X axis points forward (currently may point backward). 57 | */ 58 | vector> get_plane_rotation_matrix(int start, int end, list const &t, list const &x, list const &y, 59 | list const &tg, list const &zg, list const &t_geo, list const &speed_geo, double speed_thres = FLAGS_speed_detection_thres); 60 | 61 | /* 62 | * Applies rotation to given vectors of coordinates. 63 | */ 64 | void rotate_block(int start, int end, list &x, list &y, list &z, vector> const &m); 65 | -------------------------------------------------------------------------------- /src/gflags/config.hpp: -------------------------------------------------------------------------------- 1 | /* src/config.h. Generated from config.h.in by configure. */ 2 | /* src/config.h.in. Generated from configure.ac by autoheader. */ 3 | 4 | /* Always the empty-string on non-windows systems. On windows, should be 5 | "__declspec(dllexport)". This way, when we compile the dll, we export our 6 | functions/classes. It's safe to define this here because config.h is only 7 | used internally, to compile the DLL, and every DLL source file #includes 8 | "config.h" before anything else. */ 9 | #define GFLAGS_DLL_DECL /**/ 10 | 11 | /* Namespace for Google classes */ 12 | #define GOOGLE_NAMESPACE ::google 13 | 14 | /* Define to 1 if you have the header file. */ 15 | #define HAVE_DLFCN_H 1 16 | 17 | /* Define to 1 if you have the header file. */ 18 | #undef HAVE_FNMATCH_H 19 | 20 | /* Define to 1 if you have the header file. */ 21 | #define HAVE_INTTYPES_H 1 22 | 23 | /* Define to 1 if you have the header file. */ 24 | #define HAVE_MEMORY_H 1 25 | 26 | /* define if the compiler implements namespaces */ 27 | #define HAVE_NAMESPACES 1 28 | 29 | /* Define if you have POSIX threads libraries and header files. */ 30 | #define HAVE_PTHREAD 1 31 | 32 | /* Define to 1 if you have the `putenv' function. */ 33 | #define HAVE_PUTENV 1 34 | 35 | /* Define to 1 if you have the `setenv' function. */ 36 | #define HAVE_SETENV 1 37 | 38 | /* Define to 1 if you have the header file. */ 39 | #define HAVE_STDINT_H 1 40 | 41 | /* Define to 1 if you have the header file. */ 42 | #define HAVE_STDLIB_H 1 43 | 44 | /* Define to 1 if you have the header file. */ 45 | #define HAVE_STRINGS_H 1 46 | 47 | /* Define to 1 if you have the header file. */ 48 | #define HAVE_STRING_H 1 49 | 50 | /* Define to 1 if you have the `strtoll' function. */ 51 | #define HAVE_STRTOLL 1 52 | 53 | /* Define to 1 if you have the `strtoq' function. */ 54 | #define HAVE_STRTOQ 1 55 | 56 | /* Define to 1 if you have the header file. */ 57 | #define HAVE_SYS_STAT_H 1 58 | 59 | /* Define to 1 if you have the header file. */ 60 | #define HAVE_SYS_TYPES_H 1 61 | 62 | /* Define to 1 if you have the header file. */ 63 | #define HAVE_UNISTD_H 1 64 | 65 | /* define if your compiler has __attribute__ */ 66 | #define HAVE___ATTRIBUTE__ 1 67 | 68 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 69 | */ 70 | #define LT_OBJDIR ".libs/" 71 | 72 | /* Name of package */ 73 | #define PACKAGE "gflags" 74 | 75 | /* Define to the address where bug reports for this package should be sent. */ 76 | #define PACKAGE_BUGREPORT "opensource@google.com" 77 | 78 | /* Define to the full name of this package. */ 79 | #define PACKAGE_NAME "gflags" 80 | 81 | /* Define to the full name and version of this package. */ 82 | #define PACKAGE_STRING "gflags 1.5" 83 | 84 | /* Define to the one symbol short name of this package. */ 85 | #define PACKAGE_TARNAME "gflags" 86 | 87 | /* Define to the home page for this package. */ 88 | #define PACKAGE_URL "" 89 | 90 | /* Define to the version of this package. */ 91 | #define PACKAGE_VERSION "1.5" 92 | 93 | /* Define to necessary symbol if this constant uses a non-standard name on 94 | your system. */ 95 | /* #undef PTHREAD_CREATE_JOINABLE */ 96 | 97 | /* Define to 1 if you have the ANSI C header files. */ 98 | #define STDC_HEADERS 1 99 | 100 | /* the namespace where STL code like vector<> is defined */ 101 | #define STL_NAMESPACE std 102 | 103 | /* Version number of package */ 104 | #define VERSION "1.5" 105 | 106 | /* Stops putting the code inside the Google namespace */ 107 | #define _END_GOOGLE_NAMESPACE_ } 108 | 109 | /* Puts following code inside the Google namespace */ 110 | #define _START_GOOGLE_NAMESPACE_ namespace google { 111 | -------------------------------------------------------------------------------- /src/gflags/gflags_completions.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // --- 31 | // Author: Dave Nicponski 32 | // 33 | // Implement helpful bash-style command line flag completions 34 | // 35 | // ** Functional API: 36 | // HandleCommandLineCompletions() should be called early during 37 | // program startup, but after command line flag code has been 38 | // initialized, such as the beginning of HandleCommandLineHelpFlags(). 39 | // It checks the value of the flag --tab_completion_word. If this 40 | // flag is empty, nothing happens here. If it contains a string, 41 | // however, then HandleCommandLineCompletions() will hijack the 42 | // process, attempting to identify the intention behind this 43 | // completion. Regardless of the outcome of this deduction, the 44 | // process will be terminated, similar to --helpshort flag 45 | // handling. 46 | // 47 | // ** Overview of Bash completions: 48 | // Bash can be told to programatically determine completions for the 49 | // current 'cursor word'. It does this by (in this case) invoking a 50 | // command with some additional arguments identifying the command 51 | // being executed, the word being completed, and the previous word 52 | // (if any). Bash then expects a sequence of output lines to be 53 | // printed to stdout. If these lines all contain a common prefix 54 | // longer than the cursor word, bash will replace the cursor word 55 | // with that common prefix, and display nothing. If there isn't such 56 | // a common prefix, bash will display the lines in pages using 'more'. 57 | // 58 | // ** Strategy taken for command line completions: 59 | // If we can deduce either the exact flag intended, or a common flag 60 | // prefix, we'll output exactly that. Otherwise, if information 61 | // must be displayed to the user, we'll take the opportunity to add 62 | // some helpful information beyond just the flag name (specifically, 63 | // we'll include the default flag value and as much of the flag's 64 | // description as can fit on a single terminal line width, as specified 65 | // by the flag --tab_completion_columns). Furthermore, we'll try to 66 | // make bash order the output such that the most useful or relevent 67 | // flags are the most likely to be shown at the top. 68 | // 69 | // ** Additional features: 70 | // To assist in finding that one really useful flag, substring matching 71 | // was implemented. Before pressing a to get completion for the 72 | // current word, you can append one or more '?' to the flag to do 73 | // substring matching. Here's the semantics: 74 | // --foo Show me all flags with names prefixed by 'foo' 75 | // --foo? Show me all flags with 'foo' somewhere in the name 76 | // --foo?? Same as prior case, but also search in module 77 | // definition path for 'foo' 78 | // --foo??? Same as prior case, but also search in flag 79 | // descriptions for 'foo' 80 | // Finally, we'll trim the output to a relatively small number of 81 | // flags to keep bash quiet about the verbosity of output. If one 82 | // really wanted to see all possible matches, appending a '+' to the 83 | // search word will force the exhaustive list of matches to be printed. 84 | // 85 | // ** How to have bash accept completions from a binary: 86 | // Bash requires that it be informed about each command that programmatic 87 | // completion should be enabled for. Example addition to a .bashrc 88 | // file would be (your path to gflags_completions.sh file may differ): 89 | 90 | /* 91 | $ complete -o bashdefault -o default -o nospace -C \ 92 | '/usr/local/bin/gflags_completions.sh --tab_completion_columns $COLUMNS' \ 93 | time env binary_name another_binary [...] 94 | */ 95 | 96 | // This would allow the following to work: 97 | // $ /path/to/binary_name --vmodule 98 | // Or: 99 | // $ ./bin/path/another_binary --gfs_u 100 | // (etc) 101 | // 102 | // Sadly, it appears that bash gives no easy way to force this behavior for 103 | // all commands. That's where the "time" in the above example comes in. 104 | // If you haven't specifically added a command to the list of completion 105 | // supported commands, you can still get completions by prefixing the 106 | // entire command with "env". 107 | // $ env /some/brand/new/binary --vmod 108 | // Assuming that "binary" is a newly compiled binary, this should still 109 | // produce the expected completion output. 110 | 111 | 112 | #ifndef GOOGLE_GFLAGS_COMPLETIONS_H_ 113 | #define GOOGLE_GFLAGS_COMPLETIONS_H_ 114 | 115 | namespace google { 116 | 117 | void HandleCommandLineCompletions(void); 118 | 119 | } 120 | 121 | #endif // GOOGLE_GFLAGS_COMPLETIONS_H_ 122 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "types.hpp" 15 | #include "plot.hpp" 16 | #include "utils.hpp" 17 | #include "config.hpp" 18 | 19 | using namespace std; 20 | 21 | vector> read_table(string const &filename) { 22 | vector> table; 23 | ifstream input(filename); 24 | string line; 25 | int i = -1; 26 | while (getline(input, line)) { 27 | table.push_back(vector()); 28 | ++i; 29 | istringstream ss(line); 30 | string token; 31 | while (getline(ss, token, ';')) { 32 | table[i].push_back(token); 33 | } 34 | } 35 | return table; 36 | } 37 | 38 | void parse_data(vector> const &table, 39 | list &ta, list &xa, list &ya, list &za, 40 | list &tg, list &xg, list &yg, list &zg, 41 | list &t_geo, list &speed_geo) { 42 | for (int i = 0; i < table.size(); ++i) { 43 | if (table[i].size() == 0) { 44 | continue; 45 | } 46 | string type = table[i][0]; 47 | if (type == "1") { 48 | double t = atof(table[i][2].c_str()); 49 | ta.push_back(t); 50 | xa.push_back(atof(table[i][3].c_str())); 51 | ya.push_back(atof(table[i][4].c_str())); 52 | za.push_back(atof(table[i][5].c_str())); 53 | } else if (type == "4") { 54 | double t = atof(table[i][2].c_str()); 55 | tg.push_back(t); 56 | xg.push_back(atof(table[i][3].c_str())); 57 | yg.push_back(atof(table[i][4].c_str())); 58 | zg.push_back(atof(table[i][5].c_str())); 59 | } else if (type == "geo") { 60 | t_geo.push_back(atof(table[i][2].c_str())); 61 | speed_geo.push_back(atof(table[i][9].c_str())); 62 | } 63 | } 64 | } 65 | 66 | void replace_data(vector> &table, 67 | list const &ta, list const &xa, 68 | list const &ya, list const &za, 69 | list const &tg, list const &xg, 70 | list const &yg, list const &zg) { 71 | int ia = 0; 72 | int ig = 0; 73 | for (int i = 0; i < table.size(); ++i) { 74 | if (table[i].size() == 0) { 75 | continue; 76 | } 77 | string type = table[i][0]; 78 | if (type == "1") { 79 | table[i][2] = to_string(ta[ia]); 80 | table[i][3] = to_string(xa[ia]); 81 | table[i][4] = to_string(ya[ia]); 82 | table[i][5] = to_string(za[ia]); 83 | ++ia; 84 | } else if (type == "4") { 85 | table[i][2] = to_string(tg[ig]); 86 | table[i][3] = to_string(xg[ig]); 87 | table[i][4] = to_string(yg[ig]); 88 | table[i][5] = to_string(zg[ig]); 89 | ++ig; 90 | } 91 | } 92 | } 93 | 94 | void write_data(string const &filename, vector> const &table) { 95 | ofstream output(filename); 96 | for (int i = 0; i < table.size(); ++i) { 97 | for (int j = 0; j < table[i].size(); ++j) { 98 | output << table[i][j] << ((j + 1 < table[i].size()) ? ';' : '\n'); 99 | } 100 | } 101 | output.close(); 102 | 103 | } 104 | 105 | void dumb_track_calculation(list const &ta, list const &xa, list const &ya, 106 | list const &tg, list const &zg, list &x, list &y, int start = 0) { 107 | double x_cur = 0; 108 | double y_cur = 0; 109 | double alpha_cur = 0; 110 | double vx_cur = 0; 111 | double vy_cur = 0; 112 | for (int i = 0; i < start; ++i) { 113 | x.push_back(0); 114 | y.push_back(0); 115 | } 116 | for (int i = start, j = 0; i < ta.size() - 1; ++i) { 117 | while (j < zg.size() - 1 && tg[j + 1] < ta[i]) { 118 | alpha_cur += zg[j] * (tg[j + 1] - tg[j]); 119 | cout << alpha_cur << ' ' << j << ' ' << zg[j] << ' ' << tg[j + 1] << ' ' << tg[j] << endl; 120 | ++j; 121 | } 122 | double dt = ta[i + 1] - ta[i]; 123 | double ax_cur = xa[i] * cos(alpha_cur) + ya[i] * sin(alpha_cur); 124 | double ay_cur = -xa[i] * sin(alpha_cur) + ya[i] * cos(alpha_cur); 125 | vx_cur += ax_cur * dt; 126 | vy_cur += ay_cur * dt; 127 | x_cur += vx_cur * dt; 128 | y_cur += vy_cur * dt; 129 | x.push_back(x_cur); 130 | y.push_back(y_cur); 131 | } 132 | } 133 | 134 | vector> table; 135 | 136 | list ta, xa, ya, za; 137 | list tg, xg, yg, zg; 138 | list t_geo, speed_geo; 139 | list xa_mean, ya_mean, za_mean; 140 | string output_filename; 141 | 142 | #ifdef PYPLOT 143 | PyPlot plt; 144 | #endif 145 | 146 | int main(int argc, char **argv) { 147 | google::SetUsageMessage("Program normalizes sensors values as recording device is always in the same orientation"); 148 | google::ParseCommandLineFlags(&argc, &argv, true); 149 | if (argc <= 1) { 150 | cerr << "No input file given" << endl; 151 | return -1; 152 | } 153 | 154 | table = read_table(argv[1]); 155 | parse_data(table, ta, xa, ya, za, tg, xg, yg, zg, t_geo, speed_geo); 156 | output_filename = FLAGS_output.length() > 0 ? FLAGS_output : "norm_" + string(argv[1]); 157 | 158 | to_mean(ta, xa, xa_mean); 159 | to_mean(ta, ya, ya_mean); 160 | to_mean(ta, za, za_mean); 161 | 162 | vector block_starts = get_block_indices(ta, xa_mean, ya_mean, za_mean); 163 | cout << block_starts.size() << " block(s) found" << endl; 164 | for (int i = 0; i < block_starts.size(); ++i) { 165 | int start = block_starts[i]; 166 | int finish = i < block_starts.size() - 1 ? block_starts[i + 1] : (int) ta.size(); 167 | vector> rot_matrix = get_z_rotation_matrix(start, finish, xa_mean, ya_mean, za_mean); 168 | rotate_block(start, finish, xa_mean, ya_mean, za_mean, rot_matrix); 169 | int start2 = (int) (lower_bound(tg.begin(), tg.end(), ta[block_starts[i]]) - tg.begin()); 170 | int finish2 = i < block_starts.size() - 1 ? (int) (lower_bound(tg.begin(), tg.end(), ta[block_starts[i + 1]]) - tg.begin()) : 171 | ((int) tg.size()); 172 | rotate_block(start2, finish2, xg, yg, zg, rot_matrix); 173 | 174 | vector> rot_matrix2 = get_plane_rotation_matrix(start, finish, ta, xa_mean, ya_mean, tg, zg, 175 | t_geo, speed_geo); 176 | rotate_block(start, finish, xa_mean, ya_mean, za_mean, rot_matrix2); 177 | rotate_block(start2, finish2, xg, yg, zg, rot_matrix2); 178 | 179 | rotate_block(start, finish, xa, ya, za, rot_matrix); 180 | rotate_block(start, finish, xa, ya, za, rot_matrix2); 181 | } 182 | 183 | // replace_data(table, ta, xa_mean, ya_mean, za_mean, tg, xg, yg, zg); 184 | replace_data(table, ta, xa, ya, za, tg, xg, yg, zg); 185 | write_data(output_filename, table); 186 | 187 | #ifdef PYPLOT 188 | // list x, y; 189 | // dumb_track_calculation(ta, xa_mean, ya_mean, tg, zg, x, y, 1598); // 1598 to skip big pause in 2014-09-28_SensorDatafile 190 | // plt.plot(x, y); 191 | 192 | plt.plot(ta, xa_mean); 193 | plt.plot(ta, ya_mean); 194 | plt.plot(ta, za_mean); 195 | // plt.plot(ta, za); 196 | // plt.plot(ta, zg); 197 | 198 | list vert; 199 | vert.push_back(-10); 200 | vert.push_back(10); 201 | for (int i = 1; i < block_starts.size(); ++i) { 202 | list hor; 203 | hor.push_back(ta[block_starts[i]]); 204 | hor.push_back(ta[block_starts[i]]); 205 | plt.plot(hor, vert, ", c='black', lw=3"); 206 | } 207 | 208 | plt.show(); 209 | #endif 210 | 211 | return 0; 212 | } 213 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Blind Motion Project 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "types.hpp" 12 | #include "utils.hpp" 13 | 14 | using namespace std; 15 | 16 | double integrating_mean(double time, double radius, list const &t, list const &x) { 17 | list::const_iterator low_it, up_it; 18 | low_it = lower_bound(t.begin(), t.end(), time - radius); 19 | up_it = upper_bound(t.begin(), t.end(), time + radius); 20 | 21 | int low = (int) (low_it - t.begin()); 22 | int up = (int) (up_it - t.begin()); 23 | 24 | if (low == up) { 25 | return 0; 26 | } 27 | 28 | if (up - low == 1) { 29 | return x[low]; 30 | } 31 | 32 | double current = 0; 33 | for (int i = low; i < up; ++i) { 34 | if (i != low) { 35 | current += .5 * (t[i] - t[i - 1]) * (x[i] + x[i - 1]); 36 | } 37 | } 38 | return current / (t[up - 1] - t[low]); 39 | } 40 | 41 | double quantile_mean(double time, double radius, list const &t, list const &x, double percent) { 42 | list::const_iterator low_it, up_it; 43 | low_it = lower_bound(t.begin(), t.end(), time - radius); 44 | up_it = upper_bound(t.begin(), t.end(), time + radius); 45 | list x2; 46 | 47 | for (list::const_iterator it = low_it; it != up_it; ++it) { 48 | x2.push_back(x[it - t.begin()]); 49 | } 50 | 51 | //todo: optimize calculation to O(radius), without sorting 52 | sort(x2.begin(), x2.end()); 53 | 54 | int n = (int) x2.size(); 55 | int low = (int) floor(n * (0.5 * (1 - percent))); 56 | int up = (int) ceil(n * (0.5 * (1 + percent))); 57 | 58 | if (low == up) { 59 | return 0; 60 | } 61 | 62 | if (up - low == 1) { 63 | return x2[low]; 64 | } 65 | 66 | double current = 0; 67 | for (int i = low; i < up; ++i) { 68 | current += x2[i]; 69 | } 70 | return current / (up - low); 71 | } 72 | 73 | double simple_median(list &x) { 74 | // todo: optimize calculation to O(x.size()) without sorting, if method is needed 75 | sort(x.begin(), x.end()); 76 | int n = (int) x.size(); 77 | int low = 0; 78 | int up = n; 79 | if (low == up) { 80 | return 0; 81 | } 82 | return x[(low + up) / 2]; 83 | } 84 | 85 | double median(double time, double radius, list const &t, list const &x) { 86 | list::const_iterator low_it, up_it; 87 | low_it = lower_bound(t.begin(), t.end(), time - radius); 88 | up_it = upper_bound(t.begin(), t.end(), time + radius); 89 | 90 | list x2; 91 | for (list::const_iterator it = low_it; it != up_it; ++it) { 92 | x2.push_back(x[it - t.begin()]); 93 | } 94 | 95 | return simple_median(x2); 96 | } 97 | 98 | void to_mean(list const &t, list const &x, list &res, double radius, double percent) { 99 | for (int i = 0; i < t.size(); ++i) { 100 | res.push_back(quantile_mean(t[i], radius, t, x, percent)); 101 | } 102 | } 103 | 104 | double difference(int i, int j, list const &x, list const &y, list const &z) { 105 | return sqr(x[j] - x[i]) + sqr(y[j] - y[i]) + sqr(z[j] - z[i]); 106 | } 107 | 108 | vector get_block_indices(list const &t, list const &x, list const &y, list const &z, 109 | double threshold, double time_thres, bool adjacent) { 110 | vector result; 111 | result.push_back(0); 112 | int last = 0; 113 | for (int i = 1; i < x.size(); ++i) { 114 | double diff = difference(last, i, x, y, z); 115 | if (diff >= threshold || t[i] - t[i - 1] > time_thres) { 116 | result.push_back(i); 117 | last = i; 118 | } else if (adjacent) { 119 | last = i; 120 | } 121 | } 122 | return result; 123 | 124 | } 125 | 126 | vector> get_rotation_matrix(double nx, double ny, double nz, double cos_phi, double sin_phi) { 127 | vector> m(3, vector(3)); 128 | m[0][0] = cos_phi + (1 - cos_phi) * nx * nx; 129 | m[0][1] = (1 - cos_phi) * nx * ny - sin_phi * nz; 130 | m[0][2] = (1 - cos_phi) * nx * nz + sin_phi * ny; 131 | m[1][0] = (1 - cos_phi) * ny * nx + sin_phi * nz; 132 | m[1][1] = cos_phi + (1 - cos_phi) * ny * ny; 133 | m[1][2] = (1 - cos_phi) * ny * nz - sin_phi * nx; 134 | m[2][0] = (1 - cos_phi) * nz * nx - sin_phi * ny; 135 | m[2][1] = (1 - cos_phi) * nz * ny + sin_phi * nx; 136 | m[2][2] = cos_phi + (1 - cos_phi) * nz * nz; 137 | return m; 138 | } 139 | 140 | struct Vector3d { 141 | double x, y, z, len_squared; 142 | Vector3d(double x, double y, double z) : x(x), y(y), z(z), len_squared(x * x + y * y + z * z) { 143 | } 144 | }; 145 | 146 | bool operator <(Vector3d const & a, Vector3d const & b) { 147 | return a.len_squared < b.len_squared; 148 | } 149 | 150 | vector> get_z_rotation_matrix(int start, int end, list const &x, list const &y, list const &z, double part) { 151 | assert(start < end); 152 | vector acc; 153 | for (int i = start; i < end; ++i) { 154 | acc.push_back(Vector3d(x[i], y[i], z[i])); 155 | } 156 | sort(acc.begin(), acc.end()); 157 | double xx = 0, yy = 0, zz = 0; 158 | int start2 = (int) (acc.size() * (1 - part) * 0.5); 159 | int end2 = (int) (acc.size() * (1 + part) * 0.5); 160 | if (start2 == end2) { 161 | start2 = start; 162 | end2 = end; 163 | } 164 | for (int i = start2; i < end2; ++i) { 165 | xx += acc[i].x; 166 | yy += acc[i].y; 167 | zz += acc[i].z; 168 | } 169 | xx /= end2 - start2; 170 | yy /= end2 - start2; 171 | zz /= end2 - start2; 172 | double len = sqrt(sqr(xx) + sqr(yy) + sqr(zz)); 173 | double len2 = sqrt(sqr(xx) + sqr(yy)); 174 | 175 | if (len < EPSILON || len2 < EPSILON) { 176 | cerr << "Small len in get_z_rotation_matrix" << endl; 177 | return get_rotation_matrix(0, 0, 1, 1, 0); 178 | } 179 | 180 | double nx = yy / len2; 181 | double ny = -xx / len2; 182 | double nz = 0; 183 | double cos_phi = zz / len; 184 | double sin_phi = sqrt(1 - sqr(cos_phi)); 185 | 186 | return get_rotation_matrix(nx, ny, nz, cos_phi, sin_phi); 187 | } 188 | 189 | vector> get_plane_rotation_matrix(int start, int end, list const &t, list const &x, list const &y, 190 | list const &tg, list const &zg, list const &t_geo, list const &speed_geo, double speed_thres) { 191 | assert(start < end); 192 | double xx = 0, yy = 0; 193 | double c = 0; 194 | for (int i = start; i < end; ++i) { 195 | double coeff = 1.0 / (1.0 + abs(zg[lower_bound(zg.begin(), zg.end(), t[i]) - zg.begin()])); 196 | int speed_index = (int) (lower_bound(t_geo.begin(), t_geo.end(), t[i]) - t_geo.begin()); 197 | if (speed_index + 1 >= speed_geo.size() || t_geo[speed_index + 1] - t_geo[speed_index] > speed_thres || 198 | speed_geo[speed_index + 1] >= speed_geo[speed_index]) { 199 | xx += x[i] * coeff; 200 | yy += y[i] * coeff; 201 | } else { 202 | xx -= x[i] * coeff; 203 | yy -= y[i] * coeff; 204 | } 205 | c += coeff; 206 | } 207 | xx /= c; 208 | yy /= c; 209 | double len = sqrt(sqr(xx) + sqr(yy)); 210 | if (len < EPSILON) { 211 | return get_rotation_matrix(0, 0, 1, 1, 0); 212 | } 213 | xx /= len; 214 | yy /= len; 215 | return get_rotation_matrix(0, 0, 1, xx, yy); 216 | } 217 | 218 | void rotate_block(int start, int end, list &x, list &y, list &z, vector> const &m) { 219 | for (int i = start; i < end; ++i) { 220 | double x2 = m[0][0] * x[i] + m[0][1] * y[i] + m[0][2] * z[i]; 221 | double y2 = m[1][0] * x[i] + m[1][1] * y[i] + m[1][2] * z[i]; 222 | double z2 = m[2][0] * x[i] + m[2][1] * y[i] + m[2][2] * z[i]; 223 | x[i] = x2; 224 | y[i] = y2; 225 | z[i] = z2; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/gflags/mutex.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2007, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // --- 31 | // Author: Craig Silverstein. 32 | // 33 | // A simple mutex wrapper, supporting locks and read-write locks. 34 | // You should assume the locks are *not* re-entrant. 35 | // 36 | // To use: you should define the following macros in your configure.ac: 37 | // ACX_PTHREAD 38 | // AC_RWLOCK 39 | // The latter is defined in ../autoconf. 40 | // 41 | // This class is meant to be internal-only and should be wrapped by an 42 | // internal namespace. Before you use this module, please give the 43 | // name of your internal namespace for this module. Or, if you want 44 | // to expose it, you'll want to move it to the Google namespace. We 45 | // cannot put this class in global namespace because there can be some 46 | // problems when we have multiple versions of Mutex in each shared object. 47 | // 48 | // NOTE: by default, we have #ifdef'ed out the TryLock() method. 49 | // This is for two reasons: 50 | // 1) TryLock() under Windows is a bit annoying (it requires a 51 | // #define to be defined very early). 52 | // 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG 53 | // mode. 54 | // If you need TryLock(), and either these two caveats are not a 55 | // problem for you, or you're willing to work around them, then 56 | // feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs 57 | // in the code below. 58 | // 59 | // CYGWIN NOTE: Cygwin support for rwlock seems to be buggy: 60 | // http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html 61 | // Because of that, we might as well use windows locks for 62 | // cygwin. They seem to be more reliable than the cygwin pthreads layer. 63 | // 64 | // TRICKY IMPLEMENTATION NOTE: 65 | // This class is designed to be safe to use during 66 | // dynamic-initialization -- that is, by global constructors that are 67 | // run before main() starts. The issue in this case is that 68 | // dynamic-initialization happens in an unpredictable order, and it 69 | // could be that someone else's dynamic initializer could call a 70 | // function that tries to acquire this mutex -- but that all happens 71 | // before this mutex's constructor has run. (This can happen even if 72 | // the mutex and the function that uses the mutex are in the same .cc 73 | // file.) Basically, because Mutex does non-trivial work in its 74 | // constructor, it's not, in the naive implementation, safe to use 75 | // before dynamic initialization has run on it. 76 | // 77 | // The solution used here is to pair the actual mutex primitive with a 78 | // bool that is set to true when the mutex is dynamically initialized. 79 | // (Before that it's false.) Then we modify all mutex routines to 80 | // look at the bool, and not try to lock/unlock until the bool makes 81 | // it to true (which happens after the Mutex constructor has run.) 82 | // 83 | // This works because before main() starts -- particularly, during 84 | // dynamic initialization -- there are no threads, so a) it's ok that 85 | // the mutex operations are a no-op, since we don't need locking then 86 | // anyway; and b) we can be quite confident our bool won't change 87 | // state between a call to Lock() and a call to Unlock() (that would 88 | // require a global constructor in one translation unit to call Lock() 89 | // and another global constructor in another translation unit to call 90 | // Unlock() later, which is pretty perverse). 91 | // 92 | // That said, it's tricky, and can conceivably fail; it's safest to 93 | // avoid trying to acquire a mutex in a global constructor, if you 94 | // can. One way it can fail is that a really smart compiler might 95 | // initialize the bool to true at static-initialization time (too 96 | // early) rather than at dynamic-initialization time. To discourage 97 | // that, we set is_safe_ to true in code (not the constructor 98 | // colon-initializer) and set it to true via a function that always 99 | // evaluates to true, but that the compiler can't know always 100 | // evaluates to true. This should be good enough. 101 | // 102 | // A related issue is code that could try to access the mutex 103 | // after it's been destroyed in the global destructors (because 104 | // the Mutex global destructor runs before some other global 105 | // destructor, that tries to acquire the mutex). The way we 106 | // deal with this is by taking a constructor arg that global 107 | // mutexes should pass in, that causes the destructor to do no 108 | // work. We still depend on the compiler not doing anything 109 | // weird to a Mutex's memory after it is destroyed, but for a 110 | // static global variable, that's pretty safe. 111 | 112 | #ifndef GOOGLE_MUTEX_H_ 113 | #define GOOGLE_MUTEX_H_ 114 | 115 | #include "config.hpp" // to figure out pthreads support 116 | 117 | #if defined(NO_THREADS) 118 | typedef int MutexType; // to keep a lock-count 119 | #elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__) 120 | # define WIN32_LEAN_AND_MEAN // We only need minimal includes 121 | # ifdef GMUTEX_TRYLOCK 122 | // We need Windows NT or later for TryEnterCriticalSection(). If you 123 | // don't need that functionality, you can remove these _WIN32_WINNT 124 | // lines, and change TryLock() to assert(0) or something. 125 | # ifndef _WIN32_WINNT 126 | # define _WIN32_WINNT 0x0400 127 | # endif 128 | # endif 129 | # include 130 | typedef CRITICAL_SECTION MutexType; 131 | #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) 132 | // Needed for pthread_rwlock_*. If it causes problems, you could take it 133 | // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it 134 | // *does* cause problems for FreeBSD, or MacOSX, but isn't needed 135 | // for locking there.) 136 | # ifdef __linux__ 137 | # define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls 138 | # endif 139 | # include 140 | typedef pthread_rwlock_t MutexType; 141 | #elif defined(HAVE_PTHREAD) 142 | # include 143 | typedef pthread_mutex_t MutexType; 144 | #else 145 | # error Need to implement mutex.h for your architecture, or #define NO_THREADS 146 | #endif 147 | 148 | #include 149 | #include // for abort() 150 | 151 | #define MUTEX_NAMESPACE gflags_mutex_namespace 152 | 153 | namespace MUTEX_NAMESPACE { 154 | 155 | class Mutex { 156 | public: 157 | // This is used for the single-arg constructor 158 | enum LinkerInitialized { LINKER_INITIALIZED }; 159 | 160 | // Create a Mutex that is not held by anybody. This constructor is 161 | // typically used for Mutexes allocated on the heap or the stack. 162 | inline Mutex(); 163 | // This constructor should be used for global, static Mutex objects. 164 | // It inhibits work being done by the destructor, which makes it 165 | // safer for code that tries to acqiure this mutex in their global 166 | // destructor. 167 | inline Mutex(LinkerInitialized); 168 | 169 | // Destructor 170 | inline ~Mutex(); 171 | 172 | inline void Lock(); // Block if needed until free then acquire exclusively 173 | inline void Unlock(); // Release a lock acquired via Lock() 174 | #ifdef GMUTEX_TRYLOCK 175 | inline bool TryLock(); // If free, Lock() and return true, else return false 176 | #endif 177 | // Note that on systems that don't support read-write locks, these may 178 | // be implemented as synonyms to Lock() and Unlock(). So you can use 179 | // these for efficiency, but don't use them anyplace where being able 180 | // to do shared reads is necessary to avoid deadlock. 181 | inline void ReaderLock(); // Block until free or shared then acquire a share 182 | inline void ReaderUnlock(); // Release a read share of this Mutex 183 | inline void WriterLock() { Lock(); } // Acquire an exclusive lock 184 | inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock() 185 | 186 | private: 187 | MutexType mutex_; 188 | // We want to make sure that the compiler sets is_safe_ to true only 189 | // when we tell it to, and never makes assumptions is_safe_ is 190 | // always true. volatile is the most reliable way to do that. 191 | volatile bool is_safe_; 192 | // This indicates which constructor was called. 193 | bool destroy_; 194 | 195 | inline void SetIsSafe() { is_safe_ = true; } 196 | 197 | // Catch the error of writing Mutex when intending MutexLock. 198 | Mutex(Mutex* /*ignored*/) {} 199 | // Disallow "evil" constructors 200 | Mutex(const Mutex&); 201 | void operator=(const Mutex&); 202 | }; 203 | 204 | // Now the implementation of Mutex for various systems 205 | #if defined(NO_THREADS) 206 | 207 | // When we don't have threads, we can be either reading or writing, 208 | // but not both. We can have lots of readers at once (in no-threads 209 | // mode, that's most likely to happen in recursive function calls), 210 | // but only one writer. We represent this by having mutex_ be -1 when 211 | // writing and a number > 0 when reading (and 0 when no lock is held). 212 | // 213 | // In debug mode, we assert these invariants, while in non-debug mode 214 | // we do nothing, for efficiency. That's why everything is in an 215 | // assert. 216 | 217 | Mutex::Mutex() : mutex_(0) { } 218 | Mutex::Mutex(Mutex::LinkerInitialized) : mutex_(0) { } 219 | Mutex::~Mutex() { assert(mutex_ == 0); } 220 | void Mutex::Lock() { assert(--mutex_ == -1); } 221 | void Mutex::Unlock() { assert(mutex_++ == -1); } 222 | #ifdef GMUTEX_TRYLOCK 223 | bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; } 224 | #endif 225 | void Mutex::ReaderLock() { assert(++mutex_ > 0); } 226 | void Mutex::ReaderUnlock() { assert(mutex_-- > 0); } 227 | 228 | #elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__) 229 | 230 | Mutex::Mutex() : destroy_(true) { 231 | InitializeCriticalSection(&mutex_); 232 | SetIsSafe(); 233 | } 234 | Mutex::Mutex(LinkerInitialized) : destroy_(false) { 235 | InitializeCriticalSection(&mutex_); 236 | SetIsSafe(); 237 | } 238 | Mutex::~Mutex() { if (destroy_) DeleteCriticalSection(&mutex_); } 239 | void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); } 240 | void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); } 241 | #ifdef GMUTEX_TRYLOCK 242 | bool Mutex::TryLock() { return is_safe_ ? 243 | TryEnterCriticalSection(&mutex_) != 0 : true; } 244 | #endif 245 | void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks 246 | void Mutex::ReaderUnlock() { Unlock(); } 247 | 248 | #elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK) 249 | 250 | #define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ 251 | if (is_safe_ && fncall(&mutex_) != 0) abort(); \ 252 | } while (0) 253 | 254 | Mutex::Mutex() : destroy_(true) { 255 | SetIsSafe(); 256 | if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort(); 257 | } 258 | Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) { 259 | SetIsSafe(); 260 | if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort(); 261 | } 262 | Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_rwlock_destroy); } 263 | void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); } 264 | void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } 265 | #ifdef GMUTEX_TRYLOCK 266 | bool Mutex::TryLock() { return is_safe_ ? 267 | pthread_rwlock_trywrlock(&mutex_) == 0 : true; } 268 | #endif 269 | void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); } 270 | void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); } 271 | #undef SAFE_PTHREAD 272 | 273 | #elif defined(HAVE_PTHREAD) 274 | 275 | #define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \ 276 | if (is_safe_ && fncall(&mutex_) != 0) abort(); \ 277 | } while (0) 278 | 279 | Mutex::Mutex() : destroy_(true) { 280 | SetIsSafe(); 281 | if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort(); 282 | } 283 | Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) { 284 | SetIsSafe(); 285 | if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort(); 286 | } 287 | Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_mutex_destroy); } 288 | void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); } 289 | void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); } 290 | #ifdef GMUTEX_TRYLOCK 291 | bool Mutex::TryLock() { return is_safe_ ? 292 | pthread_mutex_trylock(&mutex_) == 0 : true; } 293 | #endif 294 | void Mutex::ReaderLock() { Lock(); } 295 | void Mutex::ReaderUnlock() { Unlock(); } 296 | #undef SAFE_PTHREAD 297 | 298 | #endif 299 | 300 | // -------------------------------------------------------------------------- 301 | // Some helper classes 302 | 303 | // MutexLock(mu) acquires mu when constructed and releases it when destroyed. 304 | class MutexLock { 305 | public: 306 | explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); } 307 | ~MutexLock() { mu_->Unlock(); } 308 | private: 309 | Mutex * const mu_; 310 | // Disallow "evil" constructors 311 | MutexLock(const MutexLock&); 312 | void operator=(const MutexLock&); 313 | }; 314 | 315 | // ReaderMutexLock and WriterMutexLock do the same, for rwlocks 316 | class ReaderMutexLock { 317 | public: 318 | explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); } 319 | ~ReaderMutexLock() { mu_->ReaderUnlock(); } 320 | private: 321 | Mutex * const mu_; 322 | // Disallow "evil" constructors 323 | ReaderMutexLock(const ReaderMutexLock&); 324 | void operator=(const ReaderMutexLock&); 325 | }; 326 | 327 | class WriterMutexLock { 328 | public: 329 | explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); } 330 | ~WriterMutexLock() { mu_->WriterUnlock(); } 331 | private: 332 | Mutex * const mu_; 333 | // Disallow "evil" constructors 334 | WriterMutexLock(const WriterMutexLock&); 335 | void operator=(const WriterMutexLock&); 336 | }; 337 | 338 | // Catch bug where variable name is omitted, e.g. MutexLock (&mu); 339 | #define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name) 340 | #define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name) 341 | #define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name) 342 | 343 | } // namespace MUTEX_NAMESPACE 344 | 345 | using namespace MUTEX_NAMESPACE; 346 | 347 | #undef MUTEX_NAMESPACE 348 | 349 | #endif /* #define GOOGLE_MUTEX_H__ */ 350 | -------------------------------------------------------------------------------- /src/gflags/gflags_reporting.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // --- 31 | // Author: Ray Sidney 32 | // Revamped and reorganized by Craig Silverstein 33 | // 34 | // This file contains code for handling the 'reporting' flags. These 35 | // are flags that, when present, cause the program to report some 36 | // information and then exit. --help and --version are the canonical 37 | // reporting flags, but we also have flags like --helpxml, etc. 38 | // 39 | // There's only one function that's meant to be called externally: 40 | // HandleCommandLineHelpFlags(). (Well, actually, ShowUsageWithFlags(), 41 | // ShowUsageWithFlagsRestrict(), and DescribeOneFlag() can be called 42 | // externally too, but there's little need for it.) These are all 43 | // declared in the main commandlineflags.h header file. 44 | // 45 | // HandleCommandLineHelpFlags() will check what 'reporting' flags have 46 | // been defined, if any -- the "help" part of the function name is a 47 | // bit misleading -- and do the relevant reporting. It should be 48 | // called after all flag-values have been assigned, that is, after 49 | // parsing the command-line. 50 | 51 | #include "config.hpp" 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include "gflags.hpp" 59 | #include "gflags_completions.hpp" 60 | 61 | #ifndef PATH_SEPARATOR 62 | #define PATH_SEPARATOR '/' 63 | #endif 64 | 65 | // The 'reporting' flags. They all call exit(). 66 | DEFINE_bool(help, false, 67 | "show help on all flags [tip: all flags can have two dashes]"); 68 | DEFINE_bool(helpfull, false, 69 | "show help on all flags -- same as -help"); 70 | DEFINE_bool(helpshort, false, 71 | "show help on only the main module for this program"); 72 | DEFINE_string(helpon, "", 73 | "show help on the modules named by this flag value"); 74 | DEFINE_string(helpmatch, "", 75 | "show help on modules whose name contains the specified substr"); 76 | DEFINE_bool(helppackage, false, 77 | "show help on all modules in the main package"); 78 | DEFINE_bool(helpxml, false, 79 | "produce an xml version of help"); 80 | DEFINE_bool(version, false, 81 | "show version and build info and exit"); 82 | 83 | _START_GOOGLE_NAMESPACE_ 84 | 85 | using std::string; 86 | using std::vector; 87 | 88 | // -------------------------------------------------------------------- 89 | // DescribeOneFlag() 90 | // DescribeOneFlagInXML() 91 | // Routines that pretty-print info about a flag. These use 92 | // a CommandLineFlagInfo, which is the way the commandlineflags 93 | // API exposes static info about a flag. 94 | // -------------------------------------------------------------------- 95 | 96 | static const int kLineLength = 80; 97 | 98 | static void AddString(const string& s, 99 | string* final_string, int* chars_in_line) { 100 | const int slen = static_cast(s.length()); 101 | if (*chars_in_line + 1 + slen >= kLineLength) { // < 80 chars/line 102 | *final_string += "\n "; 103 | *chars_in_line = 6; 104 | } else { 105 | *final_string += " "; 106 | *chars_in_line += 1; 107 | } 108 | *final_string += s; 109 | *chars_in_line += slen; 110 | } 111 | 112 | static string PrintStringFlagsWithQuotes(const CommandLineFlagInfo& flag, 113 | const string& text, bool current) { 114 | const char* c_string = (current ? flag.current_value.c_str() : 115 | flag.default_value.c_str()); 116 | if (strcmp(flag.type.c_str(), "string") == 0) { // add quotes for strings 117 | return text + ": \"" + c_string + "\""; 118 | } else { 119 | return text + ": " + c_string; 120 | } 121 | } 122 | 123 | // Create a descriptive string for a flag. 124 | // Goes to some trouble to make pretty line breaks. 125 | string DescribeOneFlag(const CommandLineFlagInfo& flag) { 126 | string main_part = (string(" -") + flag.name + 127 | " (" + flag.description + ')'); 128 | const char* c_string = main_part.c_str(); 129 | int chars_left = static_cast(main_part.length()); 130 | string final_string = ""; 131 | int chars_in_line = 0; // how many chars in current line so far? 132 | while (1) { 133 | assert(chars_left == strlen(c_string)); // Unless there's a \0 in there? 134 | const char* newline = strchr(c_string, '\n'); 135 | if (newline == NULL && chars_in_line+chars_left < kLineLength) { 136 | // The whole remainder of the string fits on this line 137 | final_string += c_string; 138 | chars_in_line += chars_left; 139 | break; 140 | } 141 | if (newline != NULL && newline - c_string < kLineLength - chars_in_line) { 142 | int n = static_cast(newline - c_string); 143 | final_string.append(c_string, n); 144 | chars_left -= n + 1; 145 | c_string += n + 1; 146 | } else { 147 | // Find the last whitespace on this 80-char line 148 | int whitespace = kLineLength-chars_in_line-1; // < 80 chars/line 149 | while ( whitespace > 0 && !isspace(c_string[whitespace]) ) { 150 | --whitespace; 151 | } 152 | if (whitespace <= 0) { 153 | // Couldn't find any whitespace to make a line break. Just dump the 154 | // rest out! 155 | final_string += c_string; 156 | chars_in_line = kLineLength; // next part gets its own line for sure! 157 | break; 158 | } 159 | final_string += string(c_string, whitespace); 160 | chars_in_line += whitespace; 161 | while (isspace(c_string[whitespace])) ++whitespace; 162 | c_string += whitespace; 163 | chars_left -= whitespace; 164 | } 165 | if (*c_string == '\0') 166 | break; 167 | final_string += "\n "; 168 | chars_in_line = 6; 169 | } 170 | 171 | // Append data type 172 | AddString(string("type: ") + flag.type, &final_string, &chars_in_line); 173 | // The listed default value will be the actual default from the flag 174 | // definition in the originating source file, unless the value has 175 | // subsequently been modified using SetCommandLineOptionWithMode() with mode 176 | // SET_FLAGS_DEFAULT, or by setting FLAGS_foo = bar before initializing. 177 | AddString(PrintStringFlagsWithQuotes(flag, "default", false), &final_string, 178 | &chars_in_line); 179 | if (!flag.is_default) { 180 | AddString(PrintStringFlagsWithQuotes(flag, "currently", true), 181 | &final_string, &chars_in_line); 182 | } 183 | 184 | final_string += '\n'; 185 | return final_string; 186 | } 187 | 188 | // Simple routine to xml-escape a string: escape & and < only. 189 | static string XMLText(const string& txt) { 190 | string ans = txt; 191 | for (string::size_type pos = 0; (pos = ans.find("&", pos)) != string::npos; ) 192 | ans.replace(pos++, 1, "&"); 193 | for (string::size_type pos = 0; (pos = ans.find("<", pos)) != string::npos; ) 194 | ans.replace(pos++, 1, "<"); 195 | return ans; 196 | } 197 | 198 | static void AddXMLTag(string* r, const char* tag, const string& txt) { 199 | *r += ('<'); 200 | *r += (tag); 201 | *r += ('>'); 202 | *r += (XMLText(txt)); 203 | *r += ("'); 206 | } 207 | 208 | static string DescribeOneFlagInXML(const CommandLineFlagInfo& flag) { 209 | // The file and flagname could have been attributes, but default 210 | // and meaning need to avoid attribute normalization. This way it 211 | // can be parsed by simple programs, in addition to xml parsers. 212 | string r(""); 213 | AddXMLTag(&r, "file", flag.filename); 214 | AddXMLTag(&r, "name", flag.name); 215 | AddXMLTag(&r, "meaning", flag.description); 216 | AddXMLTag(&r, "default", flag.default_value); 217 | AddXMLTag(&r, "current", flag.current_value); 218 | AddXMLTag(&r, "type", flag.type); 219 | r += ""; 220 | return r; 221 | } 222 | 223 | // -------------------------------------------------------------------- 224 | // ShowUsageWithFlags() 225 | // ShowUsageWithFlagsRestrict() 226 | // ShowXMLOfFlags() 227 | // These routines variously expose the registry's list of flag 228 | // values. ShowUsage*() prints the flag-value information 229 | // to stdout in a user-readable format (that's what --help uses). 230 | // The Restrict() version limits what flags are shown. 231 | // ShowXMLOfFlags() prints the flag-value information to stdout 232 | // in a machine-readable format. In all cases, the flags are 233 | // sorted: first by filename they are defined in, then by flagname. 234 | // -------------------------------------------------------------------- 235 | 236 | static const char* Basename(const char* filename) { 237 | const char* sep = strrchr(filename, PATH_SEPARATOR); 238 | return sep ? sep + 1 : filename; 239 | } 240 | 241 | static string Dirname(const string& filename) { 242 | string::size_type sep = filename.rfind(PATH_SEPARATOR); 243 | return filename.substr(0, (sep == string::npos) ? 0 : sep); 244 | } 245 | 246 | // Test whether a filename contains at least one of the substrings. 247 | static bool FileMatchesSubstring(const string& filename, 248 | const vector& substrings) { 249 | for (vector::const_iterator target = substrings.begin(); 250 | target != substrings.end(); 251 | ++target) { 252 | if (strstr(filename.c_str(), target->c_str()) != NULL) 253 | return true; 254 | // If the substring starts with a '/', that means that we want 255 | // the string to be at the beginning of a directory component. 256 | // That should match the first directory component as well, so 257 | // we allow '/foo' to match a filename of 'foo'. 258 | if (!target->empty() && (*target)[0] == '/' && 259 | strncmp(filename.c_str(), target->c_str() + 1, 260 | strlen(target->c_str() + 1)) == 0) 261 | return true; 262 | } 263 | return false; 264 | } 265 | 266 | // Show help for every filename which matches any of the target substrings. 267 | // If substrings is empty, shows help for every file. If a flag's help message 268 | // has been stripped (e.g. by adding '#define STRIP_FLAG_HELP 1' before 269 | // including gflags/gflags.h), then this flag will not be displayed by 270 | // '--help' and its variants. 271 | static void ShowUsageWithFlagsMatching(const char *argv0, 272 | const vector &substrings) { 273 | fprintf(stdout, "%s: %s\n", Basename(argv0), ProgramUsage()); 274 | 275 | vector flags; 276 | GetAllFlags(&flags); // flags are sorted by filename, then flagname 277 | 278 | string last_filename; // so we know when we're at a new file 279 | bool first_directory = true; // controls blank lines between dirs 280 | bool found_match = false; // stays false iff no dir matches restrict 281 | for (vector::const_iterator flag = flags.begin(); 282 | flag != flags.end(); 283 | ++flag) { 284 | if (substrings.empty() || 285 | FileMatchesSubstring(flag->filename, substrings)) { 286 | // If the flag has been stripped, pretend that it doesn't exist. 287 | if (flag->description == kStrippedFlagHelp) continue; 288 | found_match = true; // this flag passed the match! 289 | if (flag->filename != last_filename) { // new file 290 | if (Dirname(flag->filename) != Dirname(last_filename)) { // new dir! 291 | if (!first_directory) 292 | fprintf(stdout, "\n\n"); // put blank lines between directories 293 | first_directory = false; 294 | } 295 | fprintf(stdout, "\n Flags from %s:\n", flag->filename.c_str()); 296 | last_filename = flag->filename; 297 | } 298 | // Now print this flag 299 | fprintf(stdout, "%s", DescribeOneFlag(*flag).c_str()); 300 | } 301 | } 302 | if (!found_match && !substrings.empty()) { 303 | fprintf(stdout, "\n No modules matched: use -help\n"); 304 | } 305 | } 306 | 307 | void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict) { 308 | vector substrings; 309 | if (restrict != NULL && *restrict != '\0') { 310 | substrings.push_back(restrict); 311 | } 312 | ShowUsageWithFlagsMatching(argv0, substrings); 313 | } 314 | 315 | void ShowUsageWithFlags(const char *argv0) { 316 | ShowUsageWithFlagsRestrict(argv0, ""); 317 | } 318 | 319 | // Convert the help, program, and usage to xml. 320 | static void ShowXMLOfFlags(const char *prog_name) { 321 | vector flags; 322 | GetAllFlags(&flags); // flags are sorted: by filename, then flagname 323 | 324 | // XML. There is no corresponding schema yet 325 | fprintf(stdout, "\n"); 326 | // The document 327 | fprintf(stdout, "\n"); 328 | // the program name and usage 329 | fprintf(stdout, "%s\n", 330 | XMLText(Basename(prog_name)).c_str()); 331 | fprintf(stdout, "%s\n", 332 | XMLText(ProgramUsage()).c_str()); 333 | // All the flags 334 | for (vector::const_iterator flag = flags.begin(); 335 | flag != flags.end(); 336 | ++flag) { 337 | if (flag->description != kStrippedFlagHelp) 338 | fprintf(stdout, "%s\n", DescribeOneFlagInXML(*flag).c_str()); 339 | } 340 | // The end of the document 341 | fprintf(stdout, "\n"); 342 | } 343 | 344 | // -------------------------------------------------------------------- 345 | // ShowVersion() 346 | // Called upon --version. Prints build-related info. 347 | // -------------------------------------------------------------------- 348 | 349 | static void ShowVersion() { 350 | fprintf(stdout, "%s\n", ProgramInvocationShortName()); 351 | // TODO: add other stuff, like a timestamp, who built it, what 352 | // target they built, etc. 353 | 354 | # if !defined(NDEBUG) 355 | fprintf(stdout, "Debug build (NDEBUG not #defined)\n"); 356 | # endif 357 | } 358 | 359 | static void AppendPrognameStrings(vector* substrings, 360 | const char* progname) { 361 | string r("/"); 362 | r += progname; 363 | substrings->push_back(r + "."); 364 | substrings->push_back(r + "-main."); 365 | substrings->push_back(r + "_main."); 366 | } 367 | 368 | // -------------------------------------------------------------------- 369 | // HandleCommandLineHelpFlags() 370 | // Checks all the 'reporting' commandline flags to see if any 371 | // have been set. If so, handles them appropriately. Note 372 | // that all of them, by definition, cause the program to exit 373 | // if they trigger. 374 | // -------------------------------------------------------------------- 375 | 376 | void HandleCommandLineHelpFlags() { 377 | const char* progname = ProgramInvocationShortName(); 378 | extern void (*commandlineflags_exitfunc)(int); // in gflags.cc 379 | 380 | HandleCommandLineCompletions(); 381 | 382 | vector substrings; 383 | AppendPrognameStrings(&substrings, progname); 384 | 385 | if (FLAGS_helpshort) { 386 | // show only flags related to this binary: 387 | // E.g. for fileutil.cc, want flags containing ... "/fileutil." cc 388 | ShowUsageWithFlagsMatching(progname, substrings); 389 | commandlineflags_exitfunc(1); // almost certainly exit() 390 | 391 | } else if (FLAGS_help || FLAGS_helpfull) { 392 | // show all options 393 | ShowUsageWithFlagsRestrict(progname, ""); // empty restrict 394 | commandlineflags_exitfunc(1); 395 | 396 | } else if (!FLAGS_helpon.empty()) { 397 | string restrict = "/" + FLAGS_helpon + "."; 398 | ShowUsageWithFlagsRestrict(progname, restrict.c_str()); 399 | commandlineflags_exitfunc(1); 400 | 401 | } else if (!FLAGS_helpmatch.empty()) { 402 | ShowUsageWithFlagsRestrict(progname, FLAGS_helpmatch.c_str()); 403 | commandlineflags_exitfunc(1); 404 | 405 | } else if (FLAGS_helppackage) { 406 | // Shows help for all files in the same directory as main(). We 407 | // don't want to resort to looking at dirname(progname), because 408 | // the user can pick progname, and it may not relate to the file 409 | // where main() resides. So instead, we search the flags for a 410 | // filename like "/progname.cc", and take the dirname of that. 411 | vector flags; 412 | GetAllFlags(&flags); 413 | string last_package; 414 | for (vector::const_iterator flag = flags.begin(); 415 | flag != flags.end(); 416 | ++flag) { 417 | if (!FileMatchesSubstring(flag->filename, substrings)) 418 | continue; 419 | const string package = Dirname(flag->filename) + "/"; 420 | if (package != last_package) { 421 | ShowUsageWithFlagsRestrict(progname, package.c_str()); 422 | if (!last_package.empty()) { // means this isn't our first pkg 423 | fprintf(stderr, "WARNING: Multiple packages contain a file=%s\n", 424 | progname); 425 | } 426 | last_package = package; 427 | } 428 | } 429 | if (last_package.empty()) { // never found a package to print 430 | fprintf(stderr, "WARNING: Unable to find a package for file=%s\n", 431 | progname); 432 | } 433 | commandlineflags_exitfunc(1); 434 | 435 | } else if (FLAGS_helpxml) { 436 | ShowXMLOfFlags(progname); 437 | commandlineflags_exitfunc(1); 438 | 439 | } else if (FLAGS_version) { 440 | ShowVersion(); 441 | // Unlike help, we may be asking for version in a script, so return 0 442 | commandlineflags_exitfunc(0); 443 | } 444 | } 445 | 446 | _END_GOOGLE_NAMESPACE_ 447 | -------------------------------------------------------------------------------- /src/gflags/gflags_completions.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2008, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | // --- 31 | // Author: Dave Nicponski 32 | // 33 | // Bash-style command line flag completion for C++ binaries 34 | // 35 | // This module implements bash-style completions. It achieves this 36 | // goal in the following broad chunks: 37 | // 38 | // 1) Take a to-be-completed word, and examine it for search hints 39 | // 2) Identify all potentially matching flags 40 | // 2a) If there are no matching flags, do nothing. 41 | // 2b) If all matching flags share a common prefix longer than the 42 | // completion word, output just that matching prefix 43 | // 3) Categorize those flags to produce a rough ordering of relevence. 44 | // 4) Potentially trim the set of flags returned to a smaller number 45 | // that bash is happier with 46 | // 5) Output the matching flags in groups ordered by relevence. 47 | // 5a) Force bash to place most-relevent groups at the top of the list 48 | // 5b) Trim most flag's descriptions to fit on a single terminal line 49 | 50 | 51 | #include "config.hpp" 52 | #include 53 | #include 54 | #include // for strlen 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | 61 | #include "gflags.hpp" 62 | 63 | #ifndef PATH_SEPARATOR 64 | #define PATH_SEPARATOR '/' 65 | #endif 66 | 67 | DEFINE_string(tab_completion_word, "", 68 | "If non-empty, HandleCommandLineCompletions() will hijack the " 69 | "process and attempt to do bash-style command line flag " 70 | "completion on this value."); 71 | DEFINE_int32(tab_completion_columns, 80, 72 | "Number of columns to use in output for tab completion"); 73 | 74 | _START_GOOGLE_NAMESPACE_ 75 | 76 | namespace { 77 | 78 | using std::set; 79 | using std::string; 80 | using std::vector; 81 | 82 | // Function prototypes and Type forward declarations. Code may be 83 | // more easily understood if it is roughly ordered according to 84 | // control flow, rather than by C's "declare before use" ordering 85 | struct CompletionOptions; 86 | struct NotableFlags; 87 | 88 | // The entry point if flag completion is to be used. 89 | static void PrintFlagCompletionInfo(void); 90 | 91 | 92 | // 1) Examine search word 93 | static void CanonicalizeCursorWordAndSearchOptions( 94 | const string &cursor_word, 95 | string *canonical_search_token, 96 | CompletionOptions *options); 97 | 98 | static bool RemoveTrailingChar(string *str, char c); 99 | 100 | 101 | // 2) Find all matches 102 | static void FindMatchingFlags( 103 | const vector &all_flags, 104 | const CompletionOptions &options, 105 | const string &match_token, 106 | set *all_matches, 107 | string *longest_common_prefix); 108 | 109 | static bool DoesSingleFlagMatch( 110 | const CommandLineFlagInfo &flag, 111 | const CompletionOptions &options, 112 | const string &match_token); 113 | 114 | 115 | // 3) Categorize matches 116 | static void CategorizeAllMatchingFlags( 117 | const set &all_matches, 118 | const string &search_token, 119 | const string &module, 120 | const string &package_dir, 121 | NotableFlags *notable_flags); 122 | 123 | static void TryFindModuleAndPackageDir( 124 | const vector all_flags, 125 | string *module, 126 | string *package_dir); 127 | 128 | 129 | // 4) Decide which flags to use 130 | static void FinalizeCompletionOutput( 131 | const set &matching_flags, 132 | CompletionOptions *options, 133 | NotableFlags *notable_flags, 134 | vector *completions); 135 | 136 | static void RetrieveUnusedFlags( 137 | const set &matching_flags, 138 | const NotableFlags ¬able_flags, 139 | set *unused_flags); 140 | 141 | 142 | // 5) Output matches 143 | static void OutputSingleGroupWithLimit( 144 | const set &group, 145 | const string &line_indentation, 146 | const string &header, 147 | const string &footer, 148 | bool long_output_format, 149 | int *remaining_line_limit, 150 | size_t *completion_elements_added, 151 | vector *completions); 152 | 153 | // (helpers for #5) 154 | static string GetShortFlagLine( 155 | const string &line_indentation, 156 | const CommandLineFlagInfo &info); 157 | 158 | static string GetLongFlagLine( 159 | const string &line_indentation, 160 | const CommandLineFlagInfo &info); 161 | 162 | 163 | // 164 | // Useful types 165 | 166 | // Try to deduce the intentions behind this completion attempt. Return the 167 | // canonical search term in 'canonical_search_token'. Binary search options 168 | // are returned in the various booleans, which should all have intuitive 169 | // semantics, possibly except: 170 | // - return_all_matching_flags: Generally, we'll trim the number of 171 | // returned candidates to some small number, showing those that are 172 | // most likely to be useful first. If this is set, however, the user 173 | // really does want us to return every single flag as an option. 174 | // - force_no_update: Any time we output lines, all of which share a 175 | // common prefix, bash will 'helpfully' not even bother to show the 176 | // output, instead changing the current word to be that common prefix. 177 | // If it's clear this shouldn't happen, we'll set this boolean 178 | struct CompletionOptions { 179 | bool flag_name_substring_search; 180 | bool flag_location_substring_search; 181 | bool flag_description_substring_search; 182 | bool return_all_matching_flags; 183 | bool force_no_update; 184 | }; 185 | 186 | // Notable flags are flags that are special or preferred for some 187 | // reason. For example, flags that are defined in the binary's module 188 | // are expected to be much more relevent than flags defined in some 189 | // other random location. These sets are specified roughly in precedence 190 | // order. Once a flag is placed in one of these 'higher' sets, it won't 191 | // be placed in any of the 'lower' sets. 192 | struct NotableFlags { 193 | typedef set FlagSet; 194 | FlagSet perfect_match_flag; 195 | FlagSet module_flags; // Found in module file 196 | FlagSet package_flags; // Found in same directory as module file 197 | FlagSet most_common_flags; // One of the XXX most commonly supplied flags 198 | FlagSet subpackage_flags; // Found in subdirectories of package 199 | }; 200 | 201 | 202 | // 203 | // Tab completion implementation - entry point 204 | static void PrintFlagCompletionInfo(void) { 205 | string cursor_word = FLAGS_tab_completion_word; 206 | string canonical_token; 207 | CompletionOptions options = { }; 208 | CanonicalizeCursorWordAndSearchOptions( 209 | cursor_word, 210 | &canonical_token, 211 | &options); 212 | 213 | //VLOG(1) << "Identified canonical_token: '" << canonical_token << "'"; 214 | 215 | vector all_flags; 216 | set matching_flags; 217 | GetAllFlags(&all_flags); 218 | //VLOG(2) << "Found " << all_flags.size() << " flags overall"; 219 | 220 | string longest_common_prefix; 221 | FindMatchingFlags( 222 | all_flags, 223 | options, 224 | canonical_token, 225 | &matching_flags, 226 | &longest_common_prefix); 227 | //VLOG(1) << "Identified " << matching_flags.size() << " matching flags"; 228 | //VLOG(1) << "Identified " << longest_common_prefix 229 | // << " as longest common prefix."; 230 | if (longest_common_prefix.size() > canonical_token.size()) { 231 | // There's actually a shared common prefix to all matching flags, 232 | // so may as well output that and quit quickly. 233 | //VLOG(1) << "The common prefix '" << longest_common_prefix 234 | // << "' was longer than the token '" << canonical_token 235 | // << "'. Returning just this prefix for completion."; 236 | fprintf(stdout, "--%s", longest_common_prefix.c_str()); 237 | return; 238 | } 239 | if (matching_flags.empty()) { 240 | //VLOG(1) << "There were no matching flags, returning nothing."; 241 | return; 242 | } 243 | 244 | string module; 245 | string package_dir; 246 | TryFindModuleAndPackageDir(all_flags, &module, &package_dir); 247 | //VLOG(1) << "Identified module: '" << module << "'"; 248 | //VLOG(1) << "Identified package_dir: '" << package_dir << "'"; 249 | 250 | NotableFlags notable_flags; 251 | CategorizeAllMatchingFlags( 252 | matching_flags, 253 | canonical_token, 254 | module, 255 | package_dir, 256 | ¬able_flags); 257 | //VLOG(2) << "Categorized matching flags:"; 258 | //VLOG(2) << " perfect_match: " << notable_flags.perfect_match_flag.size(); 259 | //VLOG(2) << " module: " << notable_flags.module_flags.size(); 260 | //VLOG(2) << " package: " << notable_flags.package_flags.size(); 261 | //VLOG(2) << " most common: " << notable_flags.most_common_flags.size(); 262 | //VLOG(2) << " subpackage: " << notable_flags.subpackage_flags.size(); 263 | 264 | vector completions; 265 | FinalizeCompletionOutput( 266 | matching_flags, 267 | &options, 268 | ¬able_flags, 269 | &completions); 270 | 271 | if (options.force_no_update) 272 | completions.push_back("~"); 273 | 274 | //VLOG(1) << "Finalized with " << completions.size() 275 | // << " chosen completions"; 276 | 277 | for (vector::const_iterator it = completions.begin(); 278 | it != completions.end(); 279 | ++it) { 280 | //VLOG(9) << " Completion entry: '" << *it << "'"; 281 | fprintf(stdout, "%s\n", it->c_str()); 282 | } 283 | } 284 | 285 | 286 | // 1) Examine search word (and helper method) 287 | static void CanonicalizeCursorWordAndSearchOptions( 288 | const string &cursor_word, 289 | string *canonical_search_token, 290 | CompletionOptions *options) { 291 | *canonical_search_token = cursor_word; 292 | if (canonical_search_token->empty()) return; 293 | 294 | // Get rid of leading quotes and dashes in the search term 295 | if ((*canonical_search_token)[0] == '"') 296 | *canonical_search_token = canonical_search_token->substr(1); 297 | while ((*canonical_search_token)[0] == '-') 298 | *canonical_search_token = canonical_search_token->substr(1); 299 | 300 | options->flag_name_substring_search = false; 301 | options->flag_location_substring_search = false; 302 | options->flag_description_substring_search = false; 303 | options->return_all_matching_flags = false; 304 | options->force_no_update = false; 305 | 306 | // Look for all search options we can deduce now. Do this by walking 307 | // backwards through the term, looking for up to three '?' and up to 308 | // one '+' as suffixed characters. Consume them if found, and remove 309 | // them from the canonical search token. 310 | int found_question_marks = 0; 311 | int found_plusses = 0; 312 | while (true) { 313 | if (found_question_marks < 3 && 314 | RemoveTrailingChar(canonical_search_token, '?')) { 315 | ++found_question_marks; 316 | continue; 317 | } 318 | if (found_plusses < 1 && 319 | RemoveTrailingChar(canonical_search_token, '+')) { 320 | ++found_plusses; 321 | continue; 322 | } 323 | break; 324 | } 325 | 326 | switch (found_question_marks) { // all fallthroughs 327 | case 3: options->flag_description_substring_search = true; 328 | case 2: options->flag_location_substring_search = true; 329 | case 1: options->flag_name_substring_search = true; 330 | }; 331 | 332 | options->return_all_matching_flags = (found_plusses > 0); 333 | } 334 | 335 | // Returns true if a char was removed 336 | static bool RemoveTrailingChar(string *str, char c) { 337 | if (str->empty()) return false; 338 | if ((*str)[str->size() - 1] == c) { 339 | *str = str->substr(0, str->size() - 1); 340 | return true; 341 | } 342 | return false; 343 | } 344 | 345 | 346 | // 2) Find all matches (and helper methods) 347 | static void FindMatchingFlags( 348 | const vector &all_flags, 349 | const CompletionOptions &options, 350 | const string &match_token, 351 | set *all_matches, 352 | string *longest_common_prefix) { 353 | all_matches->clear(); 354 | bool first_match = true; 355 | for (vector::const_iterator it = all_flags.begin(); 356 | it != all_flags.end(); 357 | ++it) { 358 | if (DoesSingleFlagMatch(*it, options, match_token)) { 359 | all_matches->insert(&*it); 360 | if (first_match) { 361 | first_match = false; 362 | *longest_common_prefix = it->name; 363 | } else { 364 | if (longest_common_prefix->empty() || it->name.empty()) { 365 | longest_common_prefix->clear(); 366 | continue; 367 | } 368 | string::size_type pos = 0; 369 | while (pos < longest_common_prefix->size() && 370 | pos < it->name.size() && 371 | (*longest_common_prefix)[pos] == it->name[pos]) 372 | ++pos; 373 | longest_common_prefix->erase(pos); 374 | } 375 | } 376 | } 377 | } 378 | 379 | // Given the set of all flags, the parsed match options, and the 380 | // canonical search token, produce the set of all candidate matching 381 | // flags for subsequent analysis or filtering. 382 | static bool DoesSingleFlagMatch( 383 | const CommandLineFlagInfo &flag, 384 | const CompletionOptions &options, 385 | const string &match_token) { 386 | // Is there a prefix match? 387 | string::size_type pos = flag.name.find(match_token); 388 | if (pos == 0) return true; 389 | 390 | // Is there a substring match if we want it? 391 | if (options.flag_name_substring_search && 392 | pos != string::npos) 393 | return true; 394 | 395 | // Is there a location match if we want it? 396 | if (options.flag_location_substring_search && 397 | flag.filename.find(match_token) != string::npos) 398 | return true; 399 | 400 | // TODO(daven): All searches should probably be case-insensitive 401 | // (especially this one...) 402 | if (options.flag_description_substring_search && 403 | flag.description.find(match_token) != string::npos) 404 | return true; 405 | 406 | return false; 407 | } 408 | 409 | // 3) Categorize matches (and helper method) 410 | 411 | // Given a set of matching flags, categorize them by 412 | // likely relevence to this specific binary 413 | static void CategorizeAllMatchingFlags( 414 | const set &all_matches, 415 | const string &search_token, 416 | const string &module, // empty if we couldn't find any 417 | const string &package_dir, // empty if we couldn't find any 418 | NotableFlags *notable_flags) { 419 | notable_flags->perfect_match_flag.clear(); 420 | notable_flags->module_flags.clear(); 421 | notable_flags->package_flags.clear(); 422 | notable_flags->most_common_flags.clear(); 423 | notable_flags->subpackage_flags.clear(); 424 | 425 | for (set::const_iterator it = 426 | all_matches.begin(); 427 | it != all_matches.end(); 428 | ++it) { 429 | //VLOG(2) << "Examining match '" << (*it)->name << "'"; 430 | //VLOG(7) << " filename: '" << (*it)->filename << "'"; 431 | string::size_type pos = string::npos; 432 | if (!package_dir.empty()) 433 | pos = (*it)->filename.find(package_dir); 434 | string::size_type slash = string::npos; 435 | if (pos != string::npos) // candidate for package or subpackage match 436 | slash = (*it)->filename.find( 437 | PATH_SEPARATOR, 438 | pos + package_dir.size() + 1); 439 | 440 | if ((*it)->name == search_token) { 441 | // Exact match on some flag's name 442 | notable_flags->perfect_match_flag.insert(*it); 443 | //VLOG(3) << "Result: perfect match"; 444 | } else if (!module.empty() && (*it)->filename == module) { 445 | // Exact match on module filename 446 | notable_flags->module_flags.insert(*it); 447 | //VLOG(3) << "Result: module match"; 448 | } else if (!package_dir.empty() && 449 | pos != string::npos && slash == string::npos) { 450 | // In the package, since there was no slash after the package portion 451 | notable_flags->package_flags.insert(*it); 452 | //VLOG(3) << "Result: package match"; 453 | } else if (false) { 454 | // In the list of the XXX most commonly supplied flags overall 455 | // TODO(daven): Compile this list. 456 | //VLOG(3) << "Result: most-common match"; 457 | } else if (!package_dir.empty() && 458 | pos != string::npos && slash != string::npos) { 459 | // In a subdirectory of the package 460 | notable_flags->subpackage_flags.insert(*it); 461 | //VLOG(3) << "Result: subpackage match"; 462 | } 463 | 464 | //VLOG(3) << "Result: not special match"; 465 | } 466 | } 467 | 468 | static void PushNameWithSuffix(vector* suffixes, const char* suffix) { 469 | string s("/"); 470 | s += ProgramInvocationShortName(); 471 | s += suffix; 472 | suffixes->push_back(s); 473 | } 474 | 475 | static void TryFindModuleAndPackageDir( 476 | const vector all_flags, 477 | string *module, 478 | string *package_dir) { 479 | module->clear(); 480 | package_dir->clear(); 481 | 482 | vector suffixes; 483 | // TODO(daven): There's some inherant ambiguity here - multiple directories 484 | // could share the same trailing folder and file structure (and even worse, 485 | // same file names), causing us to be unsure as to which of the two is the 486 | // actual package for this binary. In this case, we'll arbitrarily choose. 487 | PushNameWithSuffix(&suffixes, "."); 488 | PushNameWithSuffix(&suffixes, "-main."); 489 | PushNameWithSuffix(&suffixes, "_main."); 490 | // These four are new but probably merited? 491 | PushNameWithSuffix(&suffixes, "-test."); 492 | PushNameWithSuffix(&suffixes, "_test."); 493 | PushNameWithSuffix(&suffixes, "-unittest."); 494 | PushNameWithSuffix(&suffixes, "_unittest."); 495 | 496 | for (vector::const_iterator it = all_flags.begin(); 497 | it != all_flags.end(); 498 | ++it) { 499 | for (vector::const_iterator suffix = suffixes.begin(); 500 | suffix != suffixes.end(); 501 | ++suffix) { 502 | // TODO(daven): Make sure the match is near the end of the string 503 | if (it->filename.find(*suffix) != string::npos) { 504 | *module = it->filename; 505 | string::size_type sep = it->filename.rfind(PATH_SEPARATOR); 506 | *package_dir = it->filename.substr(0, (sep == string::npos) ? 0 : sep); 507 | return; 508 | } 509 | } 510 | } 511 | } 512 | 513 | // Can't specialize template type on a locally defined type. Silly C++... 514 | struct DisplayInfoGroup { 515 | const char* header; 516 | const char* footer; 517 | set *group; 518 | 519 | int SizeInLines() const { 520 | int size_in_lines = static_cast(group->size()) + 1; 521 | if (strlen(header) > 0) { 522 | size_in_lines++; 523 | } 524 | if (strlen(footer) > 0) { 525 | size_in_lines++; 526 | } 527 | return size_in_lines; 528 | } 529 | }; 530 | 531 | // 4) Finalize and trim output flag set 532 | static void FinalizeCompletionOutput( 533 | const set &matching_flags, 534 | CompletionOptions *options, 535 | NotableFlags *notable_flags, 536 | vector *completions) { 537 | 538 | // We want to output lines in groups. Each group needs to be indented 539 | // the same to keep its lines together. Unless otherwise required, 540 | // only 99 lines should be output to prevent bash from harassing the 541 | // user. 542 | 543 | // First, figure out which output groups we'll actually use. For each 544 | // nonempty group, there will be ~3 lines of header & footer, plus all 545 | // output lines themselves. 546 | int max_desired_lines = // "999999 flags should be enough for anyone. -dave" 547 | (options->return_all_matching_flags ? 999999 : 98); 548 | int lines_so_far = 0; 549 | 550 | vector output_groups; 551 | bool perfect_match_found = false; 552 | if (lines_so_far < max_desired_lines && 553 | !notable_flags->perfect_match_flag.empty()) { 554 | perfect_match_found = true; 555 | DisplayInfoGroup group = 556 | { "", 557 | "==========", 558 | ¬able_flags->perfect_match_flag }; 559 | lines_so_far += group.SizeInLines(); 560 | output_groups.push_back(group); 561 | } 562 | if (lines_so_far < max_desired_lines && 563 | !notable_flags->module_flags.empty()) { 564 | DisplayInfoGroup group = { 565 | "-* Matching module flags *-", 566 | "===========================", 567 | ¬able_flags->module_flags }; 568 | lines_so_far += group.SizeInLines(); 569 | output_groups.push_back(group); 570 | } 571 | if (lines_so_far < max_desired_lines && 572 | !notable_flags->package_flags.empty()) { 573 | DisplayInfoGroup group = { 574 | "-* Matching package flags *-", 575 | "============================", 576 | ¬able_flags->package_flags }; 577 | lines_so_far += group.SizeInLines(); 578 | output_groups.push_back(group); 579 | } 580 | if (lines_so_far < max_desired_lines && 581 | !notable_flags->most_common_flags.empty()) { 582 | DisplayInfoGroup group = { 583 | "-* Commonly used flags *-", 584 | "=========================", 585 | ¬able_flags->most_common_flags }; 586 | lines_so_far += group.SizeInLines(); 587 | output_groups.push_back(group); 588 | } 589 | if (lines_so_far < max_desired_lines && 590 | !notable_flags->subpackage_flags.empty()) { 591 | DisplayInfoGroup group = { 592 | "-* Matching sub-package flags *-", 593 | "================================", 594 | ¬able_flags->subpackage_flags }; 595 | lines_so_far += group.SizeInLines(); 596 | output_groups.push_back(group); 597 | } 598 | 599 | set obscure_flags; // flags not notable 600 | if (lines_so_far < max_desired_lines) { 601 | RetrieveUnusedFlags(matching_flags, *notable_flags, &obscure_flags); 602 | if (!obscure_flags.empty()) { 603 | DisplayInfoGroup group = { 604 | "-* Other flags *-", 605 | "", 606 | &obscure_flags }; 607 | lines_so_far += group.SizeInLines(); 608 | output_groups.push_back(group); 609 | } 610 | } 611 | 612 | // Second, go through each of the chosen output groups and output 613 | // as many of those flags as we can, while remaining below our limit 614 | int remaining_lines = max_desired_lines; 615 | size_t completions_output = 0; 616 | int indent = static_cast(output_groups.size()) - 1; 617 | for (vector::const_iterator it = 618 | output_groups.begin(); 619 | it != output_groups.end(); 620 | ++it, --indent) { 621 | OutputSingleGroupWithLimit( 622 | *it->group, // group 623 | string(indent, ' '), // line indentation 624 | string(it->header), // header 625 | string(it->footer), // footer 626 | perfect_match_found, // long format 627 | &remaining_lines, // line limit - reduces this by number printed 628 | &completions_output, // completions (not lines) added 629 | completions); // produced completions 630 | perfect_match_found = false; 631 | } 632 | 633 | if (completions_output != matching_flags.size()) { 634 | options->force_no_update = false; 635 | completions->push_back("~ (Remaining flags hidden) ~"); 636 | } else { 637 | options->force_no_update = true; 638 | } 639 | } 640 | 641 | static void RetrieveUnusedFlags( 642 | const set &matching_flags, 643 | const NotableFlags ¬able_flags, 644 | set *unused_flags) { 645 | // Remove from 'matching_flags' set all members of the sets of 646 | // flags we've already printed (specifically, those in notable_flags) 647 | for (set::const_iterator it = 648 | matching_flags.begin(); 649 | it != matching_flags.end(); 650 | ++it) { 651 | if (notable_flags.perfect_match_flag.count(*it) || 652 | notable_flags.module_flags.count(*it) || 653 | notable_flags.package_flags.count(*it) || 654 | notable_flags.most_common_flags.count(*it) || 655 | notable_flags.subpackage_flags.count(*it)) 656 | continue; 657 | unused_flags->insert(*it); 658 | } 659 | } 660 | 661 | // 5) Output matches (and helper methods) 662 | 663 | static void OutputSingleGroupWithLimit( 664 | const set &group, 665 | const string &line_indentation, 666 | const string &header, 667 | const string &footer, 668 | bool long_output_format, 669 | int *remaining_line_limit, 670 | size_t *completion_elements_output, 671 | vector *completions) { 672 | if (group.empty()) return; 673 | if (!header.empty()) { 674 | if (*remaining_line_limit < 2) return; 675 | *remaining_line_limit -= 2; 676 | completions->push_back(line_indentation + header); 677 | completions->push_back(line_indentation + string(header.size(), '-')); 678 | } 679 | for (set::const_iterator it = group.begin(); 680 | it != group.end() && *remaining_line_limit > 0; 681 | ++it) { 682 | --*remaining_line_limit; 683 | ++*completion_elements_output; 684 | completions->push_back( 685 | (long_output_format 686 | ? GetLongFlagLine(line_indentation, **it) 687 | : GetShortFlagLine(line_indentation, **it))); 688 | } 689 | if (!footer.empty()) { 690 | if (*remaining_line_limit < 1) return; 691 | --*remaining_line_limit; 692 | completions->push_back(line_indentation + footer); 693 | } 694 | } 695 | 696 | static string GetShortFlagLine( 697 | const string &line_indentation, 698 | const CommandLineFlagInfo &info) { 699 | string prefix = 700 | line_indentation + "--" + info.name + " [" + 701 | (info.type == "string" ? 702 | ("'" + info.default_value + "'") : 703 | info.default_value) 704 | + "] "; 705 | int remainder = 706 | FLAGS_tab_completion_columns - static_cast(prefix.size()); 707 | string suffix; 708 | if (remainder > 0) 709 | suffix = 710 | (static_cast(info.description.size()) > remainder ? 711 | (info.description.substr(0, remainder - 3) + "...").c_str() : 712 | info.description.c_str()); 713 | return prefix + suffix; 714 | } 715 | 716 | static string GetLongFlagLine( 717 | const string &line_indentation, 718 | const CommandLineFlagInfo &info) { 719 | 720 | string output = DescribeOneFlag(info); 721 | 722 | // Replace '-' with '--', and remove trailing newline before appending 723 | // the module definition location. 724 | string old_flagname = "-" + info.name; 725 | output.replace( 726 | output.find(old_flagname), 727 | old_flagname.size(), 728 | "-" + old_flagname); 729 | // Stick a newline and indentation in front of the type and default 730 | // portions of DescribeOneFlag()s description 731 | static const char kNewlineWithIndent[] = "\n "; 732 | output.replace(output.find(" type:"), 1, string(kNewlineWithIndent)); 733 | output.replace(output.find(" default:"), 1, string(kNewlineWithIndent)); 734 | output = line_indentation + " Details for '--" + info.name + "':\n" + 735 | output + " defined: " + info.filename; 736 | 737 | // Eliminate any doubled newlines that crept in. Specifically, if 738 | // DescribeOneFlag() decided to break the line just before "type" 739 | // or "default", we don't want to introduce an extra blank line 740 | static const string line_of_spaces(FLAGS_tab_completion_columns, ' '); 741 | static const char kDoubledNewlines[] = "\n \n"; 742 | for (string::size_type newlines = output.find(kDoubledNewlines); 743 | newlines != string::npos; 744 | newlines = output.find(kDoubledNewlines)) 745 | // Replace each 'doubled newline' with a single newline 746 | output.replace(newlines, sizeof(kDoubledNewlines) - 1, string("\n")); 747 | 748 | for (string::size_type newline = output.find('\n'); 749 | newline != string::npos; 750 | newline = output.find('\n')) { 751 | int newline_pos = static_cast(newline) % FLAGS_tab_completion_columns; 752 | int missing_spaces = FLAGS_tab_completion_columns - newline_pos; 753 | output.replace(newline, 1, line_of_spaces, 1, missing_spaces); 754 | } 755 | return output; 756 | } 757 | } // anonymous 758 | 759 | void HandleCommandLineCompletions(void) { 760 | if (FLAGS_tab_completion_word.empty()) return; 761 | PrintFlagCompletionInfo(); 762 | exit(0); 763 | } 764 | 765 | _END_GOOGLE_NAMESPACE_ 766 | -------------------------------------------------------------------------------- /src/gflags/gflags.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // --- 31 | // Author: Ray Sidney 32 | // Revamped and reorganized by Craig Silverstein 33 | // 34 | // This is the file that should be included by any file which declares 35 | // or defines a command line flag or wants to parse command line flags 36 | // or print a program usage message (which will include information about 37 | // flags). Executive summary, in the form of an example foo.cc file: 38 | // 39 | // #include "foo.h" // foo.h has a line "DECLARE_int32(start);" 40 | // #include "validators.h" // hypothetical file defining ValidateIsFile() 41 | // 42 | // DEFINE_int32(end, 1000, "The last record to read"); 43 | // 44 | // DEFINE_string(filename, "my_file.txt", "The file to read"); 45 | // // Crash if the specified file does not exist. 46 | // static bool dummy = RegisterFlagValidator(&FLAGS_filename, 47 | // &ValidateIsFile); 48 | // 49 | // DECLARE_bool(verbose); // some other file has a DEFINE_bool(verbose, ...) 50 | // 51 | // void MyFunc() { 52 | // if (FLAGS_verbose) printf("Records %d-%d\n", FLAGS_start, FLAGS_end); 53 | // } 54 | // 55 | // Then, at the command-line: 56 | // ./foo --noverbose --start=5 --end=100 57 | // 58 | // For more details, see 59 | // doc/gflags.html 60 | // 61 | // --- A note about thread-safety: 62 | // 63 | // We describe many functions in this routine as being thread-hostile, 64 | // thread-compatible, or thread-safe. Here are the meanings we use: 65 | // 66 | // thread-safe: it is safe for multiple threads to call this routine 67 | // (or, when referring to a class, methods of this class) 68 | // concurrently. 69 | // thread-hostile: it is not safe for multiple threads to call this 70 | // routine (or methods of this class) concurrently. In gflags, 71 | // most thread-hostile routines are intended to be called early in, 72 | // or even before, main() -- that is, before threads are spawned. 73 | // thread-compatible: it is safe for multiple threads to read from 74 | // this variable (when applied to variables), or to call const 75 | // methods of this class (when applied to classes), as long as no 76 | // other thread is writing to the variable or calling non-const 77 | // methods of this class. 78 | 79 | #ifndef GOOGLE_GFLAGS_H_ 80 | #define GOOGLE_GFLAGS_H_ 81 | 82 | #include 83 | #include 84 | 85 | // We care a lot about number of bits things take up. Unfortunately, 86 | // systems define their bit-specific ints in a lot of different ways. 87 | // We use our own way, and have a typedef to get there. 88 | // Note: these commands below may look like "#if 1" or "#if 0", but 89 | // that's because they were constructed that way at ./configure time. 90 | // Look at gflags.h.in to see how they're calculated (based on your config). 91 | #if 1 92 | #include // the normal place uint16_t is defined 93 | #endif 94 | #if 1 95 | #include // the normal place u_int16_t is defined 96 | #endif 97 | #if 1 98 | #include // a third place for uint16_t or u_int16_t 99 | #endif 100 | 101 | namespace google { 102 | 103 | #if 1 // the C99 format 104 | typedef int32_t int32; 105 | typedef uint32_t uint32; 106 | typedef int64_t int64; 107 | typedef uint64_t uint64; 108 | #elif 1 // the BSD format 109 | typedef int32_t int32; 110 | typedef u_int32_t uint32; 111 | typedef int64_t int64; 112 | typedef u_int64_t uint64; 113 | #elif 0 // the windows (vc7) format 114 | typedef __int32 int32; 115 | typedef unsigned __int32 uint32; 116 | typedef __int64 int64; 117 | typedef unsigned __int64 uint64; 118 | #else 119 | #error Do not know how to define a 32-bit integer quantity on your system 120 | #endif 121 | 122 | // -------------------------------------------------------------------- 123 | // To actually define a flag in a file, use DEFINE_bool, 124 | // DEFINE_string, etc. at the bottom of this file. You may also find 125 | // it useful to register a validator with the flag. This ensures that 126 | // when the flag is parsed from the commandline, or is later set via 127 | // SetCommandLineOption, we call the validation function. It is _not_ 128 | // called when you assign the value to the flag directly using the = operator. 129 | // 130 | // The validation function should return true if the flag value is valid, and 131 | // false otherwise. If the function returns false for the new setting of the 132 | // flag, the flag will retain its current value. If it returns false for the 133 | // default value, ParseCommandLineFlags() will die. 134 | // 135 | // This function is safe to call at global construct time (as in the 136 | // example below). 137 | // 138 | // Example use: 139 | // static bool ValidatePort(const char* flagname, int32 value) { 140 | // if (value > 0 && value < 32768) // value is ok 141 | // return true; 142 | // printf("Invalid value for --%s: %d\n", flagname, (int)value); 143 | // return false; 144 | // } 145 | // DEFINE_int32(port, 0, "What port to listen on"); 146 | // static bool dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort); 147 | 148 | // Returns true if successfully registered, false if not (because the 149 | // first argument doesn't point to a command-line flag, or because a 150 | // validator is already registered for this flag). 151 | bool RegisterFlagValidator(const bool* flag, 152 | bool (*validate_fn)(const char*, bool)); 153 | bool RegisterFlagValidator(const int32* flag, 154 | bool (*validate_fn)(const char*, int32)); 155 | bool RegisterFlagValidator(const int64* flag, 156 | bool (*validate_fn)(const char*, int64)); 157 | bool RegisterFlagValidator(const uint64* flag, 158 | bool (*validate_fn)(const char*, uint64)); 159 | bool RegisterFlagValidator(const double* flag, 160 | bool (*validate_fn)(const char*, double)); 161 | bool RegisterFlagValidator(const std::string* flag, 162 | bool (*validate_fn)(const char*, const std::string&)); 163 | 164 | 165 | // -------------------------------------------------------------------- 166 | // These methods are the best way to get access to info about the 167 | // list of commandline flags. Note that these routines are pretty slow. 168 | // GetAllFlags: mostly-complete info about the list, sorted by file. 169 | // ShowUsageWithFlags: pretty-prints the list to stdout (what --help does) 170 | // ShowUsageWithFlagsRestrict: limit to filenames with restrict as a substr 171 | // 172 | // In addition to accessing flags, you can also access argv[0] (the program 173 | // name) and argv (the entire commandline), which we sock away a copy of. 174 | // These variables are static, so you should only set them once. 175 | 176 | struct CommandLineFlagInfo { 177 | std::string name; // the name of the flag 178 | std::string type; // the type of the flag: int32, etc 179 | std::string description; // the "help text" associated with the flag 180 | std::string current_value; // the current value, as a string 181 | std::string default_value; // the default value, as a string 182 | std::string filename; // 'cleaned' version of filename holding the flag 183 | bool has_validator_fn; // true if RegisterFlagValidator called on flag 184 | bool is_default; // true if the flag has the default value and 185 | // has not been set explicitly from the cmdline 186 | // or via SetCommandLineOption 187 | }; 188 | 189 | // Using this inside of a validator is a recipe for a deadlock. 190 | // TODO(wojtekm) Fix locking when validators are running, to make it safe to 191 | // call validators during ParseAllFlags. 192 | // Also make sure then to uncomment the corresponding unit test in 193 | // commandlineflags_unittest.sh 194 | extern void GetAllFlags(std::vector* OUTPUT); 195 | // These two are actually defined in commandlineflags_reporting.cc. 196 | extern void ShowUsageWithFlags(const char *argv0); // what --help does 197 | extern void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict); 198 | 199 | // Create a descriptive string for a flag. 200 | // Goes to some trouble to make pretty line breaks. 201 | extern std::string DescribeOneFlag(const CommandLineFlagInfo& flag); 202 | 203 | // Thread-hostile; meant to be called before any threads are spawned. 204 | extern void SetArgv(int argc, const char** argv); 205 | // The following functions are thread-safe as long as SetArgv() is 206 | // only called before any threads start. 207 | extern const std::vector& GetArgvs(); // all of argv as a vector 208 | extern const char* GetArgv(); // all of argv as a string 209 | extern const char* GetArgv0(); // only argv0 210 | extern uint32 GetArgvSum(); // simple checksum of argv 211 | extern const char* ProgramInvocationName(); // argv0, or "UNKNOWN" if not set 212 | extern const char* ProgramInvocationShortName(); // basename(argv0) 213 | // ProgramUsage() is thread-safe as long as SetUsageMessage() is only 214 | // called before any threads start. 215 | extern const char* ProgramUsage(); // string set by SetUsageMessage() 216 | 217 | 218 | // -------------------------------------------------------------------- 219 | // Normally you access commandline flags by just saying "if (FLAGS_foo)" 220 | // or whatever, and set them by calling "FLAGS_foo = bar" (or, more 221 | // commonly, via the DEFINE_foo macro). But if you need a bit more 222 | // control, we have programmatic ways to get/set the flags as well. 223 | // These programmatic ways to access flags are thread-safe, but direct 224 | // access is only thread-compatible. 225 | 226 | // Return true iff the flagname was found. 227 | // OUTPUT is set to the flag's value, or unchanged if we return false. 228 | extern bool GetCommandLineOption(const char* name, std::string* OUTPUT); 229 | 230 | // Return true iff the flagname was found. OUTPUT is set to the flag's 231 | // CommandLineFlagInfo or unchanged if we return false. 232 | extern bool GetCommandLineFlagInfo(const char* name, 233 | CommandLineFlagInfo* OUTPUT); 234 | 235 | // Return the CommandLineFlagInfo of the flagname. exit() if name not found. 236 | // Example usage, to check if a flag's value is currently the default value: 237 | // if (GetCommandLineFlagInfoOrDie("foo").is_default) ... 238 | extern CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name); 239 | 240 | enum FlagSettingMode { 241 | // update the flag's value (can call this multiple times). 242 | SET_FLAGS_VALUE, 243 | // update the flag's value, but *only if* it has not yet been updated 244 | // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef". 245 | SET_FLAG_IF_DEFAULT, 246 | // set the flag's default value to this. If the flag has not yet updated 247 | // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef") 248 | // change the flag's current value to the new default value as well. 249 | SET_FLAGS_DEFAULT 250 | }; 251 | 252 | // Set a particular flag ("command line option"). Returns a string 253 | // describing the new value that the option has been set to. The 254 | // return value API is not well-specified, so basically just depend on 255 | // it to be empty if the setting failed for some reason -- the name is 256 | // not a valid flag name, or the value is not a valid value -- and 257 | // non-empty else. 258 | 259 | // SetCommandLineOption uses set_mode == SET_FLAGS_VALUE (the common case) 260 | extern std::string SetCommandLineOption(const char* name, const char* value); 261 | extern std::string SetCommandLineOptionWithMode(const char* name, const char* value, 262 | FlagSettingMode set_mode); 263 | 264 | 265 | // -------------------------------------------------------------------- 266 | // Saves the states (value, default value, whether the user has set 267 | // the flag, registered validators, etc) of all flags, and restores 268 | // them when the FlagSaver is destroyed. This is very useful in 269 | // tests, say, when you want to let your tests change the flags, but 270 | // make sure that they get reverted to the original states when your 271 | // test is complete. 272 | // 273 | // Example usage: 274 | // void TestFoo() { 275 | // FlagSaver s1; 276 | // FLAG_foo = false; 277 | // FLAG_bar = "some value"; 278 | // 279 | // // test happens here. You can return at any time 280 | // // without worrying about restoring the FLAG values. 281 | // } 282 | // 283 | // Note: This class is marked with __attribute__((unused)) because all the 284 | // work is done in the constructor and destructor, so in the standard 285 | // usage example above, the compiler would complain that it's an 286 | // unused variable. 287 | // 288 | // This class is thread-safe. 289 | 290 | class FlagSaver { 291 | public: 292 | FlagSaver(); 293 | ~FlagSaver(); 294 | 295 | private: 296 | class FlagSaverImpl* impl_; // we use pimpl here to keep API steady 297 | 298 | FlagSaver(const FlagSaver&); // no copying! 299 | void operator=(const FlagSaver&); 300 | } 301 | #ifndef _MSC_VER 302 | __attribute__ ((unused)) 303 | #endif 304 | ; 305 | 306 | // -------------------------------------------------------------------- 307 | // Some deprecated or hopefully-soon-to-be-deprecated functions. 308 | 309 | // This is often used for logging. TODO(csilvers): figure out a better way 310 | extern std::string CommandlineFlagsIntoString(); 311 | // Usually where this is used, a FlagSaver should be used instead. 312 | extern bool ReadFlagsFromString(const std::string& flagfilecontents, 313 | const char* prog_name, 314 | bool errors_are_fatal); // uses SET_FLAGS_VALUE 315 | 316 | // These let you manually implement --flagfile functionality. 317 | // DEPRECATED. 318 | extern bool AppendFlagsIntoFile(const std::string& filename, const char* prog_name); 319 | extern bool SaveCommandFlags(); // actually defined in google.cc ! 320 | extern bool ReadFromFlagsFile(const std::string& filename, const char* prog_name, 321 | bool errors_are_fatal); // uses SET_FLAGS_VALUE 322 | 323 | 324 | // -------------------------------------------------------------------- 325 | // Useful routines for initializing flags from the environment. 326 | // In each case, if 'varname' does not exist in the environment 327 | // return defval. If 'varname' does exist but is not valid 328 | // (e.g., not a number for an int32 flag), abort with an error. 329 | // Otherwise, return the value. NOTE: for booleans, for true use 330 | // 't' or 'T' or 'true' or '1', for false 'f' or 'F' or 'false' or '0'. 331 | 332 | extern bool BoolFromEnv(const char *varname, bool defval); 333 | extern int32 Int32FromEnv(const char *varname, int32 defval); 334 | extern int64 Int64FromEnv(const char *varname, int64 defval); 335 | extern uint64 Uint64FromEnv(const char *varname, uint64 defval); 336 | extern double DoubleFromEnv(const char *varname, double defval); 337 | extern const char *StringFromEnv(const char *varname, const char *defval); 338 | 339 | 340 | // -------------------------------------------------------------------- 341 | // The next two functions parse commandlineflags from main(): 342 | 343 | // Set the "usage" message for this program. For example: 344 | // string usage("This program does nothing. Sample usage:\n"); 345 | // usage += argv[0] + " "; 346 | // SetUsageMessage(usage); 347 | // Do not include commandline flags in the usage: we do that for you! 348 | // Thread-hostile; meant to be called before any threads are spawned. 349 | extern void SetUsageMessage(const std::string& usage); 350 | 351 | // Looks for flags in argv and parses them. Rearranges argv to put 352 | // flags first, or removes them entirely if remove_flags is true. 353 | // If a flag is defined more than once in the command line or flag 354 | // file, the last definition is used. Returns the index (into argv) 355 | // of the first non-flag argument. 356 | // See top-of-file for more details on this function. 357 | #ifndef SWIG // In swig, use ParseCommandLineFlagsScript() instead. 358 | extern uint32 ParseCommandLineFlags(int *argc, char*** argv, 359 | bool remove_flags); 360 | #endif 361 | 362 | 363 | // Calls to ParseCommandLineNonHelpFlags and then to 364 | // HandleCommandLineHelpFlags can be used instead of a call to 365 | // ParseCommandLineFlags during initialization, in order to allow for 366 | // changing default values for some FLAGS (via 367 | // e.g. SetCommandLineOptionWithMode calls) between the time of 368 | // command line parsing and the time of dumping help information for 369 | // the flags as a result of command line parsing. If a flag is 370 | // defined more than once in the command line or flag file, the last 371 | // definition is used. Returns the index (into argv) of the first 372 | // non-flag argument. (If remove_flags is true, will always return 1.) 373 | extern uint32 ParseCommandLineNonHelpFlags(int *argc, char*** argv, 374 | bool remove_flags); 375 | // This is actually defined in commandlineflags_reporting.cc. 376 | // This function is misnamed (it also handles --version, etc.), but 377 | // it's too late to change that now. :-( 378 | extern void HandleCommandLineHelpFlags(); // in commandlineflags_reporting.cc 379 | 380 | // Allow command line reparsing. Disables the error normally 381 | // generated when an unknown flag is found, since it may be found in a 382 | // later parse. Thread-hostile; meant to be called before any threads 383 | // are spawned. 384 | extern void AllowCommandLineReparsing(); 385 | 386 | // Reparse the flags that have not yet been recognized. Only flags 387 | // registered since the last parse will be recognized. Any flag value 388 | // must be provided as part of the argument using "=", not as a 389 | // separate command line argument that follows the flag argument. 390 | // Intended for handling flags from dynamically loaded libraries, 391 | // since their flags are not registered until they are loaded. 392 | // Returns the index (into the original argv) of the first non-flag 393 | // argument. (If remove_flags is true, will always return 1.) 394 | extern uint32 ReparseCommandLineNonHelpFlags(); 395 | 396 | // Clean up memory allocated by flags. This is only needed to reduce 397 | // the quantity of "potentially leaked" reports emitted by memory 398 | // debugging tools such as valgrind. It is not required for normal 399 | // operation, or for the perftools heap-checker. It must only be called 400 | // when the process is about to exit, and all threads that might 401 | // access flags are quiescent. Referencing flags after this is called 402 | // will have unexpected consequences. This is not safe to run when 403 | // multiple threads might be running: the function is thread-hostile. 404 | extern void ShutDownCommandLineFlags(); 405 | 406 | 407 | // -------------------------------------------------------------------- 408 | // Now come the command line flag declaration/definition macros that 409 | // will actually be used. They're kind of hairy. A major reason 410 | // for this is initialization: we want people to be able to access 411 | // variables in global constructors and have that not crash, even if 412 | // their global constructor runs before the global constructor here. 413 | // (Obviously, we can't guarantee the flags will have the correct 414 | // default value in that case, but at least accessing them is safe.) 415 | // The only way to do that is have flags point to a static buffer. 416 | // So we make one, using a union to ensure proper alignment, and 417 | // then use placement-new to actually set up the flag with the 418 | // correct default value. In the same vein, we have to worry about 419 | // flag access in global destructors, so FlagRegisterer has to be 420 | // careful never to destroy the flag-values it constructs. 421 | // 422 | // Note that when we define a flag variable FLAGS_, we also 423 | // preemptively define a junk variable, FLAGS_no. This is to 424 | // cause a link-time error if someone tries to define 2 flags with 425 | // names like "logging" and "nologging". We do this because a bool 426 | // flag FLAG can be set from the command line to true with a "-FLAG" 427 | // argument, and to false with a "-noFLAG" argument, and so this can 428 | // potentially avert confusion. 429 | // 430 | // We also put flags into their own namespace. It is purposefully 431 | // named in an opaque way that people should have trouble typing 432 | // directly. The idea is that DEFINE puts the flag in the weird 433 | // namespace, and DECLARE imports the flag from there into the current 434 | // namespace. The net result is to force people to use DECLARE to get 435 | // access to a flag, rather than saying "extern bool FLAGS_whatever;" 436 | // or some such instead. We want this so we can put extra 437 | // functionality (like sanity-checking) in DECLARE if we want, and 438 | // make sure it is picked up everywhere. 439 | // 440 | // We also put the type of the variable in the namespace, so that 441 | // people can't DECLARE_int32 something that they DEFINE_bool'd 442 | // elsewhere. 443 | 444 | class FlagRegisterer { 445 | public: 446 | FlagRegisterer(const char* name, const char* type, 447 | const char* help, const char* filename, 448 | void* current_storage, void* defvalue_storage); 449 | }; 450 | 451 | extern bool FlagsTypeWarn(const char *name); 452 | 453 | // If your application #defines STRIP_FLAG_HELP to a non-zero value 454 | // before #including this file, we remove the help message from the 455 | // binary file. This can reduce the size of the resulting binary 456 | // somewhat, and may also be useful for security reasons. 457 | 458 | extern const char kStrippedFlagHelp[]; 459 | 460 | } 461 | 462 | #ifndef SWIG // In swig, ignore the main flag declarations 463 | 464 | #if defined(STRIP_FLAG_HELP) && STRIP_FLAG_HELP > 0 465 | // Need this construct to avoid the 'defined but not used' warning. 466 | #define MAYBE_STRIPPED_HELP(txt) (false ? (txt) : ::google::kStrippedFlagHelp) 467 | #else 468 | #define MAYBE_STRIPPED_HELP(txt) txt 469 | #endif 470 | 471 | // Each command-line flag has two variables associated with it: one 472 | // with the current value, and one with the default value. However, 473 | // we have a third variable, which is where value is assigned; it's a 474 | // constant. This guarantees that FLAG_##value is initialized at 475 | // static initialization time (e.g. before program-start) rather than 476 | // than global construction time (which is after program-start but 477 | // before main), at least when 'value' is a compile-time constant. We 478 | // use a small trick for the "default value" variable, and call it 479 | // FLAGS_no. This serves the second purpose of assuring a 480 | // compile error if someone tries to define a flag named no 481 | // which is illegal (--foo and --nofoo both affect the "foo" flag). 482 | #define DEFINE_VARIABLE(type, shorttype, name, value, help) \ 483 | namespace fL##shorttype { \ 484 | static const type FLAGS_nono##name = value; \ 485 | type FLAGS_##name = FLAGS_nono##name; \ 486 | type FLAGS_no##name = FLAGS_nono##name; \ 487 | static ::google::FlagRegisterer o_##name( \ 488 | #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__, \ 489 | &FLAGS_##name, &FLAGS_no##name); \ 490 | } \ 491 | using fL##shorttype::FLAGS_##name 492 | 493 | #define DECLARE_VARIABLE(type, shorttype, name) \ 494 | namespace fL##shorttype { \ 495 | extern type FLAGS_##name; \ 496 | } \ 497 | using fL##shorttype::FLAGS_##name 498 | 499 | // For DEFINE_bool, we want to do the extra check that the passed-in 500 | // value is actually a bool, and not a string or something that can be 501 | // coerced to a bool. These declarations (no definition needed!) will 502 | // help us do that, and never evaluate From, which is important. 503 | // We'll use 'sizeof(IsBool(val))' to distinguish. This code requires 504 | // that the compiler have different sizes for bool & double. Since 505 | // this is not guaranteed by the standard, we check it with a 506 | // compile-time assert (msg[-1] will give a compile-time error). 507 | namespace fLB { 508 | struct CompileAssert {}; 509 | typedef CompileAssert expected_sizeof_double_neq_sizeof_bool[ 510 | (sizeof(double) != sizeof(bool)) ? 1 : -1]; 511 | template double IsBoolFlag(const From& from); 512 | bool IsBoolFlag(bool from); 513 | } // namespace fLB 514 | 515 | #define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name) 516 | #define DEFINE_bool(name, val, txt) \ 517 | namespace fLB { \ 518 | typedef ::fLB::CompileAssert FLAG_##name##_value_is_not_a_bool[ \ 519 | (sizeof(::fLB::IsBoolFlag(val)) != sizeof(double)) ? 1 : -1]; \ 520 | } \ 521 | DEFINE_VARIABLE(bool, B, name, val, txt) 522 | 523 | #define DECLARE_int32(name) DECLARE_VARIABLE(::google::int32, I, name) 524 | #define DEFINE_int32(name,val,txt) DEFINE_VARIABLE(::google::int32, I, name, val, txt) 525 | 526 | #define DECLARE_int64(name) DECLARE_VARIABLE(::google::int64, I64, name) 527 | #define DEFINE_int64(name,val,txt) DEFINE_VARIABLE(::google::int64, I64, name, val, txt) 528 | 529 | #define DECLARE_uint64(name) DECLARE_VARIABLE(::google::uint64, U64, name) 530 | #define DEFINE_uint64(name,val,txt) DEFINE_VARIABLE(::google::uint64, U64, name, val, txt) 531 | 532 | #define DECLARE_double(name) DECLARE_VARIABLE(double, D, name) 533 | #define DEFINE_double(name, val, txt) DEFINE_VARIABLE(double, D, name, val, txt) 534 | 535 | // Strings are trickier, because they're not a POD, so we can't 536 | // construct them at static-initialization time (instead they get 537 | // constructed at global-constructor time, which is much later). To 538 | // try to avoid crashes in that case, we use a char buffer to store 539 | // the string, which we can static-initialize, and then placement-new 540 | // into it later. It's not perfect, but the best we can do. 541 | 542 | namespace fLS { 543 | // The meaning of "string" might be different between now and when the 544 | // macros below get invoked (e.g., if someone is experimenting with 545 | // other string implementations that get defined after this file is 546 | // included). Save the current meaning now and use it in the macros. 547 | typedef std::string clstring; 548 | 549 | inline clstring* dont_pass0toDEFINE_string(char *stringspot, 550 | const char *value) { 551 | return new(stringspot) clstring(value); 552 | } 553 | inline clstring* dont_pass0toDEFINE_string(char *stringspot, 554 | const clstring &value) { 555 | return new(stringspot) clstring(value); 556 | } 557 | inline clstring* dont_pass0toDEFINE_string(char *stringspot, 558 | int value); 559 | } // namespace fLS 560 | 561 | #define DECLARE_string(name) namespace fLS { extern ::fLS::clstring& FLAGS_##name; } \ 562 | using fLS::FLAGS_##name 563 | 564 | // We need to define a var named FLAGS_no##name so people don't define 565 | // --string and --nostring. And we need a temporary place to put val 566 | // so we don't have to evaluate it twice. Two great needs that go 567 | // great together! 568 | // The weird 'using' + 'extern' inside the fLS namespace is to work around 569 | // an unknown compiler bug/issue with the gcc 4.2.1 on SUSE 10. See 570 | // http://code.google.com/p/google-gflags/issues/detail?id=20 571 | #define DEFINE_string(name, val, txt) \ 572 | namespace fLS { \ 573 | using ::fLS::clstring; \ 574 | static union { void* align; char s[sizeof(clstring)]; } s_##name[2]; \ 575 | clstring* const FLAGS_no##name = ::fLS:: \ 576 | dont_pass0toDEFINE_string(s_##name[0].s, \ 577 | val); \ 578 | static ::google::FlagRegisterer o_##name( \ 579 | #name, "string", MAYBE_STRIPPED_HELP(txt), __FILE__, \ 580 | s_##name[0].s, new (s_##name[1].s) clstring(*FLAGS_no##name)); \ 581 | extern clstring& FLAGS_##name; \ 582 | using fLS::FLAGS_##name; \ 583 | clstring& FLAGS_##name = *FLAGS_no##name; \ 584 | } \ 585 | using fLS::FLAGS_##name 586 | 587 | #endif // SWIG 588 | 589 | #endif // GOOGLE_GFLAGS_H_ 590 | -------------------------------------------------------------------------------- /src/gflags/gflags.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // --- 31 | // Author: Ray Sidney 32 | // Revamped and reorganized by Craig Silverstein 33 | // 34 | // This file contains the implementation of all our command line flags 35 | // stuff. Here's how everything fits together 36 | // 37 | // * FlagRegistry owns CommandLineFlags owns FlagValue. 38 | // * FlagSaver holds a FlagRegistry (saves it at construct time, 39 | // restores it at destroy time). 40 | // * CommandLineFlagParser lives outside that hierarchy, but works on 41 | // CommandLineFlags (modifying the FlagValues). 42 | // * Free functions like SetCommandLineOption() work via one of the 43 | // above (such as CommandLineFlagParser). 44 | // 45 | // In more detail: 46 | // 47 | // -- The main classes that hold flag data: 48 | // 49 | // FlagValue holds the current value of a flag. It's 50 | // pseudo-templatized: every operation on a FlagValue is typed. It 51 | // also deals with storage-lifetime issues (so flag values don't go 52 | // away in a destructor), which is why we need a whole class to hold a 53 | // variable's value. 54 | // 55 | // CommandLineFlag is all the information about a single command-line 56 | // flag. It has a FlagValue for the flag's current value, but also 57 | // the flag's name, type, etc. 58 | // 59 | // FlagRegistry is a collection of CommandLineFlags. There's the 60 | // global registry, which is where flags defined via DEFINE_foo() 61 | // live. But it's possible to define your own flag, manually, in a 62 | // different registry you create. (In practice, multiple registries 63 | // are used only by FlagSaver). 64 | // 65 | // A given FlagValue is owned by exactly one CommandLineFlag. A given 66 | // CommandLineFlag is owned by exactly one FlagRegistry. FlagRegistry 67 | // has a lock; any operation that writes to a FlagValue or 68 | // CommandLineFlag owned by that registry must acquire the 69 | // FlagRegistry lock before doing so. 70 | // 71 | // --- Some other classes and free functions: 72 | // 73 | // CommandLineFlagInfo is a client-exposed version of CommandLineFlag. 74 | // Once it's instantiated, it has no dependencies or relationships 75 | // with any other part of this file. 76 | // 77 | // FlagRegisterer is the helper class used by the DEFINE_* macros to 78 | // allow work to be done at global initialization time. 79 | // 80 | // CommandLineFlagParser is the class that reads from the commandline 81 | // and instantiates flag values based on that. It needs to poke into 82 | // the innards of the FlagValue->CommandLineFlag->FlagRegistry class 83 | // hierarchy to do that. It's careful to acquire the FlagRegistry 84 | // lock before doing any writing or other non-const actions. 85 | // 86 | // GetCommandLineOption is just a hook into registry routines to 87 | // retrieve a flag based on its name. SetCommandLineOption, on the 88 | // other hand, hooks into CommandLineFlagParser. Other API functions 89 | // are, similarly, mostly hooks into the functionality described above. 90 | 91 | #include "config.hpp" 92 | // This comes first to ensure we define __STDC_FORMAT_MACROS in time. 93 | #ifdef HAVE_INTTYPES_H 94 | #ifndef __STDC_FORMAT_MACROS 95 | # define __STDC_FORMAT_MACROS 1 // gcc requires this to get PRId64, etc. 96 | #endif 97 | #include 98 | #endif // HAVE_INTTYPES_H 99 | #include // for snprintf 100 | #include 101 | #include 102 | #include 103 | #include // For va_list and related operations 104 | #include 105 | #include 106 | #ifdef HAVE_FNMATCH_H 107 | #include 108 | #endif // HAVE_FNMATCH_H 109 | #include 110 | #include 111 | #include 112 | #include // for pair<> 113 | #include 114 | #include "gflags.hpp" 115 | #include "mutex.hpp" 116 | 117 | #ifndef PATH_SEPARATOR 118 | #define PATH_SEPARATOR '/' 119 | #endif 120 | 121 | // Work properly if either strtoll or strtoq is on this system 122 | #ifdef HAVE_STRTOLL 123 | # define strtoint64 strtoll 124 | # define strtouint64 strtoull 125 | #elif HAVE_STRTOQ 126 | # define strtoint64 strtoq 127 | # define strtouint64 strtouq 128 | #else 129 | // Neither strtoll nor strtoq are defined. I hope strtol works! 130 | # define strtoint64 strtol 131 | # define strtouint64 strtoul 132 | #endif 133 | 134 | // If we have inttypes.h, it will have defined PRId32/etc for us. If 135 | // not, take our best guess. 136 | #ifndef PRId32 137 | # define PRId32 "d" 138 | #endif 139 | #ifndef PRId64 140 | # define PRId64 "lld" 141 | #endif 142 | #ifndef PRIu64 143 | # define PRIu64 "llu" 144 | #endif 145 | 146 | // Windows is missing random bits like strcasecmp, strtoll, strtoull, and 147 | // snprintf in the usual locations. Put them somewhere sensible. 148 | // 149 | // TODO(keir): Get the upstream Windows port and use that instead. 150 | #ifdef _MSC_VER 151 | # define snprintf _snprintf 152 | # undef strtoint64 153 | # define strtoint64 _strtoi64 154 | # undef strtouint64 155 | # define strtouint64 _strtoui64 156 | # define strcasecmp _stricmp 157 | #endif 158 | 159 | typedef signed char int8; 160 | typedef unsigned char uint8; 161 | 162 | // Special flags, type 1: the 'recursive' flags. They set another flag's val. 163 | DEFINE_string(flagfile, "", 164 | "load flags from file"); 165 | DEFINE_string(fromenv, "", 166 | "set flags from the environment" 167 | " [use 'export FLAGS_flag1=value']"); 168 | DEFINE_string(tryfromenv, "", 169 | "set flags from the environment if present"); 170 | 171 | // Special flags, type 2: the 'parsing' flags. They modify how we parse. 172 | DEFINE_string(undefok, "", 173 | "comma-separated list of flag names that it is okay to specify " 174 | "on the command line even if the program does not define a flag " 175 | "with that name. IMPORTANT: flags in this list that have " 176 | "arguments MUST use the flag=value format"); 177 | 178 | _START_GOOGLE_NAMESPACE_ 179 | 180 | using std::map; 181 | using std::pair; 182 | using std::sort; 183 | using std::string; 184 | using std::vector; 185 | 186 | // The help message indicating that the commandline flag has been 187 | // 'stripped'. It will not show up when doing "-help" and its 188 | // variants. The flag is stripped if STRIP_FLAG_HELP is set to 1 189 | // before including gflags/gflags.h. 190 | 191 | // This is used by this file, and also in commandlineflags_reporting.cc 192 | const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001"; 193 | 194 | // This is used by the unittest to test error-exit code 195 | void GFLAGS_DLL_DECL (*commandlineflags_exitfunc)(int) = &exit; // from stdlib.h 196 | 197 | namespace { 198 | 199 | // There are also 'reporting' flags, in commandlineflags_reporting.cc. 200 | 201 | static const char kError[] = "ERROR: "; 202 | 203 | // Indicates that undefined options are to be ignored. 204 | // Enables deferred processing of flags in dynamically loaded libraries. 205 | static bool allow_command_line_reparsing = false; 206 | 207 | static bool logging_is_probably_set_up = false; 208 | 209 | // This is a 'prototype' validate-function. 'Real' validate 210 | // functions, take a flag-value as an argument: ValidateFn(bool) or 211 | // ValidateFn(uint64). However, for easier storage, we strip off this 212 | // argument and then restore it when actually calling the function on 213 | // a flag value. 214 | typedef bool (*ValidateFnProto)(); 215 | 216 | // Whether we should die when reporting an error. 217 | enum DieWhenReporting { DIE, DO_NOT_DIE }; 218 | 219 | // Report Error and exit if requested. 220 | static void ReportError(DieWhenReporting should_die, const char* format, ...) { 221 | va_list ap; 222 | va_start(ap, format); 223 | vfprintf(stderr, format, ap); 224 | va_end(ap); 225 | if (should_die == DIE) 226 | commandlineflags_exitfunc(1); // almost certainly exit() 227 | } 228 | 229 | 230 | // -------------------------------------------------------------------- 231 | // FlagValue 232 | // This represent the value a single flag might have. The major 233 | // functionality is to convert from a string to an object of a 234 | // given type, and back. Thread-compatible. 235 | // -------------------------------------------------------------------- 236 | 237 | class CommandLineFlag; 238 | class FlagValue { 239 | public: 240 | FlagValue(void* valbuf, const char* type, bool transfer_ownership_of_value); 241 | ~FlagValue(); 242 | 243 | bool ParseFrom(const char* spec); 244 | string ToString() const; 245 | 246 | private: 247 | friend class CommandLineFlag; // for many things, including Validate() 248 | friend class GOOGLE_NAMESPACE::FlagSaverImpl; // calls New() 249 | friend class FlagRegistry; // checks value_buffer_ for flags_by_ptr_ map 250 | template friend T GetFromEnv(const char*, const char*, T); 251 | friend bool TryParseLocked(const CommandLineFlag*, FlagValue*, 252 | const char*, string*); // for New(), CopyFrom() 253 | 254 | enum ValueType { 255 | FV_BOOL = 0, 256 | FV_INT32 = 1, 257 | FV_INT64 = 2, 258 | FV_UINT64 = 3, 259 | FV_DOUBLE = 4, 260 | FV_STRING = 5, 261 | FV_MAX_INDEX = 5, 262 | }; 263 | const char* TypeName() const; 264 | bool Equal(const FlagValue& x) const; 265 | FlagValue* New() const; // creates a new one with default value 266 | void CopyFrom(const FlagValue& x); 267 | int ValueSize() const; 268 | 269 | // Calls the given validate-fn on value_buffer_, and returns 270 | // whatever it returns. But first casts validate_fn_proto to a 271 | // function that takes our value as an argument (eg void 272 | // (*validate_fn)(bool) for a bool flag). 273 | bool Validate(const char* flagname, ValidateFnProto validate_fn_proto) const; 274 | 275 | void* value_buffer_; // points to the buffer holding our data 276 | int8 type_; // how to interpret value_ 277 | bool owns_value_; // whether to free value on destruct 278 | 279 | FlagValue(const FlagValue&); // no copying! 280 | void operator=(const FlagValue&); 281 | }; 282 | 283 | 284 | // This could be a templated method of FlagValue, but doing so adds to the 285 | // size of the .o. Since there's no type-safety here anyway, macro is ok. 286 | #define VALUE_AS(type) *reinterpret_cast(value_buffer_) 287 | #define OTHER_VALUE_AS(fv, type) *reinterpret_cast(fv.value_buffer_) 288 | #define SET_VALUE_AS(type, value) VALUE_AS(type) = (value) 289 | 290 | FlagValue::FlagValue(void* valbuf, const char* type, 291 | bool transfer_ownership_of_value) 292 | : value_buffer_(valbuf), 293 | owns_value_(transfer_ownership_of_value) { 294 | for (type_ = 0; type_ <= FV_MAX_INDEX; ++type_) { 295 | if (!strcmp(type, TypeName())) { 296 | break; 297 | } 298 | } 299 | assert(type_ <= FV_MAX_INDEX); // Unknown typename 300 | } 301 | 302 | FlagValue::~FlagValue() { 303 | if (!owns_value_) { 304 | return; 305 | } 306 | switch (type_) { 307 | case FV_BOOL: delete reinterpret_cast(value_buffer_); break; 308 | case FV_INT32: delete reinterpret_cast(value_buffer_); break; 309 | case FV_INT64: delete reinterpret_cast(value_buffer_); break; 310 | case FV_UINT64: delete reinterpret_cast(value_buffer_); break; 311 | case FV_DOUBLE: delete reinterpret_cast(value_buffer_); break; 312 | case FV_STRING: delete reinterpret_cast(value_buffer_); break; 313 | } 314 | } 315 | 316 | bool FlagValue::ParseFrom(const char* value) { 317 | if (type_ == FV_BOOL) { 318 | const char* kTrue[] = { "1", "t", "true", "y", "yes" }; 319 | const char* kFalse[] = { "0", "f", "false", "n", "no" }; 320 | for (size_t i = 0; i < sizeof(kTrue)/sizeof(*kTrue); ++i) { 321 | if (strcasecmp(value, kTrue[i]) == 0) { 322 | SET_VALUE_AS(bool, true); 323 | return true; 324 | } else if (strcasecmp(value, kFalse[i]) == 0) { 325 | SET_VALUE_AS(bool, false); 326 | return true; 327 | } 328 | } 329 | return false; // didn't match a legal input 330 | 331 | } else if (type_ == FV_STRING) { 332 | SET_VALUE_AS(string, value); 333 | return true; 334 | } 335 | 336 | // OK, it's likely to be numeric, and we'll be using a strtoXXX method. 337 | if (value[0] == '\0') // empty-string is only allowed for string type. 338 | return false; 339 | char* end; 340 | // Leading 0x puts us in base 16. But leading 0 does not put us in base 8! 341 | // It caused too many bugs when we had that behavior. 342 | int base = 10; // by default 343 | if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) 344 | base = 16; 345 | errno = 0; 346 | 347 | switch (type_) { 348 | case FV_INT32: { 349 | const int64 r = strtoint64(value, &end, base); 350 | if (errno || end != value + strlen(value)) return false; // bad parse 351 | if (static_cast(r) != r) // worked, but number out of range 352 | return false; 353 | SET_VALUE_AS(int32, static_cast(r)); 354 | return true; 355 | } 356 | case FV_INT64: { 357 | const int64 r = strtoint64(value, &end, base); 358 | if (errno || end != value + strlen(value)) return false; // bad parse 359 | SET_VALUE_AS(int64, r); 360 | return true; 361 | } 362 | case FV_UINT64: { 363 | while (*value == ' ') value++; 364 | if (*value == '-') return false; // negative number 365 | const uint64 r = strtouint64(value, &end, base); 366 | if (errno || end != value + strlen(value)) return false; // bad parse 367 | SET_VALUE_AS(uint64, r); 368 | return true; 369 | } 370 | case FV_DOUBLE: { 371 | const double r = strtod(value, &end); 372 | if (errno || end != value + strlen(value)) return false; // bad parse 373 | SET_VALUE_AS(double, r); 374 | return true; 375 | } 376 | default: { 377 | assert(false); // unknown type 378 | return false; 379 | } 380 | } 381 | } 382 | 383 | string FlagValue::ToString() const { 384 | char intbuf[64]; // enough to hold even the biggest number 385 | switch (type_) { 386 | case FV_BOOL: 387 | return VALUE_AS(bool) ? "true" : "false"; 388 | case FV_INT32: 389 | snprintf(intbuf, sizeof(intbuf), "%" PRId32, VALUE_AS(int32)); 390 | return intbuf; 391 | case FV_INT64: 392 | snprintf(intbuf, sizeof(intbuf), "%" PRId64, VALUE_AS(int64)); 393 | return intbuf; 394 | case FV_UINT64: 395 | snprintf(intbuf, sizeof(intbuf), "%" PRIu64, VALUE_AS(uint64)); 396 | return intbuf; 397 | case FV_DOUBLE: 398 | snprintf(intbuf, sizeof(intbuf), "%.17g", VALUE_AS(double)); 399 | return intbuf; 400 | case FV_STRING: 401 | return VALUE_AS(string); 402 | default: 403 | assert(false); 404 | return ""; // unknown type 405 | } 406 | } 407 | 408 | bool FlagValue::Validate(const char* flagname, 409 | ValidateFnProto validate_fn_proto) const { 410 | switch (type_) { 411 | case FV_BOOL: 412 | return reinterpret_cast( 413 | validate_fn_proto)(flagname, VALUE_AS(bool)); 414 | case FV_INT32: 415 | return reinterpret_cast( 416 | validate_fn_proto)(flagname, VALUE_AS(int32)); 417 | case FV_INT64: 418 | return reinterpret_cast( 419 | validate_fn_proto)(flagname, VALUE_AS(int64)); 420 | case FV_UINT64: 421 | return reinterpret_cast( 422 | validate_fn_proto)(flagname, VALUE_AS(uint64)); 423 | case FV_DOUBLE: 424 | return reinterpret_cast( 425 | validate_fn_proto)(flagname, VALUE_AS(double)); 426 | case FV_STRING: 427 | return reinterpret_cast( 428 | validate_fn_proto)(flagname, VALUE_AS(string)); 429 | default: 430 | assert(false); // unknown type 431 | return false; 432 | } 433 | } 434 | 435 | const char* FlagValue::TypeName() const { 436 | static const char types[] = 437 | "bool\0xx" 438 | "int32\0x" 439 | "int64\0x" 440 | "uint64\0" 441 | "double\0" 442 | "string"; 443 | if (type_ > FV_MAX_INDEX) { 444 | assert(false); 445 | return ""; 446 | } 447 | // Directly indexing the strigns in the 'types' string, each of them 448 | // is 7 bytes long. 449 | return &types[type_ * 7]; 450 | } 451 | 452 | bool FlagValue::Equal(const FlagValue& x) const { 453 | if (type_ != x.type_) 454 | return false; 455 | switch (type_) { 456 | case FV_BOOL: return VALUE_AS(bool) == OTHER_VALUE_AS(x, bool); 457 | case FV_INT32: return VALUE_AS(int32) == OTHER_VALUE_AS(x, int32); 458 | case FV_INT64: return VALUE_AS(int64) == OTHER_VALUE_AS(x, int64); 459 | case FV_UINT64: return VALUE_AS(uint64) == OTHER_VALUE_AS(x, uint64); 460 | case FV_DOUBLE: return VALUE_AS(double) == OTHER_VALUE_AS(x, double); 461 | case FV_STRING: return VALUE_AS(string) == OTHER_VALUE_AS(x, string); 462 | default: assert(false); return false; // unknown type 463 | } 464 | } 465 | 466 | FlagValue* FlagValue::New() const { 467 | const char *type = TypeName(); 468 | switch (type_) { 469 | case FV_BOOL: return new FlagValue(new bool(false), type, true); 470 | case FV_INT32: return new FlagValue(new int32(0), type, true); 471 | case FV_INT64: return new FlagValue(new int64(0), type, true); 472 | case FV_UINT64: return new FlagValue(new uint64(0), type, true); 473 | case FV_DOUBLE: return new FlagValue(new double(0.0), type, true); 474 | case FV_STRING: return new FlagValue(new string, type, true); 475 | default: assert(false); return NULL; // unknown type 476 | } 477 | } 478 | 479 | void FlagValue::CopyFrom(const FlagValue& x) { 480 | assert(type_ == x.type_); 481 | switch (type_) { 482 | case FV_BOOL: SET_VALUE_AS(bool, OTHER_VALUE_AS(x, bool)); break; 483 | case FV_INT32: SET_VALUE_AS(int32, OTHER_VALUE_AS(x, int32)); break; 484 | case FV_INT64: SET_VALUE_AS(int64, OTHER_VALUE_AS(x, int64)); break; 485 | case FV_UINT64: SET_VALUE_AS(uint64, OTHER_VALUE_AS(x, uint64)); break; 486 | case FV_DOUBLE: SET_VALUE_AS(double, OTHER_VALUE_AS(x, double)); break; 487 | case FV_STRING: SET_VALUE_AS(string, OTHER_VALUE_AS(x, string)); break; 488 | default: assert(false); // unknown type 489 | } 490 | } 491 | 492 | int FlagValue::ValueSize() const { 493 | if (type_ > FV_MAX_INDEX) { 494 | assert(false); // unknown type 495 | return 0; 496 | } 497 | static const uint8 valuesize[] = { 498 | sizeof(bool), 499 | sizeof(int32), 500 | sizeof(int64), 501 | sizeof(uint64), 502 | sizeof(double), 503 | sizeof(string), 504 | }; 505 | return valuesize[type_]; 506 | } 507 | 508 | // -------------------------------------------------------------------- 509 | // CommandLineFlag 510 | // This represents a single flag, including its name, description, 511 | // default value, and current value. Mostly this serves as a 512 | // struct, though it also knows how to register itself. 513 | // All CommandLineFlags are owned by a (exactly one) 514 | // FlagRegistry. If you wish to modify fields in this class, you 515 | // should acquire the FlagRegistry lock for the registry that owns 516 | // this flag. 517 | // -------------------------------------------------------------------- 518 | 519 | class CommandLineFlag { 520 | public: 521 | // Note: we take over memory-ownership of current_val and default_val. 522 | CommandLineFlag(const char* name, const char* help, const char* filename, 523 | FlagValue* current_val, FlagValue* default_val); 524 | ~CommandLineFlag(); 525 | 526 | const char* name() const { return name_; } 527 | const char* help() const { return help_; } 528 | const char* filename() const { return file_; } 529 | const char* CleanFileName() const; // nixes irrelevant prefix such as homedir 530 | string current_value() const { return current_->ToString(); } 531 | string default_value() const { return defvalue_->ToString(); } 532 | const char* type_name() const { return defvalue_->TypeName(); } 533 | ValidateFnProto validate_function() const { return validate_fn_proto_; } 534 | 535 | void FillCommandLineFlagInfo(struct CommandLineFlagInfo* result); 536 | 537 | // If validate_fn_proto_ is non-NULL, calls it on value, returns result. 538 | bool Validate(const FlagValue& value) const; 539 | bool ValidateCurrent() const { return Validate(*current_); } 540 | 541 | private: 542 | // for SetFlagLocked() and setting flags_by_ptr_ 543 | friend class FlagRegistry; 544 | friend class GOOGLE_NAMESPACE::FlagSaverImpl; // for cloning the values 545 | // set validate_fn 546 | friend bool AddFlagValidator(const void*, ValidateFnProto); 547 | 548 | // This copies all the non-const members: modified, processed, defvalue, etc. 549 | void CopyFrom(const CommandLineFlag& src); 550 | 551 | void UpdateModifiedBit(); 552 | 553 | const char* const name_; // Flag name 554 | const char* const help_; // Help message 555 | const char* const file_; // Which file did this come from? 556 | bool modified_; // Set after default assignment? 557 | FlagValue* defvalue_; // Default value for flag 558 | FlagValue* current_; // Current value for flag 559 | // This is a casted, 'generic' version of validate_fn, which actually 560 | // takes a flag-value as an arg (void (*validate_fn)(bool), say). 561 | // When we pass this to current_->Validate(), it will cast it back to 562 | // the proper type. This may be NULL to mean we have no validate_fn. 563 | ValidateFnProto validate_fn_proto_; 564 | 565 | CommandLineFlag(const CommandLineFlag&); // no copying! 566 | void operator=(const CommandLineFlag&); 567 | }; 568 | 569 | CommandLineFlag::CommandLineFlag(const char* name, const char* help, 570 | const char* filename, 571 | FlagValue* current_val, FlagValue* default_val) 572 | : name_(name), help_(help), file_(filename), modified_(false), 573 | defvalue_(default_val), current_(current_val), validate_fn_proto_(NULL) { 574 | } 575 | 576 | CommandLineFlag::~CommandLineFlag() { 577 | delete current_; 578 | delete defvalue_; 579 | } 580 | 581 | const char* CommandLineFlag::CleanFileName() const { 582 | // Compute top-level directory & file that this appears in 583 | // search full path backwards. 584 | // Stop going backwards at kRootDir; and skip by the first slash. 585 | static const char kRootDir[] = ""; // can set this to root directory, 586 | // e.g. "myproject" 587 | 588 | if (sizeof(kRootDir)-1 == 0) // no prefix to strip 589 | return filename(); 590 | 591 | const char* clean_name = filename() + strlen(filename()) - 1; 592 | while ( clean_name > filename() ) { 593 | if (*clean_name == PATH_SEPARATOR) { 594 | if (strncmp(clean_name, kRootDir, sizeof(kRootDir)-1) == 0) { 595 | // ".../myproject/base/logging.cc" ==> "base/logging.cc" 596 | clean_name += sizeof(kRootDir)-1; // past "/myproject/" 597 | break; 598 | } 599 | } 600 | --clean_name; 601 | } 602 | while ( *clean_name == PATH_SEPARATOR ) ++clean_name; // Skip any slashes 603 | return clean_name; 604 | } 605 | 606 | void CommandLineFlag::FillCommandLineFlagInfo( 607 | CommandLineFlagInfo* result) { 608 | result->name = name(); 609 | result->type = type_name(); 610 | result->description = help(); 611 | result->current_value = current_value(); 612 | result->default_value = default_value(); 613 | result->filename = CleanFileName(); 614 | UpdateModifiedBit(); 615 | result->is_default = !modified_; 616 | result->has_validator_fn = validate_function() != NULL; 617 | } 618 | 619 | void CommandLineFlag::UpdateModifiedBit() { 620 | // Update the "modified" bit in case somebody bypassed the 621 | // Flags API and wrote directly through the FLAGS_name variable. 622 | if (!modified_ && !current_->Equal(*defvalue_)) { 623 | modified_ = true; 624 | } 625 | } 626 | 627 | void CommandLineFlag::CopyFrom(const CommandLineFlag& src) { 628 | // Note we only copy the non-const members; others are fixed at construct time 629 | if (modified_ != src.modified_) modified_ = src.modified_; 630 | if (!current_->Equal(*src.current_)) current_->CopyFrom(*src.current_); 631 | if (!defvalue_->Equal(*src.defvalue_)) defvalue_->CopyFrom(*src.defvalue_); 632 | if (validate_fn_proto_ != src.validate_fn_proto_) 633 | validate_fn_proto_ = src.validate_fn_proto_; 634 | } 635 | 636 | bool CommandLineFlag::Validate(const FlagValue& value) const { 637 | if (validate_function() == NULL) 638 | return true; 639 | else 640 | return value.Validate(name(), validate_function()); 641 | } 642 | 643 | 644 | // -------------------------------------------------------------------- 645 | // FlagRegistry 646 | // A FlagRegistry singleton object holds all flag objects indexed 647 | // by their names so that if you know a flag's name (as a C 648 | // string), you can access or set it. If the function is named 649 | // FooLocked(), you must own the registry lock before calling 650 | // the function; otherwise, you should *not* hold the lock, and 651 | // the function will acquire it itself if needed. 652 | // -------------------------------------------------------------------- 653 | 654 | struct StringCmp { // Used by the FlagRegistry map class to compare char*'s 655 | bool operator() (const char* s1, const char* s2) const { 656 | return (strcmp(s1, s2) < 0); 657 | } 658 | }; 659 | 660 | class FlagRegistry { 661 | public: 662 | FlagRegistry() { } 663 | ~FlagRegistry() { 664 | for (FlagMap::iterator p = flags_.begin(), e = flags_.end(); p != e; ++p) { 665 | CommandLineFlag* flag = p->second; 666 | delete flag; 667 | } 668 | } 669 | 670 | static void DeleteGlobalRegistry() { 671 | delete global_registry_; 672 | global_registry_ = NULL; 673 | } 674 | 675 | void Lock() { lock_.Lock(); } 676 | void Unlock() { lock_.Unlock(); } 677 | 678 | // Store a flag in this registry. Takes ownership of the given pointer. 679 | void RegisterFlag(CommandLineFlag* flag); 680 | 681 | // Returns the flag object for the specified name, or NULL if not found. 682 | CommandLineFlag* FindFlagLocked(const char* name); 683 | 684 | // Returns the flag object whose current-value is stored at flag_ptr. 685 | // That is, for whom current_->value_buffer_ == flag_ptr 686 | CommandLineFlag* FindFlagViaPtrLocked(const void* flag_ptr); 687 | 688 | // A fancier form of FindFlag that works correctly if name is of the 689 | // form flag=value. In that case, we set key to point to flag, and 690 | // modify v to point to the value (if present), and return the flag 691 | // with the given name. If the flag does not exist, returns NULL 692 | // and sets error_message. 693 | CommandLineFlag* SplitArgumentLocked(const char* argument, 694 | string* key, const char** v, 695 | string* error_message); 696 | 697 | // Set the value of a flag. If the flag was successfully set to 698 | // value, set msg to indicate the new flag-value, and return true. 699 | // Otherwise, set msg to indicate the error, leave flag unchanged, 700 | // and return false. msg can be NULL. 701 | bool SetFlagLocked(CommandLineFlag* flag, const char* value, 702 | FlagSettingMode set_mode, string* msg); 703 | 704 | static FlagRegistry* GlobalRegistry(); // returns a singleton registry 705 | 706 | private: 707 | friend class GOOGLE_NAMESPACE::FlagSaverImpl; // reads all the flags in order to copy them 708 | friend class CommandLineFlagParser; // for ValidateAllFlags 709 | friend void GOOGLE_NAMESPACE::GetAllFlags(vector*); 710 | 711 | // The map from name to flag, for FindFlagLocked(). 712 | typedef map FlagMap; 713 | typedef FlagMap::iterator FlagIterator; 714 | typedef FlagMap::const_iterator FlagConstIterator; 715 | FlagMap flags_; 716 | 717 | // The map from current-value pointer to flag, fo FindFlagViaPtrLocked(). 718 | typedef map FlagPtrMap; 719 | FlagPtrMap flags_by_ptr_; 720 | 721 | Mutex lock_; 722 | 723 | static FlagRegistry* global_registry_; // a singleton registry 724 | static Mutex global_registry_lock_; // guards creation of global_registry_ 725 | 726 | // Disallow 727 | FlagRegistry(const FlagRegistry&); 728 | FlagRegistry& operator=(const FlagRegistry&); 729 | }; 730 | 731 | FlagRegistry* FlagRegistry::global_registry_ = NULL; 732 | Mutex FlagRegistry::global_registry_lock_(Mutex::LINKER_INITIALIZED); 733 | 734 | FlagRegistry* FlagRegistry::GlobalRegistry() { 735 | MutexLock acquire_lock(&global_registry_lock_); 736 | if (!global_registry_) { 737 | global_registry_ = new FlagRegistry; 738 | } 739 | return global_registry_; 740 | } 741 | 742 | void FlagRegistry::RegisterFlag(CommandLineFlag* flag) { 743 | Lock(); 744 | pair ins = 745 | flags_.insert(pair(flag->name(), flag)); 746 | if (ins.second == false) { // means the name was already in the map 747 | if (strcmp(ins.first->second->filename(), flag->filename()) != 0) { 748 | ReportError(DIE, "ERROR: flag '%s' was defined more than once " 749 | "(in files '%s' and '%s').\n", 750 | flag->name(), 751 | ins.first->second->filename(), 752 | flag->filename()); 753 | } else { 754 | ReportError(DIE, "ERROR: something wrong with flag '%s' in file '%s'. " 755 | "One possibility: file '%s' is being linked both statically " 756 | "and dynamically into this executable.\n", 757 | flag->name(), 758 | flag->filename(), flag->filename()); 759 | } 760 | } 761 | // Also add to the flags_by_ptr_ map. 762 | flags_by_ptr_[flag->current_->value_buffer_] = flag; 763 | Unlock(); 764 | } 765 | 766 | CommandLineFlag* FlagRegistry::FindFlagLocked(const char* name) { 767 | FlagConstIterator i = flags_.find(name); 768 | if (i == flags_.end()) { 769 | return NULL; 770 | } else { 771 | return i->second; 772 | } 773 | } 774 | 775 | CommandLineFlag* FlagRegistry::FindFlagViaPtrLocked(const void* flag_ptr) { 776 | FlagPtrMap::const_iterator i = flags_by_ptr_.find(flag_ptr); 777 | if (i == flags_by_ptr_.end()) { 778 | return NULL; 779 | } else { 780 | return i->second; 781 | } 782 | } 783 | 784 | CommandLineFlag* FlagRegistry::SplitArgumentLocked(const char* arg, 785 | string* key, 786 | const char** v, 787 | string* error_message) { 788 | // Find the flag object for this option 789 | const char* flag_name; 790 | const char* value = strchr(arg, '='); 791 | if (value == NULL) { 792 | key->assign(arg); 793 | *v = NULL; 794 | } else { 795 | // Strip out the "=value" portion from arg 796 | key->assign(arg, value-arg); 797 | *v = ++value; // advance past the '=' 798 | } 799 | flag_name = key->c_str(); 800 | 801 | CommandLineFlag* flag = FindFlagLocked(flag_name); 802 | 803 | if (flag == NULL) { 804 | // If we can't find the flag-name, then we should return an error. 805 | // The one exception is if 1) the flag-name is 'nox', 2) there 806 | // exists a flag named 'x', and 3) 'x' is a boolean flag. 807 | // In that case, we want to return flag 'x'. 808 | if (!(flag_name[0] == 'n' && flag_name[1] == 'o')) { 809 | // flag-name is not 'nox', so we're not in the exception case. 810 | *error_message = (string(kError) + 811 | "unknown command line flag '" + *key + "'\n"); 812 | return NULL; 813 | } 814 | flag = FindFlagLocked(flag_name+2); 815 | if (flag == NULL) { 816 | // No flag named 'x' exists, so we're not in the exception case. 817 | *error_message = (string(kError) + 818 | "unknown command line flag '" + *key + "'\n"); 819 | return NULL; 820 | } 821 | if (strcmp(flag->type_name(), "bool") != 0) { 822 | // 'x' exists but is not boolean, so we're not in the exception case. 823 | *error_message = (string(kError) + 824 | "boolean value (" + *key + ") specified for " + 825 | flag->type_name() + " command line flag\n"); 826 | return NULL; 827 | } 828 | // We're in the exception case! 829 | // Make up a fake value to replace the "no" we stripped out 830 | key->assign(flag_name+2); // the name without the "no" 831 | *v = "0"; 832 | } 833 | 834 | // Assign a value if this is a boolean flag 835 | if (*v == NULL && strcmp(flag->type_name(), "bool") == 0) { 836 | *v = "1"; // the --nox case was already handled, so this is the --x case 837 | } 838 | 839 | return flag; 840 | } 841 | 842 | bool TryParseLocked(const CommandLineFlag* flag, FlagValue* flag_value, 843 | const char* value, string* msg) { 844 | // Use tenative_value, not flag_value, until we know value is valid. 845 | FlagValue* tentative_value = flag_value->New(); 846 | if (!tentative_value->ParseFrom(value)) { 847 | if (msg) { 848 | *msg += (string(kError) + "illegal value '" + value + 849 | + "' specified for " + flag->type_name() + " flag '" 850 | + flag->name() + "'\n"); 851 | } 852 | delete tentative_value; 853 | return false; 854 | } else if (!flag->Validate(*tentative_value)) { 855 | if (msg) { 856 | *msg += (string(kError) + "failed validation of new value " 857 | + "'" + tentative_value->ToString() + "' for flag '" + 858 | + flag->name() + "'\n"); 859 | } 860 | delete tentative_value; 861 | return false; 862 | } else { 863 | flag_value->CopyFrom(*tentative_value); 864 | if (msg) { 865 | *msg += (string(flag->name()) + " set to " + flag_value->ToString() 866 | + "\n"); 867 | } 868 | delete tentative_value; 869 | return true; 870 | } 871 | } 872 | 873 | bool FlagRegistry::SetFlagLocked(CommandLineFlag* flag, 874 | const char* value, 875 | FlagSettingMode set_mode, 876 | string* msg) { 877 | flag->UpdateModifiedBit(); 878 | switch (set_mode) { 879 | case SET_FLAGS_VALUE: { 880 | // set or modify the flag's value 881 | if (!TryParseLocked(flag, flag->current_, value, msg)) 882 | return false; 883 | flag->modified_ = true; 884 | break; 885 | } 886 | case SET_FLAG_IF_DEFAULT: { 887 | // set the flag's value, but only if it hasn't been set by someone else 888 | if (!flag->modified_) { 889 | if (!TryParseLocked(flag, flag->current_, value, msg)) 890 | return false; 891 | flag->modified_ = true; 892 | } else { 893 | *msg = string(flag->name()) + " set to " + flag->current_value(); 894 | } 895 | break; 896 | } 897 | case SET_FLAGS_DEFAULT: { 898 | // modify the flag's default-value 899 | if (!TryParseLocked(flag, flag->defvalue_, value, msg)) 900 | return false; 901 | if (!flag->modified_) { 902 | // Need to set both defvalue *and* current, in this case 903 | TryParseLocked(flag, flag->current_, value, NULL); 904 | } 905 | break; 906 | } 907 | default: { 908 | // unknown set_mode 909 | assert(false); 910 | return false; 911 | } 912 | } 913 | 914 | return true; 915 | } 916 | 917 | class FlagRegistryLock { 918 | public: 919 | explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); } 920 | ~FlagRegistryLock() { fr_->Unlock(); } 921 | private: 922 | FlagRegistry *const fr_; 923 | }; 924 | 925 | // -------------------------------------------------------------------- 926 | // CommandLineFlagParser 927 | // Parsing is done in two stages. In the first, we go through 928 | // argv. For every flag-like arg we can make sense of, we parse 929 | // it and set the appropriate FLAGS_* variable. For every flag- 930 | // like arg we can't make sense of, we store it in a vector, 931 | // along with an explanation of the trouble. In stage 2, we 932 | // handle the 'reporting' flags like --help and --mpm_version. 933 | // (This is via a call to HandleCommandLineHelpFlags(), in 934 | // gflags_reporting.cc.) 935 | // An optional stage 3 prints out the error messages. 936 | // This is a bit of a simplification. For instance, --flagfile 937 | // is handled as soon as it's seen in stage 1, not in stage 2. 938 | // -------------------------------------------------------------------- 939 | 940 | class CommandLineFlagParser { 941 | public: 942 | // The argument is the flag-registry to register the parsed flags in 943 | explicit CommandLineFlagParser(FlagRegistry* reg) : registry_(reg) {} 944 | ~CommandLineFlagParser() {} 945 | 946 | // Stage 1: Every time this is called, it reads all flags in argv. 947 | // However, it ignores all flags that have been successfully set 948 | // before. Typically this is only called once, so this 'reparsing' 949 | // behavior isn't important. It can be useful when trying to 950 | // reparse after loading a dll, though. 951 | uint32 ParseNewCommandLineFlags(int* argc, char*** argv, bool remove_flags); 952 | 953 | // Stage 2: print reporting info and exit, if requested. 954 | // In gflags_reporting.cc:HandleCommandLineHelpFlags(). 955 | 956 | // Stage 3: validate all the commandline flags that have validators 957 | // registered. 958 | void ValidateAllFlags(); 959 | 960 | // Stage 4: report any errors and return true if any were found. 961 | bool ReportErrors(); 962 | 963 | // Set a particular command line option. "newval" is a string 964 | // describing the new value that the option has been set to. If 965 | // option_name does not specify a valid option name, or value is not 966 | // a valid value for option_name, newval is empty. Does recursive 967 | // processing for --flagfile and --fromenv. Returns the new value 968 | // if everything went ok, or empty-string if not. (Actually, the 969 | // return-string could hold many flag/value pairs due to --flagfile.) 970 | // NB: Must have called registry_->Lock() before calling this function. 971 | string ProcessSingleOptionLocked(CommandLineFlag* flag, 972 | const char* value, 973 | FlagSettingMode set_mode); 974 | 975 | // Set a whole batch of command line options as specified by contentdata, 976 | // which is in flagfile format (and probably has been read from a flagfile). 977 | // Returns the new value if everything went ok, or empty-string if 978 | // not. (Actually, the return-string could hold many flag/value 979 | // pairs due to --flagfile.) 980 | // NB: Must have called registry_->Lock() before calling this function. 981 | string ProcessOptionsFromStringLocked(const string& contentdata, 982 | FlagSettingMode set_mode); 983 | 984 | // These are the 'recursive' flags, defined at the top of this file. 985 | // Whenever we see these flags on the commandline, we must take action. 986 | // These are called by ProcessSingleOptionLocked and, similarly, return 987 | // new values if everything went ok, or the empty-string if not. 988 | string ProcessFlagfileLocked(const string& flagval, FlagSettingMode set_mode); 989 | // diff fromenv/tryfromenv 990 | string ProcessFromenvLocked(const string& flagval, FlagSettingMode set_mode, 991 | bool errors_are_fatal); 992 | 993 | private: 994 | FlagRegistry* const registry_; 995 | map error_flags_; // map from name to error message 996 | // This could be a set, but we reuse the map to minimize the .o size 997 | map undefined_names_; // --[flag] name was not registered 998 | }; 999 | 1000 | 1001 | // Parse a list of (comma-separated) flags. 1002 | static void ParseFlagList(const char* value, vector* flags) { 1003 | for (const char *p = value; p && *p; value = p) { 1004 | p = strchr(value, ','); 1005 | int len; 1006 | if (p) { 1007 | len = static_cast(p - value); 1008 | p++; 1009 | } else { 1010 | len = static_cast(strlen(value)); 1011 | } 1012 | 1013 | if (len == 0) 1014 | ReportError(DIE, "ERROR: empty flaglist entry\n"); 1015 | if (value[0] == '-') 1016 | ReportError(DIE, "ERROR: flag \"%*s\" begins with '-'\n", len, value); 1017 | 1018 | flags->push_back(string(value, len)); 1019 | } 1020 | } 1021 | 1022 | // Snarf an entire file into a C++ string. This is just so that we 1023 | // can do all the I/O in one place and not worry about it everywhere. 1024 | // Plus, it's convenient to have the whole file contents at hand. 1025 | // Adds a newline at the end of the file. 1026 | #define PFATAL(s) do { perror(s); commandlineflags_exitfunc(1); } while (0) 1027 | 1028 | static string ReadFileIntoString(const char* filename) { 1029 | const int kBufSize = 8092; 1030 | char buffer[kBufSize]; 1031 | string s; 1032 | FILE* fp = fopen(filename, "r"); 1033 | if (!fp) PFATAL(filename); 1034 | size_t n; 1035 | while ( (n=fread(buffer, 1, kBufSize, fp)) > 0 ) { 1036 | if (ferror(fp)) PFATAL(filename); 1037 | s.append(buffer, n); 1038 | } 1039 | fclose(fp); 1040 | return s; 1041 | } 1042 | 1043 | uint32 CommandLineFlagParser::ParseNewCommandLineFlags(int* argc, char*** argv, 1044 | bool remove_flags) { 1045 | const char *program_name = strrchr((*argv)[0], PATH_SEPARATOR); // nix path 1046 | program_name = (program_name == NULL ? (*argv)[0] : program_name+1); 1047 | 1048 | int first_nonopt = *argc; // for non-options moved to the end 1049 | 1050 | registry_->Lock(); 1051 | for (int i = 1; i < first_nonopt; i++) { 1052 | char* arg = (*argv)[i]; 1053 | 1054 | // Like getopt(), we permute non-option flags to be at the end. 1055 | if (arg[0] != '-' || // must be a program argument 1056 | (arg[0] == '-' && arg[1] == '\0')) { // "-" is an argument, not a flag 1057 | memmove((*argv) + i, (*argv) + i+1, (*argc - (i+1)) * sizeof((*argv)[i])); 1058 | (*argv)[*argc-1] = arg; // we go last 1059 | first_nonopt--; // we've been pushed onto the stack 1060 | i--; // to undo the i++ in the loop 1061 | continue; 1062 | } 1063 | 1064 | if (arg[0] == '-') arg++; // allow leading '-' 1065 | if (arg[0] == '-') arg++; // or leading '--' 1066 | 1067 | // -- alone means what it does for GNU: stop options parsing 1068 | if (*arg == '\0') { 1069 | first_nonopt = i+1; 1070 | break; 1071 | } 1072 | 1073 | // Find the flag object for this option 1074 | string key; 1075 | const char* value; 1076 | string error_message; 1077 | CommandLineFlag* flag = registry_->SplitArgumentLocked(arg, &key, &value, 1078 | &error_message); 1079 | if (flag == NULL) { 1080 | undefined_names_[key] = ""; // value isn't actually used 1081 | error_flags_[key] = error_message; 1082 | continue; 1083 | } 1084 | 1085 | if (value == NULL) { 1086 | // Boolean options are always assigned a value by SplitArgumentLocked() 1087 | assert(strcmp(flag->type_name(), "bool") != 0); 1088 | if (i+1 >= first_nonopt) { 1089 | // This flag needs a value, but there is nothing available 1090 | error_flags_[key] = (string(kError) + "flag '" + (*argv)[i] + "'" 1091 | + " is missing its argument"); 1092 | if (flag->help() && flag->help()[0] > '\001') { 1093 | // Be useful in case we have a non-stripped description. 1094 | error_flags_[key] += string("; flag description: ") + flag->help(); 1095 | } 1096 | error_flags_[key] += "\n"; 1097 | break; // we treat this as an unrecoverable error 1098 | } else { 1099 | value = (*argv)[++i]; // read next arg for value 1100 | 1101 | // Heuristic to detect the case where someone treats a string arg 1102 | // like a bool: 1103 | // --my_string_var --foo=bar 1104 | // We look for a flag of string type, whose value begins with a 1105 | // dash, and where the flag-name and value are separated by a 1106 | // space rather than an '='. 1107 | // To avoid false positives, we also require the word "true" 1108 | // or "false" in the help string. Without this, a valid usage 1109 | // "-lat -30.5" would trigger the warning. The common cases we 1110 | // want to solve talk about true and false as values. 1111 | if (value[0] == '-' 1112 | && strcmp(flag->type_name(), "string") == 0 1113 | && (strstr(flag->help(), "true") 1114 | || strstr(flag->help(), "false"))) { 1115 | fprintf(stderr, "Did you really mean to set flag '%s'" 1116 | " to the value '%s'?\n", 1117 | flag->name(), value); 1118 | } 1119 | } 1120 | } 1121 | 1122 | // TODO(csilvers): only set a flag if we hadn't set it before here 1123 | ProcessSingleOptionLocked(flag, value, SET_FLAGS_VALUE); 1124 | } 1125 | registry_->Unlock(); 1126 | 1127 | if (remove_flags) { // Fix up argc and argv by removing command line flags 1128 | (*argv)[first_nonopt-1] = (*argv)[0]; 1129 | (*argv) += (first_nonopt-1); 1130 | (*argc) -= (first_nonopt-1); 1131 | first_nonopt = 1; // because we still don't count argv[0] 1132 | } 1133 | 1134 | logging_is_probably_set_up = true; // because we've parsed --logdir, etc. 1135 | 1136 | return first_nonopt; 1137 | } 1138 | 1139 | string CommandLineFlagParser::ProcessFlagfileLocked(const string& flagval, 1140 | FlagSettingMode set_mode) { 1141 | if (flagval.empty()) 1142 | return ""; 1143 | 1144 | string msg; 1145 | vector filename_list; 1146 | ParseFlagList(flagval.c_str(), &filename_list); // take a list of filenames 1147 | for (size_t i = 0; i < filename_list.size(); ++i) { 1148 | const char* file = filename_list[i].c_str(); 1149 | msg += ProcessOptionsFromStringLocked(ReadFileIntoString(file), set_mode); 1150 | } 1151 | return msg; 1152 | } 1153 | 1154 | string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval, 1155 | FlagSettingMode set_mode, 1156 | bool errors_are_fatal) { 1157 | if (flagval.empty()) 1158 | return ""; 1159 | 1160 | string msg; 1161 | vector flaglist; 1162 | ParseFlagList(flagval.c_str(), &flaglist); 1163 | 1164 | for (size_t i = 0; i < flaglist.size(); ++i) { 1165 | const char* flagname = flaglist[i].c_str(); 1166 | CommandLineFlag* flag = registry_->FindFlagLocked(flagname); 1167 | if (flag == NULL) { 1168 | error_flags_[flagname] = (string(kError) + "unknown command line flag" 1169 | + " '" + flagname + "'" 1170 | + " (via --fromenv or --tryfromenv)\n"); 1171 | undefined_names_[flagname] = ""; 1172 | continue; 1173 | } 1174 | 1175 | const string envname = string("FLAGS_") + string(flagname); 1176 | const char* envval = getenv(envname.c_str()); 1177 | if (!envval) { 1178 | if (errors_are_fatal) { 1179 | error_flags_[flagname] = (string(kError) + envname + 1180 | " not found in environment\n"); 1181 | } 1182 | continue; 1183 | } 1184 | 1185 | // Avoid infinite recursion. 1186 | if ((strcmp(envval, "fromenv") == 0) || 1187 | (strcmp(envval, "tryfromenv") == 0)) { 1188 | error_flags_[flagname] = (string(kError) + "infinite recursion on " + 1189 | "environment flag '" + envval + "'\n"); 1190 | continue; 1191 | } 1192 | 1193 | msg += ProcessSingleOptionLocked(flag, envval, set_mode); 1194 | } 1195 | return msg; 1196 | } 1197 | 1198 | string CommandLineFlagParser::ProcessSingleOptionLocked( 1199 | CommandLineFlag* flag, const char* value, FlagSettingMode set_mode) { 1200 | string msg; 1201 | if (value && !registry_->SetFlagLocked(flag, value, set_mode, &msg)) { 1202 | error_flags_[flag->name()] = msg; 1203 | return ""; 1204 | } 1205 | 1206 | // The recursive flags, --flagfile and --fromenv and --tryfromenv, 1207 | // must be dealt with as soon as they're seen. They will emit 1208 | // messages of their own. 1209 | if (strcmp(flag->name(), "flagfile") == 0) { 1210 | msg += ProcessFlagfileLocked(FLAGS_flagfile, set_mode); 1211 | 1212 | } else if (strcmp(flag->name(), "fromenv") == 0) { 1213 | // last arg indicates envval-not-found is fatal (unlike in --tryfromenv) 1214 | msg += ProcessFromenvLocked(FLAGS_fromenv, set_mode, true); 1215 | 1216 | } else if (strcmp(flag->name(), "tryfromenv") == 0) { 1217 | msg += ProcessFromenvLocked(FLAGS_tryfromenv, set_mode, false); 1218 | } 1219 | 1220 | return msg; 1221 | } 1222 | 1223 | void CommandLineFlagParser::ValidateAllFlags() { 1224 | FlagRegistryLock frl(registry_); 1225 | for (FlagRegistry::FlagConstIterator i = registry_->flags_.begin(); 1226 | i != registry_->flags_.end(); ++i) { 1227 | if (!i->second->ValidateCurrent()) { 1228 | // only set a message if one isn't already there. (If there's 1229 | // an error message, our job is done, even if it's not exactly 1230 | // the same error.) 1231 | if (error_flags_[i->second->name()].empty()) 1232 | error_flags_[i->second->name()] = 1233 | string(kError) + "--" + i->second->name() + 1234 | " must be set on the commandline" 1235 | " (default value fails validation)\n"; 1236 | } 1237 | } 1238 | } 1239 | 1240 | bool CommandLineFlagParser::ReportErrors() { 1241 | // error_flags_ indicates errors we saw while parsing. 1242 | // But we ignore undefined-names if ok'ed by --undef_ok 1243 | if (!FLAGS_undefok.empty()) { 1244 | vector flaglist; 1245 | ParseFlagList(FLAGS_undefok.c_str(), &flaglist); 1246 | for (size_t i = 0; i < flaglist.size(); ++i) { 1247 | // We also deal with --no, in case the flagname was boolean 1248 | const string no_version = string("no") + flaglist[i]; 1249 | if (undefined_names_.find(flaglist[i]) != undefined_names_.end()) { 1250 | error_flags_[flaglist[i]] = ""; // clear the error message 1251 | } else if (undefined_names_.find(no_version) != undefined_names_.end()) { 1252 | error_flags_[no_version] = ""; 1253 | } 1254 | } 1255 | } 1256 | // Likewise, if they decided to allow reparsing, all undefined-names 1257 | // are ok; we just silently ignore them now, and hope that a future 1258 | // parse will pick them up somehow. 1259 | if (allow_command_line_reparsing) { 1260 | for (map::const_iterator it = undefined_names_.begin(); 1261 | it != undefined_names_.end(); ++it) 1262 | error_flags_[it->first] = ""; // clear the error message 1263 | } 1264 | 1265 | bool found_error = false; 1266 | string error_message; 1267 | for (map::const_iterator it = error_flags_.begin(); 1268 | it != error_flags_.end(); ++it) { 1269 | if (!it->second.empty()) { 1270 | error_message.append(it->second.data(), it->second.size()); 1271 | found_error = true; 1272 | } 1273 | } 1274 | if (found_error) 1275 | ReportError(DO_NOT_DIE, "%s", error_message.c_str()); 1276 | return found_error; 1277 | } 1278 | 1279 | string CommandLineFlagParser::ProcessOptionsFromStringLocked( 1280 | const string& contentdata, FlagSettingMode set_mode) { 1281 | string retval; 1282 | const char* flagfile_contents = contentdata.c_str(); 1283 | bool flags_are_relevant = true; // set to false when filenames don't match 1284 | bool in_filename_section = false; 1285 | 1286 | const char* line_end = flagfile_contents; 1287 | // We read this file a line at a time. 1288 | for (; line_end; flagfile_contents = line_end + 1) { 1289 | while (*flagfile_contents && isspace(*flagfile_contents)) 1290 | ++flagfile_contents; 1291 | line_end = strchr(flagfile_contents, '\n'); 1292 | size_t len = line_end ? static_cast(line_end - flagfile_contents) 1293 | : strlen(flagfile_contents); 1294 | string line(flagfile_contents, len); 1295 | 1296 | // Each line can be one of four things: 1297 | // 1) A comment line -- we skip it 1298 | // 2) An empty line -- we skip it 1299 | // 3) A list of filenames -- starts a new filenames+flags section 1300 | // 4) A --flag=value line -- apply if previous filenames match 1301 | if (line.empty() || line[0] == '#') { 1302 | // comment or empty line; just ignore 1303 | 1304 | } else if (line[0] == '-') { // flag 1305 | in_filename_section = false; // instead, it was a flag-line 1306 | if (!flags_are_relevant) // skip this flag; applies to someone else 1307 | continue; 1308 | 1309 | const char* name_and_val = line.c_str() + 1; // skip the leading - 1310 | if (*name_and_val == '-') 1311 | name_and_val++; // skip second - too 1312 | string key; 1313 | const char* value; 1314 | string error_message; 1315 | CommandLineFlag* flag = registry_->SplitArgumentLocked(name_and_val, 1316 | &key, &value, 1317 | &error_message); 1318 | // By API, errors parsing flagfile lines are silently ignored. 1319 | if (flag == NULL) { 1320 | // "WARNING: flagname '" + key + "' not found\n" 1321 | } else if (value == NULL) { 1322 | // "WARNING: flagname '" + key + "' missing a value\n" 1323 | } else { 1324 | retval += ProcessSingleOptionLocked(flag, value, set_mode); 1325 | } 1326 | 1327 | } else { // a filename! 1328 | if (!in_filename_section) { // start over: assume filenames don't match 1329 | in_filename_section = true; 1330 | flags_are_relevant = false; 1331 | } 1332 | 1333 | // Split the line up at spaces into glob-patterns 1334 | const char* space = line.c_str(); // just has to be non-NULL 1335 | for (const char* word = line.c_str(); *space; word = space+1) { 1336 | if (flags_are_relevant) // we can stop as soon as we match 1337 | break; 1338 | space = strchr(word, ' '); 1339 | if (space == NULL) 1340 | space = word + strlen(word); 1341 | const string glob(word, space - word); 1342 | // We try matching both against the full argv0 and basename(argv0) 1343 | #ifdef HAVE_FNMATCH_H 1344 | if (fnmatch(glob.c_str(), 1345 | ProgramInvocationName(), 1346 | FNM_PATHNAME) == 0 || 1347 | fnmatch(glob.c_str(), 1348 | ProgramInvocationShortName(), 1349 | FNM_PATHNAME) == 0) { 1350 | #else // !HAVE_FNMATCH_H 1351 | if ((glob == ProgramInvocationName()) || 1352 | (glob == ProgramInvocationShortName())) { 1353 | #endif // HAVE_FNMATCH_H 1354 | flags_are_relevant = true; 1355 | } 1356 | } 1357 | } 1358 | } 1359 | return retval; 1360 | } 1361 | 1362 | // -------------------------------------------------------------------- 1363 | // GetFromEnv() 1364 | // AddFlagValidator() 1365 | // These are helper functions for routines like BoolFromEnv() and 1366 | // RegisterFlagValidator, defined below. They're defined here so 1367 | // they can live in the unnamed namespace (which makes friendship 1368 | // declarations for these classes possible). 1369 | // -------------------------------------------------------------------- 1370 | 1371 | template 1372 | T GetFromEnv(const char *varname, const char* type, T dflt) { 1373 | const char* const valstr = getenv(varname); 1374 | if (!valstr) 1375 | return dflt; 1376 | FlagValue ifv(new T, type, true); 1377 | if (!ifv.ParseFrom(valstr)) 1378 | ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n", 1379 | varname, valstr); 1380 | return OTHER_VALUE_AS(ifv, T); 1381 | } 1382 | 1383 | bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) { 1384 | // We want a lock around this routine, in case two threads try to 1385 | // add a validator (hopefully the same one!) at once. We could use 1386 | // our own thread, but we need to loook at the registry anyway, so 1387 | // we just steal that one. 1388 | FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); 1389 | FlagRegistryLock frl(registry); 1390 | // First, find the flag whose current-flag storage is 'flag'. 1391 | // This is the CommandLineFlag whose current_->value_buffer_ == flag 1392 | CommandLineFlag* flag = registry->FindFlagViaPtrLocked(flag_ptr); 1393 | if (!flag) { 1394 | // WARNING << "Ignoring RegisterValidateFunction() for flag pointer " 1395 | // << flag_ptr << ": no flag found at that address"; 1396 | return false; 1397 | } else if (validate_fn_proto == flag->validate_function()) { 1398 | return true; // ok to register the same function over and over again 1399 | } else if (validate_fn_proto != NULL && flag->validate_function() != NULL) { 1400 | // WARNING << "Ignoring RegisterValidateFunction() for flag '" 1401 | // << flag->name() << "': validate-fn already registered"; 1402 | return false; 1403 | } else { 1404 | flag->validate_fn_proto_ = validate_fn_proto; 1405 | return true; 1406 | } 1407 | } 1408 | 1409 | } // end unnamed namespaces 1410 | 1411 | 1412 | // Now define the functions that are exported via the .h file 1413 | 1414 | // -------------------------------------------------------------------- 1415 | // FlagRegisterer 1416 | // This class exists merely to have a global constructor (the 1417 | // kind that runs before main(), that goes an initializes each 1418 | // flag that's been declared. Note that it's very important we 1419 | // don't have a destructor that deletes flag_, because that would 1420 | // cause us to delete current_storage/defvalue_storage as well, 1421 | // which can cause a crash if anything tries to access the flag 1422 | // values in a global destructor. 1423 | // -------------------------------------------------------------------- 1424 | 1425 | FlagRegisterer::FlagRegisterer(const char* name, const char* type, 1426 | const char* help, const char* filename, 1427 | void* current_storage, void* defvalue_storage) { 1428 | if (help == NULL) 1429 | help = ""; 1430 | // FlagValue expects the type-name to not include any namespace 1431 | // components, so we get rid of those, if any. 1432 | if (strchr(type, ':')) 1433 | type = strrchr(type, ':') + 1; 1434 | FlagValue* current = new FlagValue(current_storage, type, false); 1435 | FlagValue* defvalue = new FlagValue(defvalue_storage, type, false); 1436 | // Importantly, flag_ will never be deleted, so storage is always good. 1437 | CommandLineFlag* flag = new CommandLineFlag(name, help, filename, 1438 | current, defvalue); 1439 | FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry 1440 | } 1441 | 1442 | // -------------------------------------------------------------------- 1443 | // GetAllFlags() 1444 | // The main way the FlagRegistry class exposes its data. This 1445 | // returns, as strings, all the info about all the flags in 1446 | // the main registry, sorted first by filename they are defined 1447 | // in, and then by flagname. 1448 | // -------------------------------------------------------------------- 1449 | 1450 | struct FilenameFlagnameCmp { 1451 | bool operator()(const CommandLineFlagInfo& a, 1452 | const CommandLineFlagInfo& b) const { 1453 | int cmp = strcmp(a.filename.c_str(), b.filename.c_str()); 1454 | if (cmp == 0) 1455 | cmp = strcmp(a.name.c_str(), b.name.c_str()); // secondary sort key 1456 | return cmp < 0; 1457 | } 1458 | }; 1459 | 1460 | void GetAllFlags(vector* OUTPUT) { 1461 | FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); 1462 | registry->Lock(); 1463 | for (FlagRegistry::FlagConstIterator i = registry->flags_.begin(); 1464 | i != registry->flags_.end(); ++i) { 1465 | CommandLineFlagInfo fi; 1466 | i->second->FillCommandLineFlagInfo(&fi); 1467 | OUTPUT->push_back(fi); 1468 | } 1469 | registry->Unlock(); 1470 | // Now sort the flags, first by filename they occur in, then alphabetically 1471 | sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameCmp()); 1472 | } 1473 | 1474 | // -------------------------------------------------------------------- 1475 | // SetArgv() 1476 | // GetArgvs() 1477 | // GetArgv() 1478 | // GetArgv0() 1479 | // ProgramInvocationName() 1480 | // ProgramInvocationShortName() 1481 | // SetUsageMessage() 1482 | // ProgramUsage() 1483 | // Functions to set and get argv. Typically the setter is called 1484 | // by ParseCommandLineFlags. Also can get the ProgramUsage string, 1485 | // set by SetUsageMessage. 1486 | // -------------------------------------------------------------------- 1487 | 1488 | // These values are not protected by a Mutex because they are normally 1489 | // set only once during program startup. 1490 | static const char* argv0 = "UNKNOWN"; // just the program name 1491 | static const char* cmdline = ""; // the entire command-line 1492 | static vector argvs; 1493 | static uint32 argv_sum = 0; 1494 | static const char* program_usage = NULL; 1495 | 1496 | void SetArgv(int argc, const char** argv) { 1497 | static bool called_set_argv = false; 1498 | if (called_set_argv) // we already have an argv for you 1499 | return; 1500 | 1501 | called_set_argv = true; 1502 | 1503 | assert(argc > 0); // every program has at least a progname 1504 | argv0 = strdup(argv[0]); // small memory leak, but fn only called once 1505 | assert(argv0); 1506 | 1507 | string cmdline_string; // easier than doing strcats 1508 | for (int i = 0; i < argc; i++) { 1509 | if (i != 0) { 1510 | cmdline_string += " "; 1511 | } 1512 | cmdline_string += argv[i]; 1513 | argvs.push_back(argv[i]); 1514 | } 1515 | cmdline = strdup(cmdline_string.c_str()); // another small memory leak 1516 | assert(cmdline); 1517 | 1518 | // Compute a simple sum of all the chars in argv 1519 | for (const char* c = cmdline; *c; c++) 1520 | argv_sum += *c; 1521 | } 1522 | 1523 | const vector& GetArgvs() { return argvs; } 1524 | const char* GetArgv() { return cmdline; } 1525 | const char* GetArgv0() { return argv0; } 1526 | uint32 GetArgvSum() { return argv_sum; } 1527 | const char* ProgramInvocationName() { // like the GNU libc fn 1528 | return GetArgv0(); 1529 | } 1530 | const char* ProgramInvocationShortName() { // like the GNU libc fn 1531 | const char* slash = strrchr(argv0, '/'); 1532 | #ifdef OS_WINDOWS 1533 | if (!slash) slash = strrchr(argv0, '\\'); 1534 | #endif 1535 | return slash ? slash + 1 : argv0; 1536 | } 1537 | 1538 | void SetUsageMessage(const string& usage) { 1539 | if (program_usage != NULL) 1540 | ReportError(DIE, "ERROR: SetUsageMessage() called twice\n"); 1541 | program_usage = strdup(usage.c_str()); // small memory leak 1542 | } 1543 | 1544 | const char* ProgramUsage() { 1545 | if (program_usage) { 1546 | return program_usage; 1547 | } 1548 | return "Warning: SetUsageMessage() never called"; 1549 | } 1550 | 1551 | // -------------------------------------------------------------------- 1552 | // GetCommandLineOption() 1553 | // GetCommandLineFlagInfo() 1554 | // GetCommandLineFlagInfoOrDie() 1555 | // SetCommandLineOption() 1556 | // SetCommandLineOptionWithMode() 1557 | // The programmatic way to set a flag's value, using a string 1558 | // for its name rather than the variable itself (that is, 1559 | // SetCommandLineOption("foo", x) rather than FLAGS_foo = x). 1560 | // There's also a bit more flexibility here due to the various 1561 | // set-modes, but typically these are used when you only have 1562 | // that flag's name as a string, perhaps at runtime. 1563 | // All of these work on the default, global registry. 1564 | // For GetCommandLineOption, return false if no such flag 1565 | // is known, true otherwise. We clear "value" if a suitable 1566 | // flag is found. 1567 | // -------------------------------------------------------------------- 1568 | 1569 | 1570 | bool GetCommandLineOption(const char* name, string* value) { 1571 | if (NULL == name) 1572 | return false; 1573 | assert(value); 1574 | 1575 | FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); 1576 | FlagRegistryLock frl(registry); 1577 | CommandLineFlag* flag = registry->FindFlagLocked(name); 1578 | if (flag == NULL) { 1579 | return false; 1580 | } else { 1581 | *value = flag->current_value(); 1582 | return true; 1583 | } 1584 | } 1585 | 1586 | bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) { 1587 | if (NULL == name) return false; 1588 | FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); 1589 | FlagRegistryLock frl(registry); 1590 | CommandLineFlag* flag = registry->FindFlagLocked(name); 1591 | if (flag == NULL) { 1592 | return false; 1593 | } else { 1594 | assert(OUTPUT); 1595 | flag->FillCommandLineFlagInfo(OUTPUT); 1596 | return true; 1597 | } 1598 | } 1599 | 1600 | CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) { 1601 | CommandLineFlagInfo info; 1602 | if (!GetCommandLineFlagInfo(name, &info)) { 1603 | fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exist\n", name); 1604 | commandlineflags_exitfunc(1); // almost certainly exit() 1605 | } 1606 | return info; 1607 | } 1608 | 1609 | string SetCommandLineOptionWithMode(const char* name, const char* value, 1610 | FlagSettingMode set_mode) { 1611 | string result; 1612 | FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); 1613 | FlagRegistryLock frl(registry); 1614 | CommandLineFlag* flag = registry->FindFlagLocked(name); 1615 | if (flag) { 1616 | CommandLineFlagParser parser(registry); 1617 | result = parser.ProcessSingleOptionLocked(flag, value, set_mode); 1618 | if (!result.empty()) { // in the error case, we've already logged 1619 | // You could consider logging this change, if you wanted to know it: 1620 | //fprintf(stderr, "%sFLAGS_%s\n", 1621 | // (set_mode == SET_FLAGS_DEFAULT ? "default value of " : ""), 1622 | // result); 1623 | } 1624 | } 1625 | // The API of this function is that we return empty string on error 1626 | return result; 1627 | } 1628 | 1629 | string SetCommandLineOption(const char* name, const char* value) { 1630 | return SetCommandLineOptionWithMode(name, value, SET_FLAGS_VALUE); 1631 | } 1632 | 1633 | // -------------------------------------------------------------------- 1634 | // FlagSaver 1635 | // FlagSaverImpl 1636 | // This class stores the states of all flags at construct time, 1637 | // and restores all flags to that state at destruct time. 1638 | // Its major implementation challenge is that it never modifies 1639 | // pointers in the 'main' registry, so global FLAG_* vars always 1640 | // point to the right place. 1641 | // -------------------------------------------------------------------- 1642 | 1643 | class FlagSaverImpl { 1644 | public: 1645 | // Constructs an empty FlagSaverImpl object. 1646 | explicit FlagSaverImpl(FlagRegistry* main_registry) 1647 | : main_registry_(main_registry) { } 1648 | ~FlagSaverImpl() { 1649 | // reclaim memory from each of our CommandLineFlags 1650 | vector::const_iterator it; 1651 | for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) 1652 | delete *it; 1653 | } 1654 | 1655 | // Saves the flag states from the flag registry into this object. 1656 | // It's an error to call this more than once. 1657 | // Must be called when the registry mutex is not held. 1658 | void SaveFromRegistry() { 1659 | FlagRegistryLock frl(main_registry_); 1660 | assert(backup_registry_.empty()); // call only once! 1661 | for (FlagRegistry::FlagConstIterator it = main_registry_->flags_.begin(); 1662 | it != main_registry_->flags_.end(); 1663 | ++it) { 1664 | const CommandLineFlag* main = it->second; 1665 | // Sets up all the const variables in backup correctly 1666 | CommandLineFlag* backup = new CommandLineFlag( 1667 | main->name(), main->help(), main->filename(), 1668 | main->current_->New(), main->defvalue_->New()); 1669 | // Sets up all the non-const variables in backup correctly 1670 | backup->CopyFrom(*main); 1671 | backup_registry_.push_back(backup); // add it to a convenient list 1672 | } 1673 | } 1674 | 1675 | // Restores the saved flag states into the flag registry. We 1676 | // assume no flags were added or deleted from the registry since 1677 | // the SaveFromRegistry; if they were, that's trouble! Must be 1678 | // called when the registry mutex is not held. 1679 | void RestoreToRegistry() { 1680 | FlagRegistryLock frl(main_registry_); 1681 | vector::const_iterator it; 1682 | for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) { 1683 | CommandLineFlag* main = main_registry_->FindFlagLocked((*it)->name()); 1684 | if (main != NULL) { // if NULL, flag got deleted from registry(!) 1685 | main->CopyFrom(**it); 1686 | } 1687 | } 1688 | } 1689 | 1690 | private: 1691 | FlagRegistry* const main_registry_; 1692 | vector backup_registry_; 1693 | 1694 | FlagSaverImpl(const FlagSaverImpl&); // no copying! 1695 | void operator=(const FlagSaverImpl&); 1696 | }; 1697 | 1698 | FlagSaver::FlagSaver() 1699 | : impl_(new FlagSaverImpl(FlagRegistry::GlobalRegistry())) { 1700 | impl_->SaveFromRegistry(); 1701 | } 1702 | 1703 | FlagSaver::~FlagSaver() { 1704 | impl_->RestoreToRegistry(); 1705 | delete impl_; 1706 | } 1707 | 1708 | 1709 | // -------------------------------------------------------------------- 1710 | // CommandlineFlagsIntoString() 1711 | // ReadFlagsFromString() 1712 | // AppendFlagsIntoFile() 1713 | // ReadFromFlagsFile() 1714 | // These are mostly-deprecated routines that stick the 1715 | // commandline flags into a file/string and read them back 1716 | // out again. I can see a use for CommandlineFlagsIntoString, 1717 | // for creating a flagfile, but the rest don't seem that useful 1718 | // -- some, I think, are a poor-man's attempt at FlagSaver -- 1719 | // and are included only until we can delete them from callers. 1720 | // Note they don't save --flagfile flags (though they do save 1721 | // the result of having called the flagfile, of course). 1722 | // -------------------------------------------------------------------- 1723 | 1724 | static string TheseCommandlineFlagsIntoString( 1725 | const vector& flags) { 1726 | vector::const_iterator i; 1727 | 1728 | size_t retval_space = 0; 1729 | for (i = flags.begin(); i != flags.end(); ++i) { 1730 | // An (over)estimate of how much space it will take to print this flag 1731 | retval_space += i->name.length() + i->current_value.length() + 5; 1732 | } 1733 | 1734 | string retval; 1735 | retval.reserve(retval_space); 1736 | for (i = flags.begin(); i != flags.end(); ++i) { 1737 | retval += "--"; 1738 | retval += i->name; 1739 | retval += "="; 1740 | retval += i->current_value; 1741 | retval += "\n"; 1742 | } 1743 | return retval; 1744 | } 1745 | 1746 | string CommandlineFlagsIntoString() { 1747 | vector sorted_flags; 1748 | GetAllFlags(&sorted_flags); 1749 | return TheseCommandlineFlagsIntoString(sorted_flags); 1750 | } 1751 | 1752 | bool ReadFlagsFromString(const string& flagfilecontents, 1753 | const char* /*prog_name*/, // TODO(csilvers): nix this 1754 | bool errors_are_fatal) { 1755 | FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); 1756 | FlagSaverImpl saved_states(registry); 1757 | saved_states.SaveFromRegistry(); 1758 | 1759 | CommandLineFlagParser parser(registry); 1760 | registry->Lock(); 1761 | parser.ProcessOptionsFromStringLocked(flagfilecontents, SET_FLAGS_VALUE); 1762 | registry->Unlock(); 1763 | // Should we handle --help and such when reading flags from a string? Sure. 1764 | HandleCommandLineHelpFlags(); 1765 | if (parser.ReportErrors()) { 1766 | // Error. Restore all global flags to their previous values. 1767 | if (errors_are_fatal) 1768 | commandlineflags_exitfunc(1); // almost certainly exit() 1769 | saved_states.RestoreToRegistry(); 1770 | return false; 1771 | } 1772 | return true; 1773 | } 1774 | 1775 | // TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName() 1776 | bool AppendFlagsIntoFile(const string& filename, const char *prog_name) { 1777 | FILE *fp = fopen(filename.c_str(), "a"); 1778 | if (!fp) { 1779 | return false; 1780 | } 1781 | 1782 | if (prog_name) 1783 | fprintf(fp, "%s\n", prog_name); 1784 | 1785 | vector flags; 1786 | GetAllFlags(&flags); 1787 | // But we don't want --flagfile, which leads to weird recursion issues 1788 | vector::iterator i; 1789 | for (i = flags.begin(); i != flags.end(); ++i) { 1790 | if (strcmp(i->name.c_str(), "flagfile") == 0) { 1791 | flags.erase(i); 1792 | break; 1793 | } 1794 | } 1795 | fprintf(fp, "%s", TheseCommandlineFlagsIntoString(flags).c_str()); 1796 | 1797 | fclose(fp); 1798 | return true; 1799 | } 1800 | 1801 | bool ReadFromFlagsFile(const string& filename, const char* prog_name, 1802 | bool errors_are_fatal) { 1803 | return ReadFlagsFromString(ReadFileIntoString(filename.c_str()), 1804 | prog_name, errors_are_fatal); 1805 | } 1806 | 1807 | 1808 | // -------------------------------------------------------------------- 1809 | // BoolFromEnv() 1810 | // Int32FromEnv() 1811 | // Int64FromEnv() 1812 | // Uint64FromEnv() 1813 | // DoubleFromEnv() 1814 | // StringFromEnv() 1815 | // Reads the value from the environment and returns it. 1816 | // We use an FlagValue to make the parsing easy. 1817 | // Example usage: 1818 | // DEFINE_bool(myflag, BoolFromEnv("MYFLAG_DEFAULT", false), "whatever"); 1819 | // -------------------------------------------------------------------- 1820 | 1821 | bool BoolFromEnv(const char *v, bool dflt) { 1822 | return GetFromEnv(v, "bool", dflt); 1823 | } 1824 | int32 Int32FromEnv(const char *v, int32 dflt) { 1825 | return GetFromEnv(v, "int32", dflt); 1826 | } 1827 | int64 Int64FromEnv(const char *v, int64 dflt) { 1828 | return GetFromEnv(v, "int64", dflt); 1829 | } 1830 | uint64 Uint64FromEnv(const char *v, uint64 dflt) { 1831 | return GetFromEnv(v, "uint64", dflt); 1832 | } 1833 | double DoubleFromEnv(const char *v, double dflt) { 1834 | return GetFromEnv(v, "double", dflt); 1835 | } 1836 | const char *StringFromEnv(const char *varname, const char *dflt) { 1837 | const char* const val = getenv(varname); 1838 | return val ? val : dflt; 1839 | } 1840 | 1841 | 1842 | // -------------------------------------------------------------------- 1843 | // RegisterFlagValidator() 1844 | // RegisterFlagValidator() is the function that clients use to 1845 | // 'decorate' a flag with a validation function. Once this is 1846 | // done, every time the flag is set (including when the flag 1847 | // is parsed from argv), the validator-function is called. 1848 | // These functions return true if the validator was added 1849 | // successfully, or false if not: the flag already has a validator, 1850 | // (only one allowed per flag), the 1st arg isn't a flag, etc. 1851 | // This function is not thread-safe. 1852 | // -------------------------------------------------------------------- 1853 | 1854 | bool RegisterFlagValidator(const bool* flag, 1855 | bool (*validate_fn)(const char*, bool)) { 1856 | return AddFlagValidator(flag, reinterpret_cast(validate_fn)); 1857 | } 1858 | bool RegisterFlagValidator(const int32* flag, 1859 | bool (*validate_fn)(const char*, int32)) { 1860 | return AddFlagValidator(flag, reinterpret_cast(validate_fn)); 1861 | } 1862 | bool RegisterFlagValidator(const int64* flag, 1863 | bool (*validate_fn)(const char*, int64)) { 1864 | return AddFlagValidator(flag, reinterpret_cast(validate_fn)); 1865 | } 1866 | bool RegisterFlagValidator(const uint64* flag, 1867 | bool (*validate_fn)(const char*, uint64)) { 1868 | return AddFlagValidator(flag, reinterpret_cast(validate_fn)); 1869 | } 1870 | bool RegisterFlagValidator(const double* flag, 1871 | bool (*validate_fn)(const char*, double)) { 1872 | return AddFlagValidator(flag, reinterpret_cast(validate_fn)); 1873 | } 1874 | bool RegisterFlagValidator(const string* flag, 1875 | bool (*validate_fn)(const char*, const string&)) { 1876 | return AddFlagValidator(flag, reinterpret_cast(validate_fn)); 1877 | } 1878 | 1879 | 1880 | // -------------------------------------------------------------------- 1881 | // ParseCommandLineFlags() 1882 | // ParseCommandLineNonHelpFlags() 1883 | // HandleCommandLineHelpFlags() 1884 | // This is the main function called from main(), to actually 1885 | // parse the commandline. It modifies argc and argv as described 1886 | // at the top of gflags.h. You can also divide this 1887 | // function into two parts, if you want to do work between 1888 | // the parsing of the flags and the printing of any help output. 1889 | // -------------------------------------------------------------------- 1890 | 1891 | static uint32 ParseCommandLineFlagsInternal(int* argc, char*** argv, 1892 | bool remove_flags, bool do_report) { 1893 | SetArgv(*argc, const_cast(*argv)); // save it for later 1894 | 1895 | FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); 1896 | CommandLineFlagParser parser(registry); 1897 | 1898 | // When we parse the commandline flags, we'll handle --flagfile, 1899 | // --tryfromenv, etc. as we see them (since flag-evaluation order 1900 | // may be important). But sometimes apps set FLAGS_tryfromenv/etc. 1901 | // manually before calling ParseCommandLineFlags. We want to evaluate 1902 | // those too, as if they were the first flags on the commandline. 1903 | registry->Lock(); 1904 | parser.ProcessFlagfileLocked(FLAGS_flagfile, SET_FLAGS_VALUE); 1905 | // Last arg here indicates whether flag-not-found is a fatal error or not 1906 | parser.ProcessFromenvLocked(FLAGS_fromenv, SET_FLAGS_VALUE, true); 1907 | parser.ProcessFromenvLocked(FLAGS_tryfromenv, SET_FLAGS_VALUE, false); 1908 | registry->Unlock(); 1909 | 1910 | // Now get the flags specified on the commandline 1911 | const int r = parser.ParseNewCommandLineFlags(argc, argv, remove_flags); 1912 | 1913 | if (do_report) 1914 | HandleCommandLineHelpFlags(); // may cause us to exit on --help, etc. 1915 | 1916 | // See if any of the unset flags fail their validation checks 1917 | parser.ValidateAllFlags(); 1918 | 1919 | if (parser.ReportErrors()) // may cause us to exit on illegal flags 1920 | commandlineflags_exitfunc(1); // almost certainly exit() 1921 | return r; 1922 | } 1923 | 1924 | uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) { 1925 | return ParseCommandLineFlagsInternal(argc, argv, remove_flags, true); 1926 | } 1927 | 1928 | uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv, 1929 | bool remove_flags) { 1930 | return ParseCommandLineFlagsInternal(argc, argv, remove_flags, false); 1931 | } 1932 | 1933 | // -------------------------------------------------------------------- 1934 | // AllowCommandLineReparsing() 1935 | // ReparseCommandLineNonHelpFlags() 1936 | // This is most useful for shared libraries. The idea is if 1937 | // a flag is defined in a shared library that is dlopen'ed 1938 | // sometime after main(), you can ParseCommandLineFlags before 1939 | // the dlopen, then ReparseCommandLineNonHelpFlags() after the 1940 | // dlopen, to get the new flags. But you have to explicitly 1941 | // Allow() it; otherwise, you get the normal default behavior 1942 | // of unrecognized flags calling a fatal error. 1943 | // TODO(csilvers): this isn't used. Just delete it? 1944 | // -------------------------------------------------------------------- 1945 | 1946 | void AllowCommandLineReparsing() { 1947 | allow_command_line_reparsing = true; 1948 | } 1949 | 1950 | uint32 ReparseCommandLineNonHelpFlags() { 1951 | // We make a copy of argc and argv to pass in 1952 | const vector& argvs = GetArgvs(); 1953 | int tmp_argc = static_cast(argvs.size()); 1954 | char** tmp_argv = new char* [tmp_argc + 1]; 1955 | for (int i = 0; i < tmp_argc; ++i) 1956 | tmp_argv[i] = strdup(argvs[i].c_str()); // TODO(csilvers): don't dup 1957 | 1958 | const int retval = ParseCommandLineNonHelpFlags(&tmp_argc, &tmp_argv, false); 1959 | 1960 | for (int i = 0; i < tmp_argc; ++i) 1961 | free(tmp_argv[i]); 1962 | delete[] tmp_argv; 1963 | 1964 | return retval; 1965 | } 1966 | 1967 | void ShutDownCommandLineFlags() { 1968 | FlagRegistry::DeleteGlobalRegistry(); 1969 | } 1970 | 1971 | _END_GOOGLE_NAMESPACE_ 1972 | --------------------------------------------------------------------------------