xref: /aosp_15_r20/external/libbrillo/brillo/flag_helper.h (revision 1a96fba65179ea7d3f56207137718607415c5953)
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