Home | History | Annotate | Download | only in brillo
      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