| // Copyright 2014 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // This is a helper class for dealing with command line flags. It uses | |
| // base/command_line.h to parse flags from argv, but provides an API similar | |
| // to gflags. Command line arguments with either '-' or '--' prefixes are | |
| // treated as flags. Flags can optionally have a value set using an '=' | |
| // delimeter, e.g. "--flag=value". An argument of "--" will terminate flag | |
| // parsing, so that any subsequent arguments will be treated as non-flag | |
| // arguments, regardless of prefix. Non-flag arguments are outside the scope | |
| // of this class, and can instead be accessed through the GetArgs() function | |
| // of the base::CommandLine singleton after FlagHelper initialization. | |
| // | |
| // The FlagHelper class will automatically take care of the --help flag, as | |
| // well as aborting the program when unknown flags are passed to the | |
| // application and when passed in parameters cannot be correctly parsed to | |
| // their respective types. Developers define flags at compile time using the | |
| // following macros from within main(): | |
| // | |
| // DEFINE_bool(name, default_value, help) | |
| // DEFINE_int32(name, default_value, help) | |
| // DEFINE_uint32(name, default_value, help) | |
| // DEFINE_int64(name, default_value, help) | |
| // DEFINE_uint64(name, default_value, help) | |
| // DEFINE_double(name, default_value, help) | |
| // DEFINE_string(name, default_value, help) | |
| // | |
| // Using the macro will create a scoped variable of the appropriate type | |
| // with the name FLAGS_<name>, that can be used to access the flag's | |
| // value within the program. Here is an example of how the FlagHelper | |
| // class is to be used: | |
| // | |
| // -- | |
| // | |
| // #include <brillo/flag_helper.h> | |
| // #include <stdio.h> | |
| // | |
| // int main(int argc, char** argv) { | |
| // DEFINE_int32(example, 0, "Example int flag"); | |
| // brillo::FlagHelper::Init(argc, argv, "Test application."); | |
| // | |
| // printf("You passed in %d to --example command line flag\n", | |
| // FLAGS_example); | |
| // return 0; | |
| // } | |
| // | |
| // -- | |
| // | |
| // In order to update the FLAGS_xxxx values from their defaults to the | |
| // values passed in to the command line, Init(...) must be called after | |
| // all the DEFINE_xxxx macros have instantiated the variables. | |
| #ifndef LIBBRILLO_BRILLO_FLAG_HELPER_H_ | |
| #define LIBBRILLO_BRILLO_FLAG_HELPER_H_ | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <vector> | |
| #include <base/command_line.h> | |
| #include <brillo/brillo_export.h> | |
| namespace brillo { | |
| // The corresponding class representation of a command line flag, used | |
| // to keep track of pointers to the FLAGS_xxxx variables so that they | |
| // can be updated. | |
| class Flag { | |
| public: | |
| Flag(const char* name, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| virtual ~Flag() = default; | |
| // Sets the associated FLAGS_xxxx value, taking into account the flag type | |
| virtual bool SetValue(const std::string& value) = 0; | |
| // Returns the type of the flag as a char array, for use in the help message | |
| virtual const char* GetType() const = 0; | |
| const char* name_; | |
| const char* default_value_; | |
| const char* help_; | |
| bool visible_; | |
| }; | |
| class BRILLO_EXPORT BoolFlag final : public Flag { | |
| public: | |
| BoolFlag(const char* name, | |
| bool* value, | |
| bool* no_value, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| bool SetValue(const std::string& value) override; | |
| const char* GetType() const override; | |
| private: | |
| bool* value_; | |
| bool* no_value_; | |
| }; | |
| class BRILLO_EXPORT Int32Flag final : public Flag { | |
| public: | |
| Int32Flag(const char* name, | |
| int* value, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| bool SetValue(const std::string& value) override; | |
| const char* GetType() const override; | |
| private: | |
| int* value_; | |
| }; | |
| class BRILLO_EXPORT UInt32Flag final : public Flag { | |
| public: | |
| UInt32Flag(const char* name, | |
| uint32_t* value, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| bool SetValue(const std::string& value) override; | |
| const char* GetType() const override; | |
| private: | |
| uint32_t* value_; | |
| }; | |
| class BRILLO_EXPORT Int64Flag final : public Flag { | |
| public: | |
| Int64Flag(const char* name, | |
| int64_t* value, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| bool SetValue(const std::string& value) override; | |
| const char* GetType() const override; | |
| private: | |
| int64_t* value_; | |
| }; | |
| class BRILLO_EXPORT UInt64Flag final : public Flag { | |
| public: | |
| UInt64Flag(const char* name, | |
| uint64_t* value, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| bool SetValue(const std::string& value) override; | |
| const char* GetType() const override; | |
| private: | |
| uint64_t* value_; | |
| }; | |
| class BRILLO_EXPORT DoubleFlag final : public Flag { | |
| public: | |
| DoubleFlag(const char* name, | |
| double* value, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| bool SetValue(const std::string& value) override; | |
| const char* GetType() const override; | |
| private: | |
| double* value_; | |
| }; | |
| class BRILLO_EXPORT StringFlag final : public Flag { | |
| public: | |
| StringFlag(const char* name, | |
| std::string* value, | |
| const char* default_value, | |
| const char* help, | |
| bool visible); | |
| bool SetValue(const std::string& value) override; | |
| const char* GetType() const override; | |
| private: | |
| std::string* value_; | |
| }; | |
| // The following macros are to be used from within main() to create | |
| // scoped FLAGS_xxxx variables for easier access to command line flag | |
| // values. FLAGS_noxxxx variables are also created, which are used to | |
| // set bool flags to false. Creating the FLAGS_noxxxx variables here | |
| // will also ensure a compiler error will be thrown if another flag | |
| // is created with a conflicting name. | |
| #define DEFINE_type(type, classtype, name, value, help) \ | |
| type FLAGS_##name = value; \ | |
| brillo::FlagHelper::GetInstance()->AddFlag(std::unique_ptr<brillo::Flag>( \ | |
| new brillo::classtype(#name, &FLAGS_##name, #value, help, true))); | |
| #define DEFINE_int32(name, value, help) \ | |
| DEFINE_type(int, Int32Flag, name, value, help) | |
| #define DEFINE_uint32(name, value, help) \ | |
| DEFINE_type(uint32_t, UInt32Flag, name, value, help) | |
| #define DEFINE_int64(name, value, help) \ | |
| DEFINE_type(int64_t, Int64Flag, name, value, help) | |
| #define DEFINE_uint64(name, value, help) \ | |
| DEFINE_type(uint64_t, UInt64Flag, name, value, help) | |
| #define DEFINE_double(name, value, help) \ | |
| DEFINE_type(double, DoubleFlag, name, value, help) | |
| #define DEFINE_string(name, value, help) \ | |
| DEFINE_type(std::string, StringFlag, name, value, help) | |
| // Due to the FLAGS_no##name variables, can't re-use the same DEFINE_type macro | |
| // for defining bool flags | |
| #define DEFINE_bool(name, value, help) \ | |
| bool FLAGS_##name = value; \ | |
| bool FLAGS_no##name = !value; \ | |
| brillo::FlagHelper::GetInstance()->AddFlag( \ | |
| std::unique_ptr<brillo::Flag>(new brillo::BoolFlag( \ | |
| #name, &FLAGS_##name, &FLAGS_no##name, #value, help, true))); \ | |
| brillo::FlagHelper::GetInstance()->AddFlag( \ | |
| std::unique_ptr<brillo::Flag>(new brillo::BoolFlag( \ | |
| "no" #name, &FLAGS_no##name, &FLAGS_##name, #value, help, false))); | |
| // The FlagHelper class is a singleton class used for registering command | |
| // line flags and pointers to their associated scoped variables, so that | |
| // the variables can be updated once the command line arguments have been | |
| // parsed by base::CommandLine. | |
| class BRILLO_EXPORT FlagHelper final { | |
| public: | |
| // The singleton accessor function. | |
| static FlagHelper* GetInstance(); | |
| // Resets the singleton object. Developers shouldn't ever need to use this, | |
| // however it is required to be run at the end of every unit test to prevent | |
| // Flag definitions from carrying over from previous tests. | |
| static void ResetForTesting(); | |
| enum class InitFuncType { | |
| kAbort, // Always aborts. | |
| kExit, // Always exits the function with exit code. | |
| kReturn, // Always returns boolean results. | |
| }; | |
| enum class ParseFailure { | |
| kBadValue, // Bad value (e.g. string when expected int) | |
| kUnknownFlag, // Unknown name | |
| }; | |
| struct ParseResultsEntry { | |
| std::string flag_name; | |
| // to avoid uninitialized memory, give it *a* default. | |
| ParseFailure failure_type = ParseFailure::kBadValue; | |
| bool operator==(const ParseResultsEntry& other) const { | |
| return flag_name == other.flag_name && failure_type == other.failure_type; | |
| } | |
| }; | |
| // This function aborts/exits/returns based on the func_type arg. | |
| static bool Init(int argc, | |
| const char* const* argv, | |
| std::string help_usage, | |
| InitFuncType func_type = InitFuncType::kExit, | |
| std::vector<ParseResultsEntry>* out = nullptr); | |
| // Only to be used for running unit tests. | |
| void set_command_line_for_testing(base::CommandLine* command_line) { | |
| command_line_ = command_line; | |
| } | |
| // Checks all the parsed command line flags. This iterates over the switch | |
| // map from base::CommandLine, and finds the corresponding Flag in order to | |
| // update the FLAGS_xxxx values to the parsed value. If the --help flag is | |
| // passed in, it outputs a help message and exits the program. If an unknown | |
| // flag is passed in, it outputs an error message and returns exit code | |
| // EX_USAGE. | |
| int UpdateFlagValues(std::vector<ParseResultsEntry>* out = nullptr); | |
| // Adds a flag to be tracked and updated once the command line is actually | |
| // parsed. This function is an implementation detail, and is not meant | |
| // to be used directly by developers. Developers should instead use the | |
| // DEFINE_xxxx macros to register a command line flag. | |
| void AddFlag(std::unique_ptr<Flag> flag); | |
| // Sets the usage message, which is prepended to the --help message. | |
| void SetUsageMessage(std::string help_usage); | |
| // Sets the program name. | |
| void SetProgramName(std::string prog_name); | |
| private: | |
| FlagHelper(); | |
| FlagHelper(const FlagHelper&) = delete; | |
| FlagHelper& operator=(const FlagHelper&) = delete; | |
| ~FlagHelper(); | |
| // Generates a help message from the Usage Message and registered flags. | |
| std::string GetHelpMessage() const; | |
| // Returns the program name. | |
| std::string GetProgramName() const; | |
| std::string help_usage_; | |
| std::string program_name_; | |
| std::map<std::string, std::unique_ptr<Flag>> defined_flags_; | |
| // base::CommandLine object for parsing the command line switches. This | |
| // object isn't owned by this class, so don't need to delete it in the | |
| // destructor. | |
| base::CommandLine* command_line_; | |
| }; | |
| } // namespace brillo | |
| #endif // LIBBRILLO_BRILLO_FLAG_HELPER_H_ |