00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "absl/flags/parse.h"
00017
00018 #include <stdlib.h>
00019 #include <fstream>
00020 #include <iostream>
00021 #include <tuple>
00022
00023 #ifdef _WIN32
00024 #include <windows.h>
00025 #endif
00026
00027 #include "absl/flags/flag.h"
00028 #include "absl/flags/internal/program_name.h"
00029 #include "absl/flags/internal/registry.h"
00030 #include "absl/flags/internal/usage.h"
00031 #include "absl/flags/usage_config.h"
00032 #include "absl/strings/str_cat.h"
00033 #include "absl/strings/strip.h"
00034 #include "absl/synchronization/mutex.h"
00035
00036
00037
00038 namespace absl {
00039 namespace flags_internal {
00040 namespace {
00041
00042 ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit);
00043
00044 ABSL_CONST_INIT bool flagfile_needs_processing
00045 GUARDED_BY(processing_checks_guard) = false;
00046 ABSL_CONST_INIT bool fromenv_needs_processing
00047 GUARDED_BY(processing_checks_guard) = false;
00048 ABSL_CONST_INIT bool tryfromenv_needs_processing
00049 GUARDED_BY(processing_checks_guard) = false;
00050
00051 }
00052 }
00053 }
00054
00055 ABSL_FLAG(std::vector<std::string>, flagfile, {},
00056 "comma-separated list of files to load flags from")
00057 .OnUpdate([]() {
00058 if (absl::GetFlag(FLAGS_flagfile).empty()) return;
00059
00060 absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
00061
00062
00063
00064 if (absl::flags_internal::flagfile_needs_processing) {
00065 ABSL_INTERNAL_LOG(WARNING, "flagfile set twice before it is handled");
00066 }
00067
00068 absl::flags_internal::flagfile_needs_processing = true;
00069 });
00070 ABSL_FLAG(std::vector<std::string>, fromenv, {},
00071 "comma-separated list of flags to set from the environment"
00072 " [use 'export FLAGS_flag1=value']")
00073 .OnUpdate([]() {
00074 if (absl::GetFlag(FLAGS_fromenv).empty()) return;
00075
00076 absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
00077
00078
00079
00080 if (absl::flags_internal::fromenv_needs_processing) {
00081 ABSL_INTERNAL_LOG(WARNING, "fromenv set twice before it is handled.");
00082 }
00083
00084 absl::flags_internal::fromenv_needs_processing = true;
00085 });
00086 ABSL_FLAG(std::vector<std::string>, tryfromenv, {},
00087 "comma-separated list of flags to try to set from the environment if "
00088 "present")
00089 .OnUpdate([]() {
00090 if (absl::GetFlag(FLAGS_tryfromenv).empty()) return;
00091
00092 absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
00093
00094
00095
00096 if (absl::flags_internal::tryfromenv_needs_processing) {
00097 ABSL_INTERNAL_LOG(WARNING,
00098 "tryfromenv set twice before it is handled.");
00099 }
00100
00101 absl::flags_internal::tryfromenv_needs_processing = true;
00102 });
00103
00104 ABSL_FLAG(std::vector<std::string>, undefok, {},
00105 "comma-separated list of flag names that it is okay to specify "
00106 "on the command line even if the program does not define a flag "
00107 "with that name");
00108
00109 namespace absl {
00110 namespace flags_internal {
00111
00112 namespace {
00113
00114 class ArgsList {
00115 public:
00116 ArgsList() : next_arg_(0) {}
00117 ArgsList(int argc, char* argv[]) : args_(argv, argv + argc), next_arg_(0) {}
00118 explicit ArgsList(const std::vector<std::string>& args)
00119 : args_(args), next_arg_(0) {}
00120
00121
00122 bool ReadFromFlagfile(const std::string& flag_file_name);
00123
00124 int Size() const { return args_.size() - next_arg_; }
00125 int FrontIndex() const { return next_arg_; }
00126 absl::string_view Front() const { return args_[next_arg_]; }
00127 void PopFront() { next_arg_++; }
00128
00129 private:
00130 std::vector<std::string> args_;
00131 int next_arg_;
00132 };
00133
00134 bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) {
00135 std::ifstream flag_file(flag_file_name);
00136
00137 if (!flag_file) {
00138 flags_internal::ReportUsageError(
00139 absl::StrCat("Can't open flagfile ", flag_file_name), true);
00140
00141 return false;
00142 }
00143
00144
00145
00146 args_.push_back("");
00147
00148 std::string line;
00149 bool success = true;
00150
00151 while (std::getline(flag_file, line)) {
00152 absl::string_view stripped = absl::StripLeadingAsciiWhitespace(line);
00153
00154 if (stripped.empty() || stripped[0] == '#') {
00155
00156 continue;
00157 }
00158
00159 if (stripped[0] == '-') {
00160 if (stripped == "--") {
00161 flags_internal::ReportUsageError(
00162 "Flagfile can't contain position arguments or --", true);
00163
00164 success = false;
00165 break;
00166 }
00167
00168 args_.push_back(std::string(stripped));
00169 continue;
00170 }
00171
00172 flags_internal::ReportUsageError(
00173 absl::StrCat("Unexpected line in the flagfile ", flag_file_name, ": ",
00174 line),
00175 true);
00176
00177 success = false;
00178 }
00179
00180 return success;
00181 }
00182
00183
00184
00185
00186
00187
00188 bool GetEnvVar(const char* var_name, std::string* var_value) {
00189 #ifdef _WIN32
00190 char buf[1024];
00191 auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
00192 if (get_res >= sizeof(buf)) {
00193 return false;
00194 }
00195
00196 if (get_res == 0) {
00197 return false;
00198 }
00199
00200 *var_value = std::string(buf, get_res);
00201 #else
00202 const char* val = ::getenv(var_name);
00203 if (val == nullptr) {
00204 return false;
00205 }
00206
00207 *var_value = val;
00208 #endif
00209
00210 return true;
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue(
00226 absl::string_view arg) {
00227
00228 absl::ConsumePrefix(&arg, "-");
00229
00230 if (arg.empty()) {
00231 return std::make_tuple("", "", false);
00232 }
00233
00234 auto equal_sign_pos = arg.find("=");
00235
00236 absl::string_view flag_name = arg.substr(0, equal_sign_pos);
00237
00238 absl::string_view value;
00239 bool is_empty_value = false;
00240
00241 if (equal_sign_pos != absl::string_view::npos) {
00242 value = arg.substr(equal_sign_pos + 1);
00243 is_empty_value = value.empty();
00244 }
00245
00246 return std::make_tuple(flag_name, value, is_empty_value);
00247 }
00248
00249
00250
00251
00252
00253
00254 std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
00255 CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
00256 bool is_negative = false;
00257
00258 if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
00259 flag = flags_internal::FindCommandLineFlag(flag_name);
00260 is_negative = true;
00261 }
00262
00263 return std::make_tuple(flag, is_negative);
00264 }
00265
00266
00267
00268
00269
00270 void CheckDefaultValuesParsingRoundtrip() {
00271 #ifndef NDEBUG
00272 flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
00273 if (flag->IsRetired()) return;
00274
00275 #define IGNORE_TYPE(T) \
00276 if (flag->IsOfType<T>()) return;
00277
00278 ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(IGNORE_TYPE)
00279 IGNORE_TYPE(std::string)
00280 IGNORE_TYPE(std::vector<std::string>)
00281 #undef IGNORE_TYPE
00282
00283 absl::MutexLock lock(InitFlagIfNecessary(flag));
00284
00285 std::string v = flag->DefaultValue();
00286 void* dst = Clone(flag->op, flag->def);
00287 std::string error;
00288 if (!flags_internal::Parse(flag->marshalling_op, v, dst, &error)) {
00289 ABSL_INTERNAL_LOG(
00290 FATAL,
00291 absl::StrCat("Flag ", flag->Name(), " (from ", flag->Filename(),
00292 "): std::string form of default value '", v,
00293 "' could not be parsed; error=", error));
00294 }
00295
00296
00297
00298 Delete(flag->op, dst);
00299 });
00300 #endif
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310 bool ReadFlagfiles(const std::vector<std::string>& flagfiles,
00311 std::vector<ArgsList>* input_args) {
00312 bool success = true;
00313 for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
00314 ArgsList al;
00315
00316 if (al.ReadFromFlagfile(*it)) {
00317 input_args->push_back(al);
00318 } else {
00319 success = false;
00320 }
00321 }
00322
00323 return success;
00324 }
00325
00326
00327
00328
00329
00330
00331 bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names,
00332 std::vector<ArgsList>* input_args,
00333 bool fail_on_absent_in_env) {
00334 bool success = true;
00335 std::vector<std::string> args;
00336
00337
00338
00339 args.push_back("");
00340
00341 for (const auto& flag_name : flag_names) {
00342
00343 if (flag_name == "fromenv" || flag_name == "tryfromenv") {
00344 flags_internal::ReportUsageError(
00345 absl::StrCat("Infinite recursion on flag ", flag_name), true);
00346
00347 success = false;
00348 continue;
00349 }
00350
00351 const std::string envname = absl::StrCat("FLAGS_", flag_name);
00352 std::string envval;
00353 if (!GetEnvVar(envname.c_str(), &envval)) {
00354 if (fail_on_absent_in_env) {
00355 flags_internal::ReportUsageError(
00356 absl::StrCat(envname, " not found in environment"), true);
00357
00358 success = false;
00359 }
00360
00361 continue;
00362 }
00363
00364 args.push_back(absl::StrCat("--", flag_name, "=", envval));
00365 }
00366
00367 if (success) {
00368 input_args->emplace_back(args);
00369 }
00370
00371 return success;
00372 }
00373
00374
00375
00376
00377
00378 bool HandleGeneratorFlags(std::vector<ArgsList>* input_args,
00379 std::vector<std::string>* flagfile_value) {
00380 bool success = true;
00381
00382 absl::MutexLock l(&flags_internal::processing_checks_guard);
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 if (flags_internal::flagfile_needs_processing) {
00402 auto flagfiles = absl::GetFlag(FLAGS_flagfile);
00403
00404 if (input_args->size() == 1) {
00405 flagfile_value->insert(flagfile_value->end(), flagfiles.begin(),
00406 flagfiles.end());
00407 }
00408
00409 success &= ReadFlagfiles(flagfiles, input_args);
00410
00411 flags_internal::flagfile_needs_processing = false;
00412 }
00413
00414
00415
00416
00417 if (flags_internal::fromenv_needs_processing) {
00418 auto flags_list = absl::GetFlag(FLAGS_fromenv);
00419
00420 success &= ReadFlagsFromEnv(flags_list, input_args, true);
00421
00422 flags_internal::fromenv_needs_processing = false;
00423 }
00424
00425 if (flags_internal::tryfromenv_needs_processing) {
00426 auto flags_list = absl::GetFlag(FLAGS_tryfromenv);
00427
00428 success &= ReadFlagsFromEnv(flags_list, input_args, false);
00429
00430 flags_internal::tryfromenv_needs_processing = false;
00431 }
00432
00433 return success;
00434 }
00435
00436
00437
00438 void ResetGeneratorFlags(const std::vector<std::string>& flagfile_value) {
00439
00440
00441
00442
00443 if (!flagfile_value.empty()) {
00444 absl::SetFlag(&FLAGS_flagfile, flagfile_value);
00445 absl::MutexLock l(&flags_internal::processing_checks_guard);
00446 flags_internal::flagfile_needs_processing = false;
00447 }
00448
00449
00450 if (!absl::GetFlag(FLAGS_fromenv).empty()) {
00451 absl::SetFlag(&FLAGS_fromenv, {});
00452 }
00453 if (!absl::GetFlag(FLAGS_tryfromenv).empty()) {
00454 absl::SetFlag(&FLAGS_tryfromenv, {});
00455 }
00456
00457 absl::MutexLock l(&flags_internal::processing_checks_guard);
00458 flags_internal::fromenv_needs_processing = false;
00459 flags_internal::tryfromenv_needs_processing = false;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469 std::tuple<bool, absl::string_view> DeduceFlagValue(const CommandLineFlag& flag,
00470 absl::string_view value,
00471 bool is_negative,
00472 bool is_empty_value,
00473 ArgsList* curr_list) {
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 if (flag.IsOfType<bool>()) {
00491 if (value.empty()) {
00492 if (is_empty_value) {
00493
00494 flags_internal::ReportUsageError(
00495 absl::StrCat(
00496 "Missing the value after assignment for the boolean flag '",
00497 flag.Name(), "'"),
00498 true);
00499 return std::make_tuple(false, "");
00500 }
00501
00502
00503 value = is_negative ? "0" : "1";
00504 } else if (is_negative) {
00505
00506 flags_internal::ReportUsageError(
00507 absl::StrCat("Negative form with assignment is not valid for the "
00508 "boolean flag '",
00509 flag.Name(), "'"),
00510 true);
00511 return std::make_tuple(false, "");
00512 }
00513 } else if (is_negative) {
00514
00515 flags_internal::ReportUsageError(
00516 absl::StrCat("Negative form is not valid for the flag '", flag.Name(),
00517 "'"),
00518 true);
00519 return std::make_tuple(false, "");
00520 } else if (value.empty() && (!is_empty_value)) {
00521 if (curr_list->Size() == 1) {
00522
00523 flags_internal::ReportUsageError(
00524 absl::StrCat("Missing the value for the flag '", flag.Name(), "'"),
00525 true);
00526 return std::make_tuple(false, "");
00527 }
00528
00529
00530 curr_list->PopFront();
00531 value = curr_list->Front();
00532
00533
00534
00535
00536
00537
00538 if (value[0] == '-' && flag.IsOfType<std::string>()) {
00539 auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
00540
00541 if (maybe_flag_name.empty() ||
00542 std::get<0>(LocateFlag(maybe_flag_name)) != nullptr) {
00543
00544 ABSL_INTERNAL_LOG(
00545 WARNING,
00546 absl::StrCat("Did you really mean to set flag '", flag.Name(),
00547 "' to the value '", value, "'?"));
00548 }
00549 }
00550 }
00551
00552 return std::make_tuple(true, value);
00553 }
00554
00555
00556
00557 bool CanIgnoreUndefinedFlag(absl::string_view flag_name) {
00558 auto undefok = absl::GetFlag(FLAGS_undefok);
00559 if (std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
00560 return true;
00561 }
00562
00563 if (absl::ConsumePrefix(&flag_name, "no") &&
00564 std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
00565 return true;
00566 }
00567
00568 return false;
00569 }
00570
00571 }
00572
00573
00574
00575 std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
00576 ArgvListAction arg_list_act,
00577 UsageFlagsAction usage_flag_act,
00578 OnUndefinedFlag on_undef_flag) {
00579 ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
00580
00581
00582 CheckDefaultValuesParsingRoundtrip();
00583
00584 std::vector<std::string> flagfile_value;
00585
00586 std::vector<ArgsList> input_args;
00587 input_args.push_back(ArgsList(argc, argv));
00588
00589 std::vector<char*> output_args;
00590 std::vector<char*> positional_args;
00591 output_args.reserve(argc);
00592
00593
00594
00595
00596
00597 std::vector<std::pair<bool, std::string>> undefined_flag_names;
00598
00599
00600 if (ProgramInvocationName() == "UNKNOWN") {
00601 flags_internal::SetProgramInvocationName(argv[0]);
00602 }
00603 output_args.push_back(argv[0]);
00604
00605
00606
00607
00608 bool success = true;
00609 while (!input_args.empty()) {
00610
00611 success &= HandleGeneratorFlags(&input_args, &flagfile_value);
00612
00613
00614
00615 ArgsList& curr_list = input_args.back();
00616
00617 curr_list.PopFront();
00618
00619 if (curr_list.Size() == 0) {
00620 input_args.pop_back();
00621 continue;
00622 }
00623
00624
00625
00626
00627 absl::string_view arg(curr_list.Front());
00628 bool arg_from_argv = input_args.size() == 1;
00629
00630
00631
00632 if (!absl::ConsumePrefix(&arg, "-") || arg.empty()) {
00633 ABSL_INTERNAL_CHECK(arg_from_argv,
00634 "Flagfile cannot contain positional argument");
00635
00636 positional_args.push_back(argv[curr_list.FrontIndex()]);
00637 continue;
00638 }
00639
00640 if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs)) {
00641 output_args.push_back(argv[curr_list.FrontIndex()]);
00642 }
00643
00644
00645
00646
00647
00648
00649 absl::string_view flag_name;
00650 absl::string_view value;
00651 bool is_empty_value = false;
00652
00653 std::tie(flag_name, value, is_empty_value) = SplitNameAndValue(arg);
00654
00655
00656
00657 if (flag_name.empty()) {
00658 ABSL_INTERNAL_CHECK(arg_from_argv,
00659 "Flagfile cannot contain positional argument");
00660
00661 curr_list.PopFront();
00662 break;
00663 }
00664
00665
00666 CommandLineFlag* flag = nullptr;
00667 bool is_negative = false;
00668 std::tie(flag, is_negative) = LocateFlag(flag_name);
00669
00670 if (flag == nullptr) {
00671 if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
00672 undefined_flag_names.emplace_back(arg_from_argv,
00673 std::string(flag_name));
00674 }
00675 continue;
00676 }
00677
00678
00679 auto curr_index = curr_list.FrontIndex();
00680 bool value_success = true;
00681 std::tie(value_success, value) =
00682 DeduceFlagValue(*flag, value, is_negative, is_empty_value, &curr_list);
00683 success &= value_success;
00684
00685
00686 if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs) &&
00687 (curr_index != curr_list.FrontIndex())) {
00688 output_args.push_back(argv[curr_list.FrontIndex()]);
00689 }
00690
00691
00692
00693 if (flag->IsRetired()) continue;
00694
00695 std::string error;
00696 if (!flag->SetFromString(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
00697 flags_internal::ReportUsageError(error, true);
00698 success = false;
00699 }
00700 }
00701
00702 for (const auto& flag_name : undefined_flag_names) {
00703 if (CanIgnoreUndefinedFlag(flag_name.second)) continue;
00704
00705 flags_internal::ReportUsageError(
00706 absl::StrCat("Unknown command line flag '", flag_name.second, "'"),
00707 true);
00708
00709 success = false;
00710 }
00711
00712 #if ABSL_FLAGS_STRIP_NAMES
00713 if (!success) {
00714 flags_internal::ReportUsageError(
00715 "NOTE: command line flags are disabled in this build", true);
00716 }
00717 #endif
00718
00719 if (!success) {
00720 flags_internal::HandleUsageFlags(std::cout);
00721 std::exit(1);
00722 }
00723
00724 if (usage_flag_act == UsageFlagsAction::kHandleUsage) {
00725 int exit_code = flags_internal::HandleUsageFlags(std::cout);
00726
00727 if (exit_code != -1) {
00728 std::exit(exit_code);
00729 }
00730 }
00731
00732 ResetGeneratorFlags(flagfile_value);
00733
00734
00735
00736 for (auto arg : positional_args) {
00737 output_args.push_back(arg);
00738 }
00739
00740
00741 if (!input_args.empty()) {
00742 for (int arg_index = input_args.back().FrontIndex(); arg_index < argc;
00743 ++arg_index) {
00744 output_args.push_back(argv[arg_index]);
00745 }
00746 }
00747
00748 return output_args;
00749 }
00750
00751 }
00752
00753
00754
00755 std::vector<char*> ParseCommandLine(int argc, char* argv[]) {
00756 return flags_internal::ParseCommandLineImpl(
00757 argc, argv, flags_internal::ArgvListAction::kRemoveParsedArgs,
00758 flags_internal::UsageFlagsAction::kHandleUsage,
00759 flags_internal::OnUndefinedFlag::kAbortIfUndefined);
00760 }
00761
00762 }