• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
set_command_line_for_testing(base::CommandLine * command_line)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