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