• 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 #include "brillo/flag_helper.h"
6 
7 #include <memory>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string>
11 #include <sysexits.h>
12 
13 #include <base/base_switches.h>
14 #include <base/command_line.h>
15 #include <base/logging.h>
16 #include <base/strings/stringprintf.h>
17 #include <base/strings/string_number_conversions.h>
18 
19 namespace brillo {
20 
Flag(const char * name,const char * default_value,const char * help,bool visible)21 Flag::Flag(const char* name,
22            const char* default_value,
23            const char* help,
24            bool visible)
25     : name_(name),
26       default_value_(default_value),
27       help_(help),
28       visible_(visible) {
29 }
30 
31 class HelpFlag : public brillo::Flag {
32  public:
HelpFlag()33   HelpFlag() : Flag("help", "false", "Show this help message", true) {}
34 
SetValue(const std::string &)35   bool SetValue(const std::string& /* value */) override { return true; };
GetType() const36   const char* GetType() const override { return "bool"; }
37 };
38 
BoolFlag(const char * name,bool * value,bool * no_value,const char * default_value,const char * help,bool visible)39 BoolFlag::BoolFlag(const char* name,
40                    bool* value,
41                    bool* no_value,
42                    const char* default_value,
43                    const char* help,
44                    bool visible)
45     : Flag(name, default_value, help, visible),
46       value_(value),
47       no_value_(no_value) {
48 }
49 
SetValue(const std::string & value)50 bool BoolFlag::SetValue(const std::string& value) {
51   if (value.empty()) {
52     *value_ = true;
53   } else {
54     if (!value.compare("true"))
55       *value_ = true;
56     else if (!value.compare("false"))
57       *value_ = false;
58     else
59       return false;
60   }
61 
62   *no_value_ = !*value_;
63 
64   return true;
65 }
66 
GetType() const67 const char* BoolFlag::GetType() const {
68   return "bool";
69 }
70 
Int32Flag(const char * name,int * value,const char * default_value,const char * help,bool visible)71 Int32Flag::Int32Flag(const char* name,
72                      int* value,
73                      const char* default_value,
74                      const char* help,
75                      bool visible)
76     : Flag(name, default_value, help, visible), value_(value) {
77 }
78 
SetValue(const std::string & value)79 bool Int32Flag::SetValue(const std::string& value) {
80   return base::StringToInt(value, value_);
81 }
82 
GetType() const83 const char* Int32Flag::GetType() const {
84   return "int";
85 }
86 
Int64Flag(const char * name,int64_t * value,const char * default_value,const char * help,bool visible)87 Int64Flag::Int64Flag(const char* name,
88                      int64_t* value,
89                      const char* default_value,
90                      const char* help,
91                      bool visible)
92     : Flag(name, default_value, help, visible), value_(value) {
93 }
94 
SetValue(const std::string & value)95 bool Int64Flag::SetValue(const std::string& value) {
96   return base::StringToInt64(value, value_);
97 }
98 
GetType() const99 const char* Int64Flag::GetType() const {
100   return "int64";
101 }
102 
UInt64Flag(const char * name,uint64_t * value,const char * default_value,const char * help,bool visible)103 UInt64Flag::UInt64Flag(const char* name,
104                        uint64_t* value,
105                        const char* default_value,
106                        const char* help,
107                        bool visible)
108     : Flag(name, default_value, help, visible), value_(value) {
109 }
110 
SetValue(const std::string & value)111 bool UInt64Flag::SetValue(const std::string& value) {
112   return base::StringToUint64(value, value_);
113 }
114 
GetType() const115 const char* UInt64Flag::GetType() const {
116   return "uint64";
117 }
118 
DoubleFlag(const char * name,double * value,const char * default_value,const char * help,bool visible)119 DoubleFlag::DoubleFlag(const char* name,
120                        double* value,
121                        const char* default_value,
122                        const char* help,
123                        bool visible)
124     : Flag(name, default_value, help, visible), value_(value) {
125 }
126 
SetValue(const std::string & value)127 bool DoubleFlag::SetValue(const std::string& value) {
128   return base::StringToDouble(value, value_);
129 }
130 
GetType() const131 const char* DoubleFlag::GetType() const {
132   return "double";
133 }
134 
StringFlag(const char * name,std::string * value,const char * default_value,const char * help,bool visible)135 StringFlag::StringFlag(const char* name,
136                        std::string* value,
137                        const char* default_value,
138                        const char* help,
139                        bool visible)
140     : Flag(name, default_value, help, visible), value_(value) {
141 }
142 
SetValue(const std::string & value)143 bool StringFlag::SetValue(const std::string& value) {
144   value_->assign(value);
145 
146   return true;
147 }
148 
GetType() const149 const char* StringFlag::GetType() const {
150   return "string";
151 }
152 
153 namespace {
154 brillo::FlagHelper* instance_ = nullptr;
155 }  // namespace
156 
FlagHelper()157 FlagHelper::FlagHelper() : command_line_(nullptr) {
158   AddFlag(std::unique_ptr<Flag>(new HelpFlag()));
159 }
160 
~FlagHelper()161 FlagHelper::~FlagHelper() {
162 }
163 
GetInstance()164 brillo::FlagHelper* FlagHelper::GetInstance() {
165   if (!instance_)
166     instance_ = new FlagHelper();
167 
168   return instance_;
169 }
170 
ResetForTesting()171 void FlagHelper::ResetForTesting() {
172   delete instance_;
173   instance_ = nullptr;
174 }
175 
Init(int argc,const char * const * argv,std::string help_usage)176 void FlagHelper::Init(int argc,
177                       const char* const* argv,
178                       std::string help_usage) {
179   brillo::FlagHelper* helper = GetInstance();
180   if (!helper->command_line_) {
181     if (!base::CommandLine::InitializedForCurrentProcess())
182       base::CommandLine::Init(argc, argv);
183     helper->command_line_ = base::CommandLine::ForCurrentProcess();
184   }
185 
186   GetInstance()->SetUsageMessage(help_usage);
187 
188   GetInstance()->UpdateFlagValues();
189 }
190 
UpdateFlagValues()191 void FlagHelper::UpdateFlagValues() {
192   std::string error_msg;
193   int error_code = EX_OK;
194 
195   // Check that base::CommandLine has been initialized.
196   CHECK(base::CommandLine::InitializedForCurrentProcess());
197 
198   // If the --help flag exists, print out help message and exit.
199   if (command_line_->HasSwitch("help")) {
200     puts(GetHelpMessage().c_str());
201     exit(EX_OK);
202   }
203 
204   // Iterate over the base::CommandLine switches.  Update the value
205   // of the corresponding Flag if it exists, or output an error message
206   // if the flag wasn't defined.
207   const base::CommandLine::SwitchMap& switch_map = command_line_->GetSwitches();
208 
209   for (const auto& pair : switch_map) {
210     const std::string& key = pair.first;
211     // Make sure we allow the standard logging switches (--v and --vmodule).
212     if (key == switches::kV || key == switches::kVModule)
213       continue;
214 
215     const std::string& value = pair.second;
216 
217     auto df_it = defined_flags_.find(key);
218     if (df_it != defined_flags_.end()) {
219       Flag* flag = df_it->second.get();
220       if (!flag->SetValue(value)) {
221         base::StringAppendF(
222             &error_msg,
223             "ERROR: illegal value '%s' specified for %s flag '%s'\n",
224             value.c_str(),
225             flag->GetType(),
226             flag->name_);
227         error_code = EX_DATAERR;
228       }
229     } else {
230       base::StringAppendF(
231           &error_msg, "ERROR: unknown command line flag '%s'\n", key.c_str());
232       error_code = EX_USAGE;
233     }
234   }
235 
236   if (error_code != EX_OK) {
237     puts(error_msg.c_str());
238     exit(error_code);
239   }
240 }
241 
AddFlag(std::unique_ptr<Flag> flag)242 void FlagHelper::AddFlag(std::unique_ptr<Flag> flag) {
243   defined_flags_.emplace(flag->name_, std::move(flag));
244 }
245 
SetUsageMessage(std::string help_usage)246 void FlagHelper::SetUsageMessage(std::string help_usage) {
247   help_usage_.assign(std::move(help_usage));
248 }
249 
GetHelpMessage() const250 std::string FlagHelper::GetHelpMessage() const {
251   std::string help = help_usage_;
252   help.append("\n\n");
253   for (const auto& pair : defined_flags_) {
254     const Flag* flag = pair.second.get();
255     if (flag->visible_) {
256       base::StringAppendF(&help,
257                           "  --%s  (%s)  type: %s  default: %s\n",
258                           flag->name_,
259                           flag->help_,
260                           flag->GetType(),
261                           flag->default_value_);
262     }
263   }
264   return help;
265 }
266 
267 }  // namespace brillo
268