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