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