39 namespace flags_internal {
56 "comma-separated list of files to load flags from")
64 if (absl::flags_internal::flagfile_needs_processing) {
68 absl::flags_internal::flagfile_needs_processing =
true;
71 "comma-separated list of flags to set from the environment" 72 " [use 'export FLAGS_flag1=value']")
80 if (absl::flags_internal::fromenv_needs_processing) {
84 absl::flags_internal::fromenv_needs_processing =
true;
87 "comma-separated list of flags to try to set from the environment if " 96 if (absl::flags_internal::tryfromenv_needs_processing) {
98 "tryfromenv set twice before it is handled.");
101 absl::flags_internal::tryfromenv_needs_processing =
true;
104 ABSL_FLAG(std::vector<std::string>, undefok, {},
105 "comma-separated list of flag names that it is okay to specify " 106 "on the command line even if the program does not define a flag " 110 namespace flags_internal {
117 ArgsList(
int argc,
char* argv[]) :
args_(argv, argv + argc),
next_arg_(0) {}
118 explicit ArgsList(
const std::vector<std::string>& args)
122 bool ReadFromFlagfile(
const std::string& flag_file_name);
125 int FrontIndex()
const {
return next_arg_; }
134 bool ArgsList::ReadFromFlagfile(
const std::string& flag_file_name) {
135 std::ifstream flag_file(flag_file_name);
139 absl::StrCat(
"Can't open flagfile ", flag_file_name),
true);
151 while (std::getline(flag_file, line)) {
154 if (stripped.
empty() || stripped[0] ==
'#') {
159 if (stripped[0] ==
'-') {
160 if (stripped ==
"--") {
162 "Flagfile can't contain position arguments or --",
true);
168 args_.push_back(std::string(stripped));
173 absl::StrCat(
"Unexpected line in the flagfile ", flag_file_name,
": ",
188 bool GetEnvVar(
const char* var_name, std::string* var_value) {
191 auto get_res = GetEnvironmentVariableA(var_name, buf,
sizeof(buf));
192 if (get_res >=
sizeof(buf)) {
200 *var_value = std::string(buf, get_res);
202 const char* val = ::getenv(var_name);
203 if (val ==
nullptr) {
225 std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue(
231 return std::make_tuple(
"",
"",
false);
234 auto equal_sign_pos = arg.
find(
"=");
239 bool is_empty_value =
false;
242 value = arg.
substr(equal_sign_pos + 1);
243 is_empty_value = value.
empty();
246 return std::make_tuple(flag_name, value, is_empty_value);
256 bool is_negative =
false;
263 return std::make_tuple(flag, is_negative);
270 void CheckDefaultValuesParsingRoundtrip() {
273 if (flag->IsRetired())
return;
275 #define IGNORE_TYPE(T) \ 276 if (flag->IsOfType<T>()) return; 285 std::string
v = flag->DefaultValue();
286 void* dst =
Clone(flag->op, flag->def);
291 absl::StrCat(
"Flag ", flag->Name(),
" (from ", flag->Filename(),
292 "): std::string form of default value '",
v,
293 "' could not be parsed; error=", error));
310 bool ReadFlagfiles(
const std::vector<std::string>& flagfiles,
311 std::vector<ArgsList>* input_args) {
313 for (
auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
316 if (al.ReadFromFlagfile(*it)) {
317 input_args->push_back(al);
331 bool ReadFlagsFromEnv(
const std::vector<std::string>& flag_names,
332 std::vector<ArgsList>* input_args,
333 bool fail_on_absent_in_env) {
335 std::vector<std::string> args;
341 for (
const auto& flag_name : flag_names) {
343 if (flag_name ==
"fromenv" || flag_name ==
"tryfromenv") {
345 absl::StrCat(
"Infinite recursion on flag ", flag_name),
true);
351 const std::string envname =
absl::StrCat(
"FLAGS_", flag_name);
353 if (!GetEnvVar(envname.c_str(), &envval)) {
354 if (fail_on_absent_in_env) {
356 absl::StrCat(envname,
" not found in environment"),
true);
364 args.push_back(
absl::StrCat(
"--", flag_name,
"=", envval));
368 input_args->emplace_back(args);
378 bool HandleGeneratorFlags(std::vector<ArgsList>* input_args,
379 std::vector<std::string>* flagfile_value) {
401 if (flags_internal::flagfile_needs_processing) {
404 if (input_args->size() == 1) {
405 flagfile_value->insert(flagfile_value->end(), flagfiles.begin(),
409 success &= ReadFlagfiles(flagfiles, input_args);
411 flags_internal::flagfile_needs_processing =
false;
417 if (flags_internal::fromenv_needs_processing) {
420 success &= ReadFlagsFromEnv(flags_list, input_args,
true);
422 flags_internal::fromenv_needs_processing =
false;
425 if (flags_internal::tryfromenv_needs_processing) {
428 success &= ReadFlagsFromEnv(flags_list, input_args,
false);
430 flags_internal::tryfromenv_needs_processing =
false;
438 void ResetGeneratorFlags(
const std::vector<std::string>& flagfile_value) {
443 if (!flagfile_value.empty()) {
446 flags_internal::flagfile_needs_processing =
false;
458 flags_internal::fromenv_needs_processing =
false;
459 flags_internal::tryfromenv_needs_processing =
false;
469 std::tuple<bool, absl::string_view> DeduceFlagValue(
const CommandLineFlag& flag,
473 ArgsList* curr_list) {
490 if (flag.IsOfType<
bool>()) {
492 if (is_empty_value) {
496 "Missing the value after assignment for the boolean flag '",
499 return std::make_tuple(
false,
"");
503 value = is_negative ?
"0" :
"1";
504 }
else if (is_negative) {
507 absl::StrCat(
"Negative form with assignment is not valid for the " 511 return std::make_tuple(
false,
"");
513 }
else if (is_negative) {
516 absl::StrCat(
"Negative form is not valid for the flag '", flag.Name(),
519 return std::make_tuple(
false,
"");
520 }
else if (value.
empty() && (!is_empty_value)) {
521 if (curr_list->Size() == 1) {
524 absl::StrCat(
"Missing the value for the flag '", flag.Name(),
"'"),
526 return std::make_tuple(
false,
"");
530 curr_list->PopFront();
531 value = curr_list->Front();
538 if (value[0] ==
'-' && flag.IsOfType<std::string>()) {
539 auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.
substr(1)));
541 if (maybe_flag_name.empty() ||
542 std::get<0>(LocateFlag(maybe_flag_name)) !=
nullptr) {
546 absl::StrCat(
"Did you really mean to set flag '", flag.Name(),
547 "' to the value '",
value,
"'?"));
552 return std::make_tuple(
true, value);
559 if (std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
564 std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
582 CheckDefaultValuesParsingRoundtrip();
584 std::vector<std::string> flagfile_value;
586 std::vector<ArgsList> input_args;
587 input_args.push_back(ArgsList(argc, argv));
589 std::vector<char*> output_args;
590 std::vector<char*> positional_args;
591 output_args.reserve(argc);
597 std::vector<std::pair<bool, std::string>> undefined_flag_names;
603 output_args.push_back(argv[0]);
609 while (!input_args.empty()) {
611 success &= HandleGeneratorFlags(&input_args, &flagfile_value);
615 ArgsList& curr_list = input_args.back();
617 curr_list.PopFront();
619 if (curr_list.Size() == 0) {
620 input_args.pop_back();
628 bool arg_from_argv = input_args.size() == 1;
634 "Flagfile cannot contain positional argument");
636 positional_args.push_back(argv[curr_list.FrontIndex()]);
641 output_args.push_back(argv[curr_list.FrontIndex()]);
651 bool is_empty_value =
false;
653 std::tie(flag_name, value, is_empty_value) = SplitNameAndValue(
arg);
657 if (flag_name.
empty()) {
659 "Flagfile cannot contain positional argument");
661 curr_list.PopFront();
667 bool is_negative =
false;
668 std::tie(flag, is_negative) = LocateFlag(flag_name);
670 if (flag ==
nullptr) {
672 undefined_flag_names.emplace_back(arg_from_argv,
673 std::string(flag_name));
679 auto curr_index = curr_list.FrontIndex();
680 bool value_success =
true;
681 std::tie(value_success, value) =
682 DeduceFlagValue(*flag, value, is_negative, is_empty_value, &curr_list);
683 success &= value_success;
687 (curr_index != curr_list.FrontIndex())) {
688 output_args.push_back(argv[curr_list.FrontIndex()]);
702 for (
const auto& flag_name : undefined_flag_names) {
703 if (CanIgnoreUndefinedFlag(flag_name.second))
continue;
706 absl::StrCat(
"Unknown command line flag '", flag_name.second,
"'"),
712 #if ABSL_FLAGS_STRIP_NAMES 715 "NOTE: command line flags are disabled in this build",
true);
727 if (exit_code != -1) {
728 std::exit(exit_code);
732 ResetGeneratorFlags(flagfile_value);
736 for (
auto arg : positional_args) {
737 output_args.push_back(
arg);
741 if (!input_args.empty()) {
742 for (
int arg_index = input_args.back().FrontIndex(); arg_index < argc;
744 output_args.push_back(argv[arg_index]);
void Delete(FlagOpFn op, const void *obj)
bool Parse(FlagMarshallingOpFn op, absl::string_view text, void *dst, std::string *error)
std::vector< char * > ParseCommandLine(int argc, char *argv[])
string_view substr(size_type pos, size_type n=npos) const
absl::Mutex * InitFlagIfNecessary(CommandLineFlag *flag) LOCK_RETURNED(flag-> locks->primary_mu)
size_type find(string_view s, size_type pos=0) const noexcept
static constexpr size_type npos
#define ABSL_INTERNAL_CHECK(condition, message)
void * Clone(FlagOpFn op, const void *obj)
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
std::vector< char * > ParseCommandLineImpl(int argc, char *argv[], ArgvListAction arg_list_act, UsageFlagsAction usage_flag_act, OnUndefinedFlag on_undef_flag)
#define ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(A)
std::vector< std::string > args_
bool SetFromString(absl::string_view value, flags_internal::FlagSettingMode set_mode, flags_internal::ValueSource source, std::string *error)
std::string ProgramInvocationName()
#define ABSL_INTERNAL_LOG(severity, message)
bool ConsumePrefix(absl::string_view *str, absl::string_view expected)
CommandLineFlag * FindCommandLineFlag(absl::string_view name)
int HandleUsageFlags(std::ostream &out)
ABSL_MUST_USE_RESULT absl::string_view StripLeadingAsciiWhitespace(absl::string_view str)
constexpr bool empty() const noexcept
void ReportUsageError(absl::string_view msg, bool is_fatal)
static ABSL_CONST_INIT std::string *program_name GUARDED_BY(program_name_guard)
void SetProgramInvocationName(absl::string_view prog_name_str)
T GetFlag(const absl::Flag< T > &flag)
ABSL_FLAG(std::vector< std::string >, flagfile,{},"comma-separated list of files to load flags from").OnUpdate([]()
void SetFlag(absl::Flag< T > *flag, const T &v)
void ForEachFlag(std::function< void(CommandLineFlag *)> visitor)