aboutsummaryrefslogtreecommitdiff
path: root/brillo/flag_helper.h
blob: 810a00c992da76129b3ea82fb1186e03f61eaa1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// 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_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 <base/command_line.h>
#include <base/macros.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 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_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();

  // Initializes the base::CommandLine class, then calls UpdateFlagValues().
  static void Init(int argc, const char* const* argv, std::string help_usage);

  // 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 exits the program with
  // exit code EX_USAGE.
  void UpdateFlagValues();

  // 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);

 private:
  FlagHelper();
  ~FlagHelper();

  // Generates a help message from the Usage Message and registered flags.
  std::string GetHelpMessage() const;

  std::string help_usage_;
  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_;

  DISALLOW_COPY_AND_ASSIGN(FlagHelper);
};

}  // namespace brillo

#endif  // LIBBRILLO_BRILLO_FLAG_HELPER_H_