You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
6.9 KiB
267 lines
6.9 KiB
// 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. |
|
|
|
#include "brillo/flag_helper.h" |
|
|
|
#include <memory> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string> |
|
#include <sysexits.h> |
|
|
|
#include <base/base_switches.h> |
|
#include <base/command_line.h> |
|
#include <base/logging.h> |
|
#include <base/strings/stringprintf.h> |
|
#include <base/strings/string_number_conversions.h> |
|
|
|
namespace brillo { |
|
|
|
Flag::Flag(const char* name, |
|
const char* default_value, |
|
const char* help, |
|
bool visible) |
|
: name_(name), |
|
default_value_(default_value), |
|
help_(help), |
|
visible_(visible) { |
|
} |
|
|
|
class HelpFlag : public brillo::Flag { |
|
public: |
|
HelpFlag() : Flag("help", "false", "Show this help message", true) {} |
|
|
|
bool SetValue(const std::string& /* value */) override { return true; }; |
|
const char* GetType() const override { return "bool"; } |
|
}; |
|
|
|
BoolFlag::BoolFlag(const char* name, |
|
bool* value, |
|
bool* no_value, |
|
const char* default_value, |
|
const char* help, |
|
bool visible) |
|
: Flag(name, default_value, help, visible), |
|
value_(value), |
|
no_value_(no_value) { |
|
} |
|
|
|
bool BoolFlag::SetValue(const std::string& value) { |
|
if (value.empty()) { |
|
*value_ = true; |
|
} else { |
|
if (!value.compare("true")) |
|
*value_ = true; |
|
else if (!value.compare("false")) |
|
*value_ = false; |
|
else |
|
return false; |
|
} |
|
|
|
*no_value_ = !*value_; |
|
|
|
return true; |
|
} |
|
|
|
const char* BoolFlag::GetType() const { |
|
return "bool"; |
|
} |
|
|
|
Int32Flag::Int32Flag(const char* name, |
|
int* value, |
|
const char* default_value, |
|
const char* help, |
|
bool visible) |
|
: Flag(name, default_value, help, visible), value_(value) { |
|
} |
|
|
|
bool Int32Flag::SetValue(const std::string& value) { |
|
return base::StringToInt(value, value_); |
|
} |
|
|
|
const char* Int32Flag::GetType() const { |
|
return "int"; |
|
} |
|
|
|
Int64Flag::Int64Flag(const char* name, |
|
int64_t* value, |
|
const char* default_value, |
|
const char* help, |
|
bool visible) |
|
: Flag(name, default_value, help, visible), value_(value) { |
|
} |
|
|
|
bool Int64Flag::SetValue(const std::string& value) { |
|
return base::StringToInt64(value, value_); |
|
} |
|
|
|
const char* Int64Flag::GetType() const { |
|
return "int64"; |
|
} |
|
|
|
UInt64Flag::UInt64Flag(const char* name, |
|
uint64_t* value, |
|
const char* default_value, |
|
const char* help, |
|
bool visible) |
|
: Flag(name, default_value, help, visible), value_(value) { |
|
} |
|
|
|
bool UInt64Flag::SetValue(const std::string& value) { |
|
return base::StringToUint64(value, value_); |
|
} |
|
|
|
const char* UInt64Flag::GetType() const { |
|
return "uint64"; |
|
} |
|
|
|
DoubleFlag::DoubleFlag(const char* name, |
|
double* value, |
|
const char* default_value, |
|
const char* help, |
|
bool visible) |
|
: Flag(name, default_value, help, visible), value_(value) { |
|
} |
|
|
|
bool DoubleFlag::SetValue(const std::string& value) { |
|
return base::StringToDouble(value, value_); |
|
} |
|
|
|
const char* DoubleFlag::GetType() const { |
|
return "double"; |
|
} |
|
|
|
StringFlag::StringFlag(const char* name, |
|
std::string* value, |
|
const char* default_value, |
|
const char* help, |
|
bool visible) |
|
: Flag(name, default_value, help, visible), value_(value) { |
|
} |
|
|
|
bool StringFlag::SetValue(const std::string& value) { |
|
value_->assign(value); |
|
|
|
return true; |
|
} |
|
|
|
const char* StringFlag::GetType() const { |
|
return "string"; |
|
} |
|
|
|
namespace { |
|
brillo::FlagHelper* instance_ = nullptr; |
|
} // namespace |
|
|
|
FlagHelper::FlagHelper() : command_line_(nullptr) { |
|
AddFlag(std::unique_ptr<Flag>(new HelpFlag())); |
|
} |
|
|
|
FlagHelper::~FlagHelper() { |
|
} |
|
|
|
brillo::FlagHelper* FlagHelper::GetInstance() { |
|
if (!instance_) |
|
instance_ = new FlagHelper(); |
|
|
|
return instance_; |
|
} |
|
|
|
void FlagHelper::ResetForTesting() { |
|
delete instance_; |
|
instance_ = nullptr; |
|
} |
|
|
|
void FlagHelper::Init(int argc, |
|
const char* const* argv, |
|
std::string help_usage) { |
|
brillo::FlagHelper* helper = GetInstance(); |
|
if (!helper->command_line_) { |
|
if (!base::CommandLine::InitializedForCurrentProcess()) |
|
base::CommandLine::Init(argc, argv); |
|
helper->command_line_ = base::CommandLine::ForCurrentProcess(); |
|
} |
|
|
|
GetInstance()->SetUsageMessage(help_usage); |
|
|
|
GetInstance()->UpdateFlagValues(); |
|
} |
|
|
|
void FlagHelper::UpdateFlagValues() { |
|
std::string error_msg; |
|
int error_code = EX_OK; |
|
|
|
// Check that base::CommandLine has been initialized. |
|
CHECK(base::CommandLine::InitializedForCurrentProcess()); |
|
|
|
// If the --help flag exists, print out help message and exit. |
|
if (command_line_->HasSwitch("help")) { |
|
puts(GetHelpMessage().c_str()); |
|
exit(EX_OK); |
|
} |
|
|
|
// Iterate over the base::CommandLine switches. Update the value |
|
// of the corresponding Flag if it exists, or output an error message |
|
// if the flag wasn't defined. |
|
const base::CommandLine::SwitchMap& switch_map = command_line_->GetSwitches(); |
|
|
|
for (const auto& pair : switch_map) { |
|
const std::string& key = pair.first; |
|
// Make sure we allow the standard logging switches (--v and --vmodule). |
|
if (key == switches::kV || key == switches::kVModule) |
|
continue; |
|
|
|
const std::string& value = pair.second; |
|
|
|
auto df_it = defined_flags_.find(key); |
|
if (df_it != defined_flags_.end()) { |
|
Flag* flag = df_it->second.get(); |
|
if (!flag->SetValue(value)) { |
|
base::StringAppendF( |
|
&error_msg, |
|
"ERROR: illegal value '%s' specified for %s flag '%s'\n", |
|
value.c_str(), |
|
flag->GetType(), |
|
flag->name_); |
|
error_code = EX_DATAERR; |
|
} |
|
} else { |
|
base::StringAppendF( |
|
&error_msg, "ERROR: unknown command line flag '%s'\n", key.c_str()); |
|
error_code = EX_USAGE; |
|
} |
|
} |
|
|
|
if (error_code != EX_OK) { |
|
puts(error_msg.c_str()); |
|
exit(error_code); |
|
} |
|
} |
|
|
|
void FlagHelper::AddFlag(std::unique_ptr<Flag> flag) { |
|
defined_flags_.emplace(flag->name_, std::move(flag)); |
|
} |
|
|
|
void FlagHelper::SetUsageMessage(std::string help_usage) { |
|
help_usage_.assign(std::move(help_usage)); |
|
} |
|
|
|
std::string FlagHelper::GetHelpMessage() const { |
|
std::string help = help_usage_; |
|
help.append("\n\n"); |
|
for (const auto& pair : defined_flags_) { |
|
const Flag* flag = pair.second.get(); |
|
if (flag->visible_) { |
|
base::StringAppendF(&help, |
|
" --%s (%s) type: %s default: %s\n", |
|
flag->name_, |
|
flag->help_, |
|
flag->GetType(), |
|
flag->default_value_); |
|
} |
|
} |
|
return help; |
|
} |
|
|
|
} // namespace brillo
|
|
|