1 // Copyright 2014 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // This is a helper class for dealing with command line flags. It uses 6 // base/command_line.h to parse flags from argv, but provides an API similar 7 // to gflags. Command line arguments with either '-' or '--' prefixes are 8 // treated as flags. Flags can optionally have a value set using an '=' 9 // delimeter, e.g. "--flag=value". An argument of "--" will terminate flag 10 // parsing, so that any subsequent arguments will be treated as non-flag 11 // arguments, regardless of prefix. Non-flag arguments are outside the scope 12 // of this class, and can instead be accessed through the GetArgs() function 13 // of the base::CommandLine singleton after FlagHelper initialization. 14 // 15 // The FlagHelper class will automatically take care of the --help flag, as 16 // well as aborting the program when unknown flags are passed to the 17 // application and when passed in parameters cannot be correctly parsed to 18 // their respective types. Developers define flags at compile time using the 19 // following macros from within main(): 20 // 21 // DEFINE_bool(name, default_value, help) 22 // DEFINE_int32(name, default_value, help) 23 // DEFINE_int64(name, default_value, help) 24 // DEFINE_uint64(name, default_value, help) 25 // DEFINE_double(name, default_value, help) 26 // DEFINE_string(name, default_value, help) 27 // 28 // Using the macro will create a scoped variable of the appropriate type 29 // with the name FLAGS_<name>, that can be used to access the flag's 30 // value within the program. Here is an example of how the FlagHelper 31 // class is to be used: 32 // 33 // -- 34 // 35 // #include <brillo/flag_helper.h> 36 // #include <stdio.h> 37 // 38 // int main(int argc, char** argv) { 39 // DEFINE_int32(example, 0, "Example int flag"); 40 // brillo::FlagHelper::Init(argc, argv, "Test application."); 41 // 42 // printf("You passed in %d to --example command line flag\n", 43 // FLAGS_example); 44 // return 0; 45 // } 46 // 47 // -- 48 // 49 // In order to update the FLAGS_xxxx values from their defaults to the 50 // values passed in to the command line, Init(...) must be called after 51 // all the DEFINE_xxxx macros have instantiated the variables. 52 53 #ifndef LIBBRILLO_BRILLO_FLAG_HELPER_H_ 54 #define LIBBRILLO_BRILLO_FLAG_HELPER_H_ 55 56 #include <map> 57 #include <memory> 58 #include <string> 59 60 #include <base/command_line.h> 61 #include <base/macros.h> 62 #include <brillo/brillo_export.h> 63 64 namespace brillo { 65 66 // The corresponding class representation of a command line flag, used 67 // to keep track of pointers to the FLAGS_xxxx variables so that they 68 // can be updated. 69 class Flag { 70 public: 71 Flag(const char* name, 72 const char* default_value, 73 const char* help, 74 bool visible); 75 virtual ~Flag() = default; 76 77 // Sets the associated FLAGS_xxxx value, taking into account the flag type 78 virtual bool SetValue(const std::string& value) = 0; 79 80 // Returns the type of the flag as a char array, for use in the help message 81 virtual const char* GetType() const = 0; 82 83 const char* name_; 84 const char* default_value_; 85 const char* help_; 86 bool visible_; 87 }; 88 89 class BRILLO_EXPORT BoolFlag final : public Flag { 90 public: 91 BoolFlag(const char* name, 92 bool* value, 93 bool* no_value, 94 const char* default_value, 95 const char* help, 96 bool visible); 97 bool SetValue(const std::string& value) override; 98 99 const char* GetType() const override; 100 101 private: 102 bool* value_; 103 bool* no_value_; 104 }; 105 106 class BRILLO_EXPORT Int32Flag final : public Flag { 107 public: 108 Int32Flag(const char* name, 109 int* value, 110 const char* default_value, 111 const char* help, 112 bool visible); 113 bool SetValue(const std::string& value) override; 114 115 const char* GetType() const override; 116 117 private: 118 int* value_; 119 }; 120 121 class BRILLO_EXPORT Int64Flag final : public Flag { 122 public: 123 Int64Flag(const char* name, 124 int64_t* value, 125 const char* default_value, 126 const char* help, 127 bool visible); 128 bool SetValue(const std::string& value) override; 129 130 const char* GetType() const override; 131 132 private: 133 int64_t* value_; 134 }; 135 136 class BRILLO_EXPORT UInt64Flag final : public Flag { 137 public: 138 UInt64Flag(const char* name, 139 uint64_t* value, 140 const char* default_value, 141 const char* help, 142 bool visible); 143 bool SetValue(const std::string& value) override; 144 145 const char* GetType() const override; 146 147 private: 148 uint64_t* value_; 149 }; 150 151 class BRILLO_EXPORT DoubleFlag final : public Flag { 152 public: 153 DoubleFlag(const char* name, 154 double* value, 155 const char* default_value, 156 const char* help, 157 bool visible); 158 bool SetValue(const std::string& value) override; 159 160 const char* GetType() const override; 161 162 private: 163 double* value_; 164 }; 165 166 class BRILLO_EXPORT StringFlag final : public Flag { 167 public: 168 StringFlag(const char* name, 169 std::string* value, 170 const char* default_value, 171 const char* help, 172 bool visible); 173 bool SetValue(const std::string& value) override; 174 175 const char* GetType() const override; 176 177 private: 178 std::string* value_; 179 }; 180 181 // The following macros are to be used from within main() to create 182 // scoped FLAGS_xxxx variables for easier access to command line flag 183 // values. FLAGS_noxxxx variables are also created, which are used to 184 // set bool flags to false. Creating the FLAGS_noxxxx variables here 185 // will also ensure a compiler error will be thrown if another flag 186 // is created with a conflicting name. 187 #define DEFINE_type(type, classtype, name, value, help) \ 188 type FLAGS_##name = value; \ 189 brillo::FlagHelper::GetInstance()->AddFlag(std::unique_ptr<brillo::Flag>( \ 190 new brillo::classtype(#name, &FLAGS_##name, #value, help, true))); 191 192 #define DEFINE_int32(name, value, help) \ 193 DEFINE_type(int, Int32Flag, name, value, help) 194 #define DEFINE_int64(name, value, help) \ 195 DEFINE_type(int64_t, Int64Flag, name, value, help) 196 #define DEFINE_uint64(name, value, help) \ 197 DEFINE_type(uint64_t, UInt64Flag, name, value, help) 198 #define DEFINE_double(name, value, help) \ 199 DEFINE_type(double, DoubleFlag, name, value, help) 200 #define DEFINE_string(name, value, help) \ 201 DEFINE_type(std::string, StringFlag, name, value, help) 202 203 // Due to the FLAGS_no##name variables, can't re-use the same DEFINE_type macro 204 // for defining bool flags 205 #define DEFINE_bool(name, value, help) \ 206 bool FLAGS_##name = value; \ 207 bool FLAGS_no##name = !value; \ 208 brillo::FlagHelper::GetInstance()->AddFlag( \ 209 std::unique_ptr<brillo::Flag>(new brillo::BoolFlag( \ 210 #name, &FLAGS_##name, &FLAGS_no##name, #value, help, true))); \ 211 brillo::FlagHelper::GetInstance()->AddFlag( \ 212 std::unique_ptr<brillo::Flag>(new brillo::BoolFlag( \ 213 "no" #name, &FLAGS_no##name, &FLAGS_##name, #value, help, false))); 214 215 // The FlagHelper class is a singleton class used for registering command 216 // line flags and pointers to their associated scoped variables, so that 217 // the variables can be updated once the command line arguments have been 218 // parsed by base::CommandLine. 219 class BRILLO_EXPORT FlagHelper final { 220 public: 221 // The singleton accessor function. 222 static FlagHelper* GetInstance(); 223 224 // Resets the singleton object. Developers shouldn't ever need to use this, 225 // however it is required to be run at the end of every unit test to prevent 226 // Flag definitions from carrying over from previous tests. 227 static void ResetForTesting(); 228 229 // Initializes the base::CommandLine class, then calls UpdateFlagValues(). 230 static void Init(int argc, const char* const* argv, std::string help_usage); 231 232 // Only to be used for running unit tests. 233 void set_command_line_for_testing(base::CommandLine* command_line) { 234 command_line_ = command_line; 235 } 236 237 // Checks all the parsed command line flags. This iterates over the switch 238 // map from base::CommandLine, and finds the corresponding Flag in order to 239 // update the FLAGS_xxxx values to the parsed value. If the --help flag is 240 // passed in, it outputs a help message and exits the program. If an unknown 241 // flag is passed in, it outputs an error message and exits the program with 242 // exit code EX_USAGE. 243 void UpdateFlagValues(); 244 245 // Adds a flag to be tracked and updated once the command line is actually 246 // parsed. This function is an implementation detail, and is not meant 247 // to be used directly by developers. Developers should instead use the 248 // DEFINE_xxxx macros to register a command line flag. 249 void AddFlag(std::unique_ptr<Flag> flag); 250 251 // Sets the usage message, which is prepended to the --help message. 252 void SetUsageMessage(std::string help_usage); 253 254 private: 255 FlagHelper(); 256 ~FlagHelper(); 257 258 // Generates a help message from the Usage Message and registered flags. 259 std::string GetHelpMessage() const; 260 261 std::string help_usage_; 262 std::map<std::string, std::unique_ptr<Flag>> defined_flags_; 263 264 // base::CommandLine object for parsing the command line switches. This 265 // object isn't owned by this class, so don't need to delete it in the 266 // destructor. 267 base::CommandLine* command_line_; 268 269 DISALLOW_COPY_AND_ASSIGN(FlagHelper); 270 }; 271 272 } // namespace brillo 273 274 #endif // LIBBRILLO_BRILLO_FLAG_HELPER_H_ 275