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