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