* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "datasystem/common/flags/flag_manager.h"
#include <cerrno>
#include <cmath>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <mutex>
#include <securec.h>
#include <stdarg.h>
#include <string>
#include <type_traits>
#include <utility>
#include <securec.h>
#include "datasystem/common/flags/string_to_long.h"
#include "datasystem/common/util/format.h"
#include "datasystem/utils/embedded_config.h"
#include "datasystem/utils/kv_client_config.h"
DS_DECLARE_bool(help);
DS_DECLARE_bool(version);
#define ugly_exit exit
#define TREAT_VALUE_AS(type, value) (*reinterpret_cast<type *>(value))
#define TREAT_VALIDATOR_AS(type, validator, name, value) \
(reinterpret_cast<bool (*)(const char *, type)>(validator)(name, TREAT_VALUE_AS(const type, value)))
namespace datasystem {
const int K_DOUBLE_STR_PRECISION = 15;
char one[2] = { '1', '\0' };
void ReportError(const char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stdout, format, ap);
va_end(ap);
fflush(stdout);
}
bool Flag::Assign(const std::string &value, std::string &errMsg)
{
bool success;
switch (type_) {
case FLAG_BOOL:
success = ParseAssignFromBoolean(value, errMsg);
break;
case FLAG_UINT32:
success = ParseAssignFromUint32(value, errMsg);
break;
case FLAG_INT32:
success = ParseAssignFromInt32(value, errMsg);
break;
case FLAG_UINT64:
success = ParseAssignFromUint64(value, errMsg);
break;
case FLAG_INT64:
success = ParseAssignFromInt64(value, errMsg);
break;
case FLAG_STRING:
success = ParseAssignFromString(value, errMsg);
break;
case FLAG_DOUBLE:
success = ParseAssignFromDouble(value, errMsg);
break;
default:
success = false;
}
if (success) {
wasSpecified_ = true;
}
return success;
}
bool Flag::IsValidate(const void *value) const
{
if (validator_ == nullptr) {
return true;
}
value = value != nullptr ? value : currentVal_;
switch (type_) {
case FLAG_BOOL:
return TREAT_VALIDATOR_AS(bool, validator_, name_.c_str(), value);
case FLAG_UINT32:
return TREAT_VALIDATOR_AS(uint32_t, validator_, name_.c_str(), value);
case FLAG_INT32:
return TREAT_VALIDATOR_AS(int32_t, validator_, name_.c_str(), value);
case FLAG_UINT64:
return TREAT_VALIDATOR_AS(uint64_t, validator_, name_.c_str(), value);
case FLAG_INT64:
return TREAT_VALIDATOR_AS(int64_t, validator_, name_.c_str(), value);
case FLAG_STRING:
return TREAT_VALIDATOR_AS(std::string, validator_, name_.c_str(), value);
case FLAG_DOUBLE:
return TREAT_VALIDATOR_AS(double, validator_, name_.c_str(), value);
default:
return false;
}
}
std::string Flag::TypeName() const
{
switch (type_) {
case FLAG_BOOL:
return "bool";
case FLAG_UINT32:
return "uint32";
case FLAG_INT32:
return "int32";
case FLAG_UINT64:
return "uint64";
case FLAG_INT64:
return "int64";
case FLAG_STRING:
return "string";
case FLAG_DOUBLE:
return "double";
default:
return "Unknown";
}
}
std::string Flag::ValueString() const
{
switch (type_) {
case FLAG_BOOL:
return std::to_string(TREAT_VALUE_AS(bool, currentVal_));
case FLAG_UINT32:
return std::to_string(TREAT_VALUE_AS(uint32_t, currentVal_));
case FLAG_INT32:
return std::to_string(TREAT_VALUE_AS(int32_t, currentVal_));
case FLAG_UINT64:
return std::to_string(TREAT_VALUE_AS(uint64_t, currentVal_));
case FLAG_INT64:
return std::to_string(TREAT_VALUE_AS(int64_t, currentVal_));
case FLAG_STRING:
return TREAT_VALUE_AS(std::string, currentVal_);
case FLAG_DOUBLE: {
char buf[32];
sprintf_s(buf, sizeof(buf), "%.15g", TREAT_VALUE_AS(double, currentVal_));
return std::string(buf);
}
default:
return "Unknown";
}
}
void Flag::UpdateModified()
{
switch (type_) {
case FLAG_BOOL:
modified_ = (TREAT_VALUE_AS(bool, currentVal_) != TREAT_VALUE_AS(bool, defaultVal_));
break;
case FLAG_UINT32:
modified_ = (TREAT_VALUE_AS(uint32_t, currentVal_) != TREAT_VALUE_AS(uint32_t, defaultVal_));
break;
case FLAG_INT32:
modified_ = (TREAT_VALUE_AS(int32_t, currentVal_) != TREAT_VALUE_AS(int32_t, defaultVal_));
break;
case FLAG_UINT64:
modified_ = (TREAT_VALUE_AS(uint64_t, currentVal_) != TREAT_VALUE_AS(uint64_t, defaultVal_));
break;
case FLAG_INT64:
modified_ = (TREAT_VALUE_AS(int64_t, currentVal_) != TREAT_VALUE_AS(int64_t, defaultVal_));
break;
case FLAG_STRING:
modified_ = (TREAT_VALUE_AS(std::string, currentVal_) != TREAT_VALUE_AS(std::string, defaultVal_));
break;
case FLAG_DOUBLE:
modified_ = (fabs(TREAT_VALUE_AS(double, currentVal_) - TREAT_VALUE_AS(double, defaultVal_)) > 1e-12);
break;
default:
break;
}
}
namespace {
const char *kTrue[] = { "1", "t", "true", "y", "yes" };
const char *kFalse[] = { "0", "f", "false", "n", "no" };
bool HasOnlyTrailingSpaces(const std::string &value, std::size_t pos)
{
while (pos < value.size()) {
if (!std::isspace(static_cast<unsigned char>(value[pos]))) {
return false;
}
++pos;
}
return true;
}
template <typename T>
struct AlwaysFalse : public std::false_type {};
template <typename IntegerType>
bool ParseIntegerStrict(const std::string &value, IntegerType &res)
{
std::size_t pos = 0;
if constexpr (std::is_same_v<IntegerType, uint32_t>) {
unsigned long parsed = StrToUnsignedLong(value, &pos);
res = static_cast<uint32_t>(parsed);
if (static_cast<unsigned long>(res) != parsed) {
return false;
}
} else if constexpr (std::is_same_v<IntegerType, int32_t>) {
res = std::stoi(value, &pos);
} else if constexpr (std::is_same_v<IntegerType, uint64_t>) {
res = StrToUnsignedLongLong(value, &pos);
} else if constexpr (std::is_same_v<IntegerType, int64_t>) {
res = std::stoll(value, &pos);
} else {
static_assert(AlwaysFalse<IntegerType>::value, "Unsupported integer type");
}
return HasOnlyTrailingSpaces(value, pos);
}
}
bool Flag::ParseAssignFromBoolean(const std::string &value, std::string &errMsg)
{
static_assert(sizeof(kTrue) == sizeof(kFalse), "True false equal");
if (value.empty()) {
errMsg = IllegalValueMessage(value);
return false;
}
bool res = false;
bool success = false;
for (size_t i = 0; i < sizeof(kTrue) / sizeof(*kTrue); ++i) {
if (strcasecmp(value.c_str(), kTrue[i]) == 0) {
res = true;
success = true;
break;
} else if (strcasecmp(value.c_str(), kFalse[i]) == 0) {
res = false;
success = true;
break;
}
}
if (!success) {
errMsg = IllegalValueMessage(value);
return false;
}
success = IsValidate(reinterpret_cast<const void *>(&res));
if (success) {
TREAT_VALUE_AS(bool, currentVal_) = res;
UpdateModified();
} else {
errMsg = ValidateFailureMessage();
}
return success;
}
bool Flag::ParseAssignFromUint32(const std::string &value, std::string &errMsg)
{
if (value.empty() || value[0] == '-') {
errMsg = IllegalValueMessage(value);
return false;
}
uint32_t res;
bool success = false;
try {
success = ParseIntegerStrict<uint32_t>(value, res);
} catch (std::invalid_argument &e) {
success = false;
} catch (const std::out_of_range &e) {
success = false;
}
if (!success) {
errMsg = IllegalValueMessage(value);
return false;
}
success = IsValidate(reinterpret_cast<const void *>(&res));
if (success) {
TREAT_VALUE_AS(uint32_t, currentVal_) = res;
UpdateModified();
} else {
errMsg = ValidateFailureMessage();
}
return success;
}
bool Flag::ParseAssignFromInt32(const std::string &value, std::string &errMsg)
{
if (value.empty()) {
errMsg = IllegalValueMessage(value);
return false;
}
int32_t res;
bool success = false;
try {
success = ParseIntegerStrict<int32_t>(value, res);
} catch (std::invalid_argument &e) {
success = false;
} catch (const std::out_of_range &e) {
success = false;
}
if (!success) {
errMsg = IllegalValueMessage(value);
return false;
}
success = IsValidate(reinterpret_cast<const void *>(&res));
if (success) {
TREAT_VALUE_AS(int32_t, currentVal_) = res;
UpdateModified();
} else {
errMsg = ValidateFailureMessage();
}
return success;
}
bool Flag::ParseAssignFromUint64(const std::string &value, std::string &errMsg)
{
if (value.empty() || value[0] == '-') {
errMsg = IllegalValueMessage(value);
return false;
}
uint64_t res;
bool success = false;
try {
success = ParseIntegerStrict<uint64_t>(value, res);
} catch (std::invalid_argument &e) {
success = false;
} catch (const std::out_of_range &e) {
success = false;
}
if (!success) {
errMsg = IllegalValueMessage(value);
return false;
}
success = IsValidate(reinterpret_cast<const void *>(&res));
if (success) {
TREAT_VALUE_AS(uint64_t, currentVal_) = res;
UpdateModified();
} else {
errMsg = ValidateFailureMessage();
}
return success;
}
bool Flag::ParseAssignFromInt64(const std::string &value, std::string &errMsg)
{
if (value.empty()) {
errMsg = IllegalValueMessage(value);
return false;
}
int64_t res;
bool success = false;
try {
success = ParseIntegerStrict<int64_t>(value, res);
} catch (std::invalid_argument &e) {
success = false;
} catch (const std::out_of_range &e) {
success = false;
}
if (!success) {
errMsg = IllegalValueMessage(value);
return false;
}
success = IsValidate(reinterpret_cast<const void *>(&res));
if (success) {
TREAT_VALUE_AS(int64_t, currentVal_) = res;
UpdateModified();
} else {
errMsg = ValidateFailureMessage();
}
return success;
}
bool Flag::ParseAssignFromString(const std::string &value, std::string &errMsg)
{
bool success = IsValidate(static_cast<const void *>(&value));
if (success) {
TREAT_VALUE_AS(std::string, currentVal_) = value;
UpdateModified();
} else {
errMsg = ValidateFailureMessage();
}
return success;
}
bool Flag::ParseAssignFromDouble(const std::string &value, std::string &errMsg)
{
char *end;
errno = 0;
double parsed = strtod(value.c_str(), &end);
if (errno != 0 || end == value.c_str() || *end != '\0' || !std::isfinite(parsed)) {
errMsg = IllegalValueMessage(value);
return false;
}
bool success = IsValidate(static_cast<const void *>(&parsed));
if (success) {
TREAT_VALUE_AS(double, currentVal_) = parsed;
UpdateModified();
} else {
errMsg = ValidateFailureMessage();
}
return success;
}
std::string Flag::IllegalValueMessage(const std::string &value) const
{
return "Error: illegal value '" + value + "' specified for " + TypeName() + " flag '" + name_ + "' \n";
}
std::string Flag::ValidateFailureMessage() const
{
return "Error: failed validation of new value '" + ValueString() + "' for flag '" + name_ + "'\n";
}
FlagManager *FlagManager::GetInstance()
{
static FlagManager manager;
return &manager;
}
bool FlagManager::ParseCommandLineFlagsFromArgsLocked(const std::unordered_map<std::string, std::string> &args,
std::string &errMsg)
{
errorFlags_.clear();
unknownFlags_.clear();
for (const auto &flagKv : args) {
if (flagKv.first == "connectTimeoutMs") {
continue;
}
auto it = flagMap_.find(flagKv.first);
if (it == flagMap_.end()) {
(void)unknownFlags_.emplace(flagKv.first, "ERROR: unknown command line flag '" + flagKv.first + "'\n");
continue;
}
auto &flag = it->second;
if (flagKv.second.empty()) {
errorFlags_[flagKv.first] =
"Error: flag '" + flagKv.first + "' is missing its argument; flag description: " + flag.meaning_ + "\n";
continue;
}
(void)AssignFlagValue(flag, flagKv.second);
}
ValidateDefaultFlagsLocked();
if (CheckAndReportErrors(errMsg)) {
return false;
}
return true;
}
bool FlagManager::ParseCommandLineFlags(const std::unordered_map<std::string, std::string> &args, std::string &errMsg)
{
std::lock_guard<std::mutex> l(mutex_);
return ParseCommandLineFlagsFromArgsLocked(args, errMsg);
}
bool FlagManager::ParseCommandLineFlags(const EmbeddedConfig &config, std::string &errMsg)
{
std::lock_guard<std::mutex> l(mutex_);
return ParseCommandLineFlagsFromArgsLocked(config.GetArgs(), errMsg);
}
bool FlagManager::ParseCommandLineFlags(const KVClientConfig &config, std::string &errMsg)
{
std::lock_guard<std::mutex> l(mutex_);
return ParseCommandLineFlagsFromArgsLocked(config.GetArgs(), errMsg);
}
void FlagManager::ParseCommandLineFlags(int argc, char **argv)
{
if (argc == 0 || argv == nullptr || *argv == nullptr) {
ReportError("Illegal command line arguments");
ugly_exit(1);
}
argv0_ = argv[0];
std::lock_guard<std::mutex> l(mutex_);
for (int i = 1; i < argc; ++i) {
auto *arg = argv[i];
if (arg[0] != '-' || arg[1] == '\0') {
continue;
}
arg++;
if (arg[0] == '-') {
arg++;
}
if (arg[0] == '\0') {
break;
}
std::string key;
char *value = nullptr;
ParseFlagValue(arg, key, &value);
auto it = flagMap_.find(key);
if (it == flagMap_.end()) {
(void)unknownFlags_.emplace(key, "ERROR: unknown command line flag '" + key + "'\n");
continue;
}
auto &flag = it->second;
if (value == nullptr) {
if (i + 1 >= argc) {
errorFlags_[key] =
"Error: flag '" + key + "' is missing its argument; flag description: " + flag.meaning_ + "\n";
break;
} else {
value = argv[i + 1];
++i;
}
}
std::string errMsg;
(void)AssignFlagValue(flag, value);
}
if (NeedPrintHelpfulMessage(argv[0])) {
ugly_exit(1);
}
ValidateDefaultFlagsLocked();
std::string unUseErrMsg;
if (CheckAndReportErrors(unUseErrMsg)) {
ugly_exit(1);
}
}
std::string FlagManager::ProgramInvocationShortName()
{
size_t pos = argv0_.rfind('/');
return (pos == std::string::npos ? argv0_ : std::string(argv0_.c_str() + pos + 1));
}
void FlagManager::GetAllFlags(std::vector<FlagInfo> &output) const
{
std::lock_guard<std::mutex> l(mutex_);
for (const auto &entry : flagMap_) {
const auto &flag = entry.second;
FlagInfo info{ .type = flag.TypeName(),
.name = flag.name_,
.meaning = flag.meaning_,
.filename = flag.filename_,
.value = flag.ValueString(),
.isDefault = !flag.IsModified(),
.wasSpecified = flag.wasSpecified_ };
output.emplace_back(std::move(info));
}
}
bool FlagManager::WasFlagSpecified(const char *name) const
{
if (name == nullptr) {
return false;
}
std::lock_guard<std::mutex> l(mutex_);
auto it = flagMap_.find(name);
if (it == flagMap_.end()) {
return false;
}
return it->second.wasSpecified_;
}
bool FlagManager::IsModifiableFlag(const std::string &name) const
{
std::lock_guard<std::mutex> l(mutex_);
auto it = flagMap_.find(name);
if (it == flagMap_.end()) {
return false;
}
return it->second.modifiable_;
}
struct FlagManager::FlagValueSnapshot {
bool wasSpecified{false};
bool modified{false};
bool boolVal{false};
uint32_t uint32Val{0};
int32_t int32Val{0};
uint64_t uint64Val{0};
int64_t int64Val{0};
std::string stringVal;
double doubleVal{0.0};
};
bool FlagManager::readCurrentIntoSnapshot(const Flag &flag, FlagValueSnapshot &snapshot, const std::string &name,
std::string &errMsg) const
{
snapshot.wasSpecified = flag.wasSpecified_;
snapshot.modified = flag.modified_;
switch (flag.type_) {
case FLAG_BOOL:
snapshot.boolVal = TREAT_VALUE_AS(bool, flag.currentVal_);
return true;
case FLAG_UINT32:
snapshot.uint32Val = TREAT_VALUE_AS(uint32_t, flag.currentVal_);
return true;
case FLAG_INT32:
snapshot.int32Val = TREAT_VALUE_AS(int32_t, flag.currentVal_);
return true;
case FLAG_UINT64:
snapshot.uint64Val = TREAT_VALUE_AS(uint64_t, flag.currentVal_);
return true;
case FLAG_INT64:
snapshot.int64Val = TREAT_VALUE_AS(int64_t, flag.currentVal_);
return true;
case FLAG_STRING:
snapshot.stringVal = TREAT_VALUE_AS(std::string, flag.currentVal_);
return true;
case FLAG_DOUBLE:
snapshot.doubleVal = TREAT_VALUE_AS(double, flag.currentVal_);
return true;
default:
errMsg = "flag '" + name + "' has unsupported type";
return false;
}
}
void FlagManager::writeSnapshotIntoFlag(Flag &flag, const FlagValueSnapshot &snapshot) const
{
switch (flag.type_) {
case FLAG_BOOL:
TREAT_VALUE_AS(bool, flag.currentVal_) = snapshot.boolVal;
break;
case FLAG_UINT32:
TREAT_VALUE_AS(uint32_t, flag.currentVal_) = snapshot.uint32Val;
break;
case FLAG_INT32:
TREAT_VALUE_AS(int32_t, flag.currentVal_) = snapshot.int32Val;
break;
case FLAG_UINT64:
TREAT_VALUE_AS(uint64_t, flag.currentVal_) = snapshot.uint64Val;
break;
case FLAG_INT64:
TREAT_VALUE_AS(int64_t, flag.currentVal_) = snapshot.int64Val;
break;
case FLAG_STRING:
TREAT_VALUE_AS(std::string, flag.currentVal_) = snapshot.stringVal;
break;
case FLAG_DOUBLE:
TREAT_VALUE_AS(double, flag.currentVal_) = snapshot.doubleVal;
break;
default:
break;
}
flag.wasSpecified_ = snapshot.wasSpecified;
flag.modified_ = snapshot.modified;
}
bool FlagManager::tryAssignWithRollback(Flag &flag, const std::string &newVal, std::string &errMsg)
{
FlagValueSnapshot snapshot;
if (!readCurrentIntoSnapshot(flag, snapshot, flag.name_, errMsg)) {
return false;
}
if (!flag.Assign(newVal, errMsg)) {
return false;
}
writeSnapshotIntoFlag(flag, snapshot);
return true;
}
bool FlagManager::ValidateChange(const std::string &name, const std::string &newVal, std::string &errMsg)
{
std::lock_guard<std::mutex> l(mutex_);
auto it = flagMap_.find(name);
if (it == flagMap_.end()) {
errMsg = "flag '" + name + "' not found!";
return false;
}
auto &flag = it->second;
if (!flag.modifiable_) {
errMsg = "flag '" + name + "' not modifiable";
return false;
}
return tryAssignWithRollback(flag, newVal, errMsg);
}
void FlagManager::GetModifiableFlagNames(std::vector<std::string> &out) const
{
out.clear();
std::lock_guard<std::mutex> l(mutex_);
for (const auto &entry : flagMap_) {
if (entry.second.modifiable_) {
out.emplace_back(entry.first);
}
}
}
void FlagManager::SetVersionString(const std::string &version)
{
version_ = version;
}
void FlagManager::SetUsageMessage(const std::string &description)
{
description_ = description;
}
void FlagManager::RegisterFlag(const std::string &name, FlagType type, const std::string &meaning,
const std::string &filename, void *currentVal, void *defaultVal, bool modifiable)
{
Flag flag(type, name, meaning, filename, currentVal, defaultVal, modifiable);
std::lock_guard<std::mutex> l(mutex_);
auto pair = flagMap_.emplace(name, flag);
if (!pair.second) {
const auto &existedFlag = pair.first->second;
if (flag.filename_ != pair.first->second.filename_) {
ReportError("ERROR: flag '%s' was defined more than once (inf file '%s' and '%s')\n", name.c_str(),
flag.filename_.c_str(), pair.first->second.filename_.c_str());
} else {
if (existedFlag.currentVal_ == currentVal) {
return;
}
ReportError(
"ERROR: register flag '%s' in file '%s' meets error. One possibility: file '%s' is being linked both "
"staticallyand dynamically into this executable.\n",
name.c_str(), flag.filename_.c_str(), flag.filename_.c_str());
}
ugly_exit(1);
}
(void)flagPtrMap_.emplace(currentVal, &pair.first->second);
}
bool FlagManager::RegisterValidator(void *flag, void *func)
{
std::lock_guard<std::mutex> l(mutex_);
auto it = flagPtrMap_.find(flag);
if (it == flagPtrMap_.end()) {
ReportError("WARNING: Ignore register validator for flag: no flag found\n");
return false;
} else if (func == it->second->validator_) {
return true;
} else if (func != nullptr && it->second->validator_ != nullptr) {
ReportError("WARNING: Ignore register validator for flag %s: validator already registered\n",
it->second->name_.c_str());
return false;
} else {
it->second->validator_ = func;
if (it->second->currentVal_ != nullptr) {
it->second->IsValidate(it->second->currentVal_);
}
return true;
}
}
bool FlagManager::FindAndAssignFlagValue(const char *name, const std::string &value, std::string &errMsg)
{
if (name == nullptr) {
errMsg = "name or value is nullptr";
return false;
}
std::lock_guard<std::mutex> l(mutex_);
auto it = flagMap_.find(name);
if (it == flagMap_.end()) {
errMsg = "flag '" + std::string(name) + "' not found!";
return false;
}
auto &flag = it->second;
return flag.Assign(value, errMsg);
}
bool FlagManager::FindAndGetFlagValue(const char *name, std::string &output)
{
if (name == nullptr) {
return false;
}
std::lock_guard<std::mutex> l(mutex_);
auto it = flagMap_.find(name);
if (it == flagMap_.end()) {
return false;
}
output = it->second.ValueString();
return true;
}
bool FlagManager::NeedPrintHelpfulMessage(const char *argv0)
{
if (!FLAGS_help && !FLAGS_version) {
return false;
}
const char *basename = std::strrchr(argv0, '/');
basename = basename == nullptr ? argv0 : basename + 1;
std::stringstream ss;
ss << std::string(basename) << ": " << description_;
if (FLAGS_help) {
ss << "\n";
for (const auto &entry : flagMap_) {
const auto &flag = entry.second;
ss << " -" << flag.name_ << " (" << flag.meaning_ << ")"
<< "\n type: " << flag.TypeName() << " default: ";
if (flag.TypeName() == "string") {
ss << "\"" << flag.ValueString() << "\"\n";
} else {
ss << flag.ValueString() << "\n";
}
}
} else if (FLAGS_version) {
ss << " version: " << version_ << "\n";
}
ReportError("%s", ss.str().c_str());
return true;
}
void FlagManager::ValidateDefaultFlagsLocked()
{
for (auto it = flagMap_.begin(); it != flagMap_.end(); ++it) {
auto &flag = it->second;
if (flag.IsModified()) {
continue;
}
if (!errorFlags_[flag.name_].empty()) {
continue;
}
if (flag.IsValidate()) {
continue;
}
errorFlags_[flag.name_] = "Error: failed validation of default value for flag '" + flag.name_ + "'\n";
}
}
void FlagManager::ParseFlagValue(char *arg, std::string &flag, char **value)
{
auto *res = std::strchr(arg, '=');
if (res == nullptr) {
flag = arg;
} else {
flag.assign(arg, res - arg);
*value = res + 1;
}
if (flag == "help" || flag == "version") {
*value = one;
}
}
void FlagManager::AssignFlagValue(Flag &flag, const std::string &value)
{
std::string errMsg;
bool success = flag.Assign(value, errMsg);
if (!success) {
errorFlags_[flag.name_] =
"Error: illegal value '" + value + "' specified for " + flag.TypeName() + " flag '" + flag.name_ + "' \n";
}
}
bool FlagManager::CheckAndReportErrors(std::string &errMsg) const
{
bool error = false;
std::stringstream ss;
for (const auto &entry : errorFlags_) {
if (!entry.second.empty()) {
ss << entry.second;
error = true;
}
}
for (const auto &entry : unknownFlags_) {
if (!entry.second.empty()) {
ss << entry.second;
error = true;
}
}
errMsg = ss.str();
if (error) {
ReportError("%s", ss.str().c_str());
}
return error;
}
}