parse.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. //
  2. // Copyright 2019 The Abseil Authors.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // https://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #include "absl/flags/parse.h"
  16. #include <stdlib.h>
  17. #include <algorithm>
  18. #include <fstream>
  19. #include <iostream>
  20. #include <iterator>
  21. #include <string>
  22. #include <tuple>
  23. #include <utility>
  24. #include <vector>
  25. #ifdef _WIN32
  26. #include <windows.h>
  27. #endif
  28. #include "absl/base/attributes.h"
  29. #include "absl/base/config.h"
  30. #include "absl/base/const_init.h"
  31. #include "absl/base/thread_annotations.h"
  32. #include "absl/flags/commandlineflag.h"
  33. #include "absl/flags/config.h"
  34. #include "absl/flags/flag.h"
  35. #include "absl/flags/internal/commandlineflag.h"
  36. #include "absl/flags/internal/flag.h"
  37. #include "absl/flags/internal/parse.h"
  38. #include "absl/flags/internal/private_handle_accessor.h"
  39. #include "absl/flags/internal/program_name.h"
  40. #include "absl/flags/internal/usage.h"
  41. #include "absl/flags/reflection.h"
  42. #include "absl/flags/usage.h"
  43. #include "absl/flags/usage_config.h"
  44. #include "absl/strings/ascii.h"
  45. #include "absl/strings/str_cat.h"
  46. #include "absl/strings/string_view.h"
  47. #include "absl/strings/strip.h"
  48. #include "absl/synchronization/mutex.h"
  49. // --------------------------------------------------------------------
  50. namespace absl {
  51. ABSL_NAMESPACE_BEGIN
  52. namespace flags_internal {
  53. namespace {
  54. ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit);
  55. ABSL_CONST_INIT bool flagfile_needs_processing
  56. ABSL_GUARDED_BY(processing_checks_guard) = false;
  57. ABSL_CONST_INIT bool fromenv_needs_processing
  58. ABSL_GUARDED_BY(processing_checks_guard) = false;
  59. ABSL_CONST_INIT bool tryfromenv_needs_processing
  60. ABSL_GUARDED_BY(processing_checks_guard) = false;
  61. ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit);
  62. ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags
  63. ABSL_GUARDED_BY(specified_flags_guard) = nullptr;
  64. struct SpecifiedFlagsCompare {
  65. bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const {
  66. return a->Name() < b->Name();
  67. }
  68. bool operator()(const CommandLineFlag* a, absl::string_view b) const {
  69. return a->Name() < b;
  70. }
  71. bool operator()(absl::string_view a, const CommandLineFlag* b) const {
  72. return a < b->Name();
  73. }
  74. };
  75. } // namespace
  76. } // namespace flags_internal
  77. ABSL_NAMESPACE_END
  78. } // namespace absl
  79. ABSL_FLAG(std::vector<std::string>, flagfile, {},
  80. "comma-separated list of files to load flags from")
  81. .OnUpdate([]() {
  82. if (absl::GetFlag(FLAGS_flagfile).empty()) return;
  83. absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
  84. // Setting this flag twice before it is handled most likely an internal
  85. // error and should be reviewed by developers.
  86. if (absl::flags_internal::flagfile_needs_processing) {
  87. ABSL_INTERNAL_LOG(WARNING, "flagfile set twice before it is handled");
  88. }
  89. absl::flags_internal::flagfile_needs_processing = true;
  90. });
  91. ABSL_FLAG(std::vector<std::string>, fromenv, {},
  92. "comma-separated list of flags to set from the environment"
  93. " [use 'export FLAGS_flag1=value']")
  94. .OnUpdate([]() {
  95. if (absl::GetFlag(FLAGS_fromenv).empty()) return;
  96. absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
  97. // Setting this flag twice before it is handled most likely an internal
  98. // error and should be reviewed by developers.
  99. if (absl::flags_internal::fromenv_needs_processing) {
  100. ABSL_INTERNAL_LOG(WARNING, "fromenv set twice before it is handled.");
  101. }
  102. absl::flags_internal::fromenv_needs_processing = true;
  103. });
  104. ABSL_FLAG(std::vector<std::string>, tryfromenv, {},
  105. "comma-separated list of flags to try to set from the environment if "
  106. "present")
  107. .OnUpdate([]() {
  108. if (absl::GetFlag(FLAGS_tryfromenv).empty()) return;
  109. absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
  110. // Setting this flag twice before it is handled most likely an internal
  111. // error and should be reviewed by developers.
  112. if (absl::flags_internal::tryfromenv_needs_processing) {
  113. ABSL_INTERNAL_LOG(WARNING,
  114. "tryfromenv set twice before it is handled.");
  115. }
  116. absl::flags_internal::tryfromenv_needs_processing = true;
  117. });
  118. ABSL_FLAG(std::vector<std::string>, undefok, {},
  119. "comma-separated list of flag names that it is okay to specify "
  120. "on the command line even if the program does not define a flag "
  121. "with that name");
  122. namespace absl {
  123. ABSL_NAMESPACE_BEGIN
  124. namespace flags_internal {
  125. namespace {
  126. class ArgsList {
  127. public:
  128. ArgsList() : next_arg_(0) {}
  129. ArgsList(int argc, char* argv[]) : args_(argv, argv + argc), next_arg_(0) {}
  130. explicit ArgsList(const std::vector<std::string>& args)
  131. : args_(args), next_arg_(0) {}
  132. // Returns success status: true if parsing successful, false otherwise.
  133. bool ReadFromFlagfile(const std::string& flag_file_name);
  134. int Size() const { return args_.size() - next_arg_; }
  135. int FrontIndex() const { return next_arg_; }
  136. absl::string_view Front() const { return args_[next_arg_]; }
  137. void PopFront() { next_arg_++; }
  138. private:
  139. std::vector<std::string> args_;
  140. int next_arg_;
  141. };
  142. bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) {
  143. std::ifstream flag_file(flag_file_name);
  144. if (!flag_file) {
  145. flags_internal::ReportUsageError(
  146. absl::StrCat("Can't open flagfile ", flag_file_name), true);
  147. return false;
  148. }
  149. // This argument represents fake argv[0], which should be present in all arg
  150. // lists.
  151. args_.push_back("");
  152. std::string line;
  153. bool success = true;
  154. while (std::getline(flag_file, line)) {
  155. absl::string_view stripped = absl::StripLeadingAsciiWhitespace(line);
  156. if (stripped.empty() || stripped[0] == '#') {
  157. // Comment or empty line; just ignore.
  158. continue;
  159. }
  160. if (stripped[0] == '-') {
  161. if (stripped == "--") {
  162. flags_internal::ReportUsageError(
  163. "Flagfile can't contain position arguments or --", true);
  164. success = false;
  165. break;
  166. }
  167. args_.push_back(std::string(stripped));
  168. continue;
  169. }
  170. flags_internal::ReportUsageError(
  171. absl::StrCat("Unexpected line in the flagfile ", flag_file_name, ": ",
  172. line),
  173. true);
  174. success = false;
  175. }
  176. return success;
  177. }
  178. // --------------------------------------------------------------------
  179. // Reads the environment variable with name `name` and stores results in
  180. // `value`. If variable is not present in environment returns false, otherwise
  181. // returns true.
  182. bool GetEnvVar(const char* var_name, std::string& var_value) {
  183. #ifdef _WIN32
  184. char buf[1024];
  185. auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
  186. if (get_res >= sizeof(buf)) {
  187. return false;
  188. }
  189. if (get_res == 0) {
  190. return false;
  191. }
  192. var_value = std::string(buf, get_res);
  193. #else
  194. const char* val = ::getenv(var_name);
  195. if (val == nullptr) {
  196. return false;
  197. }
  198. var_value = val;
  199. #endif
  200. return true;
  201. }
  202. // --------------------------------------------------------------------
  203. // Returns:
  204. // Flag name or empty if arg= --
  205. // Flag value after = in --flag=value (empty if --foo)
  206. // "Is empty value" status. True if arg= --foo=, false otherwise. This is
  207. // required to separate --foo from --foo=.
  208. // For example:
  209. // arg return values
  210. // "--foo=bar" -> {"foo", "bar", false}.
  211. // "--foo" -> {"foo", "", false}.
  212. // "--foo=" -> {"foo", "", true}.
  213. std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue(
  214. absl::string_view arg) {
  215. // Allow -foo and --foo
  216. absl::ConsumePrefix(&arg, "-");
  217. if (arg.empty()) {
  218. return std::make_tuple("", "", false);
  219. }
  220. auto equal_sign_pos = arg.find("=");
  221. absl::string_view flag_name = arg.substr(0, equal_sign_pos);
  222. absl::string_view value;
  223. bool is_empty_value = false;
  224. if (equal_sign_pos != absl::string_view::npos) {
  225. value = arg.substr(equal_sign_pos + 1);
  226. is_empty_value = value.empty();
  227. }
  228. return std::make_tuple(flag_name, value, is_empty_value);
  229. }
  230. // --------------------------------------------------------------------
  231. // Returns:
  232. // found flag or nullptr
  233. // is negative in case of --nofoo
  234. std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
  235. CommandLineFlag* flag = absl::FindCommandLineFlag(flag_name);
  236. bool is_negative = false;
  237. if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
  238. flag = absl::FindCommandLineFlag(flag_name);
  239. is_negative = true;
  240. }
  241. return std::make_tuple(flag, is_negative);
  242. }
  243. // --------------------------------------------------------------------
  244. // Verify that default values of typed flags must be convertible to string and
  245. // back.
  246. void CheckDefaultValuesParsingRoundtrip() {
  247. #ifndef NDEBUG
  248. flags_internal::ForEachFlag([&](CommandLineFlag& flag) {
  249. if (flag.IsRetired()) return;
  250. #define ABSL_FLAGS_INTERNAL_IGNORE_TYPE(T, _) \
  251. if (flag.IsOfType<T>()) return;
  252. ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IGNORE_TYPE)
  253. #undef ABSL_FLAGS_INTERNAL_IGNORE_TYPE
  254. flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip(
  255. flag);
  256. });
  257. #endif
  258. }
  259. // --------------------------------------------------------------------
  260. // Returns success status, which is true if we successfully read all flag files,
  261. // in which case new ArgLists are appended to the input_args in a reverse order
  262. // of file names in the input flagfiles list. This order ensures that flags from
  263. // the first flagfile in the input list are processed before the second flagfile
  264. // etc.
  265. bool ReadFlagfiles(const std::vector<std::string>& flagfiles,
  266. std::vector<ArgsList>& input_args) {
  267. bool success = true;
  268. for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
  269. ArgsList al;
  270. if (al.ReadFromFlagfile(*it)) {
  271. input_args.push_back(al);
  272. } else {
  273. success = false;
  274. }
  275. }
  276. return success;
  277. }
  278. // Returns success status, which is true if were able to locate all environment
  279. // variables correctly or if fail_on_absent_in_env is false. The environment
  280. // variable names are expected to be of the form `FLAGS_<flag_name>`, where
  281. // `flag_name` is a string from the input flag_names list. If successful we
  282. // append a single ArgList at the end of the input_args.
  283. bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names,
  284. std::vector<ArgsList>& input_args,
  285. bool fail_on_absent_in_env) {
  286. bool success = true;
  287. std::vector<std::string> args;
  288. // This argument represents fake argv[0], which should be present in all arg
  289. // lists.
  290. args.push_back("");
  291. for (const auto& flag_name : flag_names) {
  292. // Avoid infinite recursion.
  293. if (flag_name == "fromenv" || flag_name == "tryfromenv") {
  294. flags_internal::ReportUsageError(
  295. absl::StrCat("Infinite recursion on flag ", flag_name), true);
  296. success = false;
  297. continue;
  298. }
  299. const std::string envname = absl::StrCat("FLAGS_", flag_name);
  300. std::string envval;
  301. if (!GetEnvVar(envname.c_str(), envval)) {
  302. if (fail_on_absent_in_env) {
  303. flags_internal::ReportUsageError(
  304. absl::StrCat(envname, " not found in environment"), true);
  305. success = false;
  306. }
  307. continue;
  308. }
  309. args.push_back(absl::StrCat("--", flag_name, "=", envval));
  310. }
  311. if (success) {
  312. input_args.emplace_back(args);
  313. }
  314. return success;
  315. }
  316. // --------------------------------------------------------------------
  317. // Returns success status, which is true if were able to handle all generator
  318. // flags (flagfile, fromenv, tryfromemv) successfully.
  319. bool HandleGeneratorFlags(std::vector<ArgsList>& input_args,
  320. std::vector<std::string>& flagfile_value) {
  321. bool success = true;
  322. absl::MutexLock l(&flags_internal::processing_checks_guard);
  323. // flagfile could have been set either on a command line or
  324. // programmatically before invoking ParseCommandLine. Note that we do not
  325. // actually process arguments specified in the flagfile, but instead
  326. // create a secondary arguments list to be processed along with the rest
  327. // of the comamnd line arguments. Since we always the process most recently
  328. // created list of arguments first, this will result in flagfile argument
  329. // being processed before any other argument in the command line. If
  330. // FLAGS_flagfile contains more than one file name we create multiple new
  331. // levels of arguments in a reverse order of file names. Thus we always
  332. // process arguments from first file before arguments containing in a
  333. // second file, etc. If flagfile contains another
  334. // --flagfile inside of it, it will produce new level of arguments and
  335. // processed before the rest of the flagfile. We are also collecting all
  336. // flagfiles set on original command line. Unlike the rest of the flags,
  337. // this flag can be set multiple times and is expected to be handled
  338. // multiple times. We are collecting them all into a single list and set
  339. // the value of FLAGS_flagfile to that value at the end of the parsing.
  340. if (flags_internal::flagfile_needs_processing) {
  341. auto flagfiles = absl::GetFlag(FLAGS_flagfile);
  342. if (input_args.size() == 1) {
  343. flagfile_value.insert(flagfile_value.end(), flagfiles.begin(),
  344. flagfiles.end());
  345. }
  346. success &= ReadFlagfiles(flagfiles, input_args);
  347. flags_internal::flagfile_needs_processing = false;
  348. }
  349. // Similar to flagfile fromenv/tryfromemv can be set both
  350. // programmatically and at runtime on a command line. Unlike flagfile these
  351. // can't be recursive.
  352. if (flags_internal::fromenv_needs_processing) {
  353. auto flags_list = absl::GetFlag(FLAGS_fromenv);
  354. success &= ReadFlagsFromEnv(flags_list, input_args, true);
  355. flags_internal::fromenv_needs_processing = false;
  356. }
  357. if (flags_internal::tryfromenv_needs_processing) {
  358. auto flags_list = absl::GetFlag(FLAGS_tryfromenv);
  359. success &= ReadFlagsFromEnv(flags_list, input_args, false);
  360. flags_internal::tryfromenv_needs_processing = false;
  361. }
  362. return success;
  363. }
  364. // --------------------------------------------------------------------
  365. void ResetGeneratorFlags(const std::vector<std::string>& flagfile_value) {
  366. // Setting flagfile to the value which collates all the values set on a
  367. // command line and programmatically. So if command line looked like
  368. // --flagfile=f1 --flagfile=f2 the final value of the FLAGS_flagfile flag is
  369. // going to be {"f1", "f2"}
  370. if (!flagfile_value.empty()) {
  371. absl::SetFlag(&FLAGS_flagfile, flagfile_value);
  372. absl::MutexLock l(&flags_internal::processing_checks_guard);
  373. flags_internal::flagfile_needs_processing = false;
  374. }
  375. // fromenv/tryfromenv are set to <undefined> value.
  376. if (!absl::GetFlag(FLAGS_fromenv).empty()) {
  377. absl::SetFlag(&FLAGS_fromenv, {});
  378. }
  379. if (!absl::GetFlag(FLAGS_tryfromenv).empty()) {
  380. absl::SetFlag(&FLAGS_tryfromenv, {});
  381. }
  382. absl::MutexLock l(&flags_internal::processing_checks_guard);
  383. flags_internal::fromenv_needs_processing = false;
  384. flags_internal::tryfromenv_needs_processing = false;
  385. }
  386. // --------------------------------------------------------------------
  387. // Returns:
  388. // success status
  389. // deduced value
  390. // We are also mutating curr_list in case if we need to get a hold of next
  391. // argument in the input.
  392. std::tuple<bool, absl::string_view> DeduceFlagValue(const CommandLineFlag& flag,
  393. absl::string_view value,
  394. bool is_negative,
  395. bool is_empty_value,
  396. ArgsList* curr_list) {
  397. // Value is either an argument suffix after `=` in "--foo=<value>"
  398. // or separate argument in case of "--foo" "<value>".
  399. // boolean flags have these forms:
  400. // --foo
  401. // --nofoo
  402. // --foo=true
  403. // --foo=false
  404. // --nofoo=<value> is not supported
  405. // --foo <value> is not supported
  406. // non boolean flags have these forms:
  407. // --foo=<value>
  408. // --foo <value>
  409. // --nofoo is not supported
  410. if (flag.IsOfType<bool>()) {
  411. if (value.empty()) {
  412. if (is_empty_value) {
  413. // "--bool_flag=" case
  414. flags_internal::ReportUsageError(
  415. absl::StrCat(
  416. "Missing the value after assignment for the boolean flag '",
  417. flag.Name(), "'"),
  418. true);
  419. return std::make_tuple(false, "");
  420. }
  421. // "--bool_flag" case
  422. value = is_negative ? "0" : "1";
  423. } else if (is_negative) {
  424. // "--nobool_flag=Y" case
  425. flags_internal::ReportUsageError(
  426. absl::StrCat("Negative form with assignment is not valid for the "
  427. "boolean flag '",
  428. flag.Name(), "'"),
  429. true);
  430. return std::make_tuple(false, "");
  431. }
  432. } else if (is_negative) {
  433. // "--noint_flag=1" case
  434. flags_internal::ReportUsageError(
  435. absl::StrCat("Negative form is not valid for the flag '", flag.Name(),
  436. "'"),
  437. true);
  438. return std::make_tuple(false, "");
  439. } else if (value.empty() && (!is_empty_value)) {
  440. if (curr_list->Size() == 1) {
  441. // "--int_flag" case
  442. flags_internal::ReportUsageError(
  443. absl::StrCat("Missing the value for the flag '", flag.Name(), "'"),
  444. true);
  445. return std::make_tuple(false, "");
  446. }
  447. // "--int_flag" "10" case
  448. curr_list->PopFront();
  449. value = curr_list->Front();
  450. // Heuristic to detect the case where someone treats a string arg
  451. // like a bool or just forgets to pass a value:
  452. // --my_string_var --foo=bar
  453. // We look for a flag of string type, whose value begins with a
  454. // dash and corresponds to known flag or standalone --.
  455. if (!value.empty() && value[0] == '-' && flag.IsOfType<std::string>()) {
  456. auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
  457. if (maybe_flag_name.empty() ||
  458. std::get<0>(LocateFlag(maybe_flag_name)) != nullptr) {
  459. // "--string_flag" "--known_flag" case
  460. ABSL_INTERNAL_LOG(
  461. WARNING,
  462. absl::StrCat("Did you really mean to set flag '", flag.Name(),
  463. "' to the value '", value, "'?"));
  464. }
  465. }
  466. }
  467. return std::make_tuple(true, value);
  468. }
  469. // --------------------------------------------------------------------
  470. bool CanIgnoreUndefinedFlag(absl::string_view flag_name) {
  471. auto undefok = absl::GetFlag(FLAGS_undefok);
  472. if (std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
  473. return true;
  474. }
  475. if (absl::ConsumePrefix(&flag_name, "no") &&
  476. std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
  477. return true;
  478. }
  479. return false;
  480. }
  481. } // namespace
  482. // --------------------------------------------------------------------
  483. bool WasPresentOnCommandLine(absl::string_view flag_name) {
  484. absl::MutexLock l(&specified_flags_guard);
  485. ABSL_INTERNAL_CHECK(specified_flags != nullptr,
  486. "ParseCommandLine is not invoked yet");
  487. return std::binary_search(specified_flags->begin(), specified_flags->end(),
  488. flag_name, SpecifiedFlagsCompare{});
  489. }
  490. // --------------------------------------------------------------------
  491. std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
  492. ArgvListAction arg_list_act,
  493. UsageFlagsAction usage_flag_act,
  494. OnUndefinedFlag on_undef_flag) {
  495. ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
  496. // Once parsing has started we will not have more flag registrations.
  497. // If we did, they would be missing during parsing, which is a problem on
  498. // itself.
  499. flags_internal::FinalizeRegistry();
  500. // This routine does not return anything since we abort on failure.
  501. CheckDefaultValuesParsingRoundtrip();
  502. std::vector<std::string> flagfile_value;
  503. std::vector<ArgsList> input_args;
  504. input_args.push_back(ArgsList(argc, argv));
  505. std::vector<char*> output_args;
  506. std::vector<char*> positional_args;
  507. output_args.reserve(argc);
  508. // This is the list of undefined flags. The element of the list is the pair
  509. // consisting of boolean indicating if flag came from command line (vs from
  510. // some flag file we've read) and flag name.
  511. // TODO(rogeeff): Eliminate the first element in the pair after cleanup.
  512. std::vector<std::pair<bool, std::string>> undefined_flag_names;
  513. // Set program invocation name if it is not set before.
  514. if (ProgramInvocationName() == "UNKNOWN") {
  515. flags_internal::SetProgramInvocationName(argv[0]);
  516. }
  517. output_args.push_back(argv[0]);
  518. absl::MutexLock l(&specified_flags_guard);
  519. if (specified_flags == nullptr) {
  520. specified_flags = new std::vector<const CommandLineFlag*>;
  521. } else {
  522. specified_flags->clear();
  523. }
  524. // Iterate through the list of the input arguments. First level are arguments
  525. // originated from argc/argv. Following levels are arguments originated from
  526. // recursive parsing of flagfile(s).
  527. bool success = true;
  528. while (!input_args.empty()) {
  529. // 10. First we process the built-in generator flags.
  530. success &= HandleGeneratorFlags(input_args, flagfile_value);
  531. // 30. Select top-most (most recent) arguments list. If it is empty drop it
  532. // and re-try.
  533. ArgsList& curr_list = input_args.back();
  534. curr_list.PopFront();
  535. if (curr_list.Size() == 0) {
  536. input_args.pop_back();
  537. continue;
  538. }
  539. // 40. Pick up the front remaining argument in the current list. If current
  540. // stack of argument lists contains only one element - we are processing an
  541. // argument from the original argv.
  542. absl::string_view arg(curr_list.Front());
  543. bool arg_from_argv = input_args.size() == 1;
  544. // 50. If argument does not start with - or is just "-" - this is
  545. // positional argument.
  546. if (!absl::ConsumePrefix(&arg, "-") || arg.empty()) {
  547. ABSL_INTERNAL_CHECK(arg_from_argv,
  548. "Flagfile cannot contain positional argument");
  549. positional_args.push_back(argv[curr_list.FrontIndex()]);
  550. continue;
  551. }
  552. if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs)) {
  553. output_args.push_back(argv[curr_list.FrontIndex()]);
  554. }
  555. // 60. Split the current argument on '=' to figure out the argument
  556. // name and value. If flag name is empty it means we've got "--". value
  557. // can be empty either if there were no '=' in argument string at all or
  558. // an argument looked like "--foo=". In a latter case is_empty_value is
  559. // true.
  560. absl::string_view flag_name;
  561. absl::string_view value;
  562. bool is_empty_value = false;
  563. std::tie(flag_name, value, is_empty_value) = SplitNameAndValue(arg);
  564. // 70. "--" alone means what it does for GNU: stop flags parsing. We do
  565. // not support positional arguments in flagfiles, so we just drop them.
  566. if (flag_name.empty()) {
  567. ABSL_INTERNAL_CHECK(arg_from_argv,
  568. "Flagfile cannot contain positional argument");
  569. curr_list.PopFront();
  570. break;
  571. }
  572. // 80. Locate the flag based on flag name. Handle both --foo and --nofoo
  573. CommandLineFlag* flag = nullptr;
  574. bool is_negative = false;
  575. std::tie(flag, is_negative) = LocateFlag(flag_name);
  576. if (flag == nullptr) {
  577. // Usage flags are not modeled as Abseil flags. Locate them separately.
  578. if (flags_internal::DeduceUsageFlags(flag_name, value)) {
  579. continue;
  580. }
  581. if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
  582. undefined_flag_names.emplace_back(arg_from_argv,
  583. std::string(flag_name));
  584. }
  585. continue;
  586. }
  587. // 90. Deduce flag's value (from this or next argument)
  588. auto curr_index = curr_list.FrontIndex();
  589. bool value_success = true;
  590. std::tie(value_success, value) =
  591. DeduceFlagValue(*flag, value, is_negative, is_empty_value, &curr_list);
  592. success &= value_success;
  593. // If above call consumed an argument, it was a standalone value
  594. if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs) &&
  595. (curr_index != curr_list.FrontIndex())) {
  596. output_args.push_back(argv[curr_list.FrontIndex()]);
  597. }
  598. // 100. Set the located flag to a new new value, unless it is retired.
  599. // Setting retired flag fails, but we ignoring it here while also reporting
  600. // access to retired flag.
  601. std::string error;
  602. if (!flags_internal::PrivateHandleAccessor::ParseFrom(
  603. *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) {
  604. if (flag->IsRetired()) continue;
  605. flags_internal::ReportUsageError(error, true);
  606. success = false;
  607. } else {
  608. specified_flags->push_back(flag);
  609. }
  610. }
  611. for (const auto& flag_name : undefined_flag_names) {
  612. if (CanIgnoreUndefinedFlag(flag_name.second)) continue;
  613. flags_internal::ReportUsageError(
  614. absl::StrCat("Unknown command line flag '", flag_name.second, "'"),
  615. true);
  616. success = false;
  617. }
  618. #if ABSL_FLAGS_STRIP_NAMES
  619. if (!success) {
  620. flags_internal::ReportUsageError(
  621. "NOTE: command line flags are disabled in this build", true);
  622. }
  623. #endif
  624. if (!success) {
  625. flags_internal::HandleUsageFlags(std::cout,
  626. ProgramUsageMessage());
  627. std::exit(1);
  628. }
  629. if (usage_flag_act == UsageFlagsAction::kHandleUsage) {
  630. int exit_code = flags_internal::HandleUsageFlags(
  631. std::cout, ProgramUsageMessage());
  632. if (exit_code != -1) {
  633. std::exit(exit_code);
  634. }
  635. }
  636. ResetGeneratorFlags(flagfile_value);
  637. // Reinstate positional args which were intermixed with flags in the arguments
  638. // list.
  639. for (auto arg : positional_args) {
  640. output_args.push_back(arg);
  641. }
  642. // All the remaining arguments are positional.
  643. if (!input_args.empty()) {
  644. for (int arg_index = input_args.back().FrontIndex(); arg_index < argc;
  645. ++arg_index) {
  646. output_args.push_back(argv[arg_index]);
  647. }
  648. }
  649. // Trim and sort the vector.
  650. specified_flags->shrink_to_fit();
  651. std::sort(specified_flags->begin(), specified_flags->end(),
  652. SpecifiedFlagsCompare{});
  653. return output_args;
  654. }
  655. } // namespace flags_internal
  656. // --------------------------------------------------------------------
  657. std::vector<char*> ParseCommandLine(int argc, char* argv[]) {
  658. return flags_internal::ParseCommandLineImpl(
  659. argc, argv, flags_internal::ArgvListAction::kRemoveParsedArgs,
  660. flags_internal::UsageFlagsAction::kHandleUsage,
  661. flags_internal::OnUndefinedFlag::kAbortIfUndefined);
  662. }
  663. ABSL_NAMESPACE_END
  664. } // namespace absl