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