parse.cc
Go to the documentation of this file.
00001 //
00002 // Copyright 2019 The Abseil Authors.
00003 //
00004 // Licensed under the Apache License, Version 2.0 (the "License");
00005 // you may not use this file except in compliance with the License.
00006 // You may obtain a copy of the License at
00007 //
00008 //      https://www.apache.org/licenses/LICENSE-2.0
00009 //
00010 // Unless required by applicable law or agreed to in writing, software
00011 // distributed under the License is distributed on an "AS IS" BASIS,
00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 // See the License for the specific language governing permissions and
00014 // limitations under the License.
00015 
00016 #include "absl/flags/parse.h"
00017 
00018 #include <stdlib.h>
00019 #include <fstream>
00020 #include <iostream>
00021 #include <tuple>
00022 
00023 #ifdef _WIN32
00024 #include <windows.h>
00025 #endif
00026 
00027 #include "absl/flags/flag.h"
00028 #include "absl/flags/internal/program_name.h"
00029 #include "absl/flags/internal/registry.h"
00030 #include "absl/flags/internal/usage.h"
00031 #include "absl/flags/usage_config.h"
00032 #include "absl/strings/str_cat.h"
00033 #include "absl/strings/strip.h"
00034 #include "absl/synchronization/mutex.h"
00035 
00036 // --------------------------------------------------------------------
00037 
00038 namespace absl {
00039 namespace flags_internal {
00040 namespace {
00041 
00042 ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit);
00043 
00044 ABSL_CONST_INIT bool flagfile_needs_processing
00045     GUARDED_BY(processing_checks_guard) = false;
00046 ABSL_CONST_INIT bool fromenv_needs_processing
00047     GUARDED_BY(processing_checks_guard) = false;
00048 ABSL_CONST_INIT bool tryfromenv_needs_processing
00049     GUARDED_BY(processing_checks_guard) = false;
00050 
00051 }  // namespace
00052 }  // namespace flags_internal
00053 }  // namespace absl
00054 
00055 ABSL_FLAG(std::vector<std::string>, flagfile, {},
00056           "comma-separated list of files to load flags from")
00057     .OnUpdate([]() {
00058       if (absl::GetFlag(FLAGS_flagfile).empty()) return;
00059 
00060       absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
00061 
00062       // Setting this flag twice before it is handled most likely an internal
00063       // error and should be reviewed by developers.
00064       if (absl::flags_internal::flagfile_needs_processing) {
00065         ABSL_INTERNAL_LOG(WARNING, "flagfile set twice before it is handled");
00066       }
00067 
00068       absl::flags_internal::flagfile_needs_processing = true;
00069     });
00070 ABSL_FLAG(std::vector<std::string>, fromenv, {},
00071           "comma-separated list of flags to set from the environment"
00072           " [use 'export FLAGS_flag1=value']")
00073     .OnUpdate([]() {
00074       if (absl::GetFlag(FLAGS_fromenv).empty()) return;
00075 
00076       absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
00077 
00078       // Setting this flag twice before it is handled most likely an internal
00079       // error and should be reviewed by developers.
00080       if (absl::flags_internal::fromenv_needs_processing) {
00081         ABSL_INTERNAL_LOG(WARNING, "fromenv set twice before it is handled.");
00082       }
00083 
00084       absl::flags_internal::fromenv_needs_processing = true;
00085     });
00086 ABSL_FLAG(std::vector<std::string>, tryfromenv, {},
00087           "comma-separated list of flags to try to set from the environment if "
00088           "present")
00089     .OnUpdate([]() {
00090       if (absl::GetFlag(FLAGS_tryfromenv).empty()) return;
00091 
00092       absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
00093 
00094       // Setting this flag twice before it is handled most likely an internal
00095       // error and should be reviewed by developers.
00096       if (absl::flags_internal::tryfromenv_needs_processing) {
00097         ABSL_INTERNAL_LOG(WARNING,
00098                           "tryfromenv set twice before it is handled.");
00099       }
00100 
00101       absl::flags_internal::tryfromenv_needs_processing = true;
00102     });
00103 
00104 ABSL_FLAG(std::vector<std::string>, undefok, {},
00105           "comma-separated list of flag names that it is okay to specify "
00106           "on the command line even if the program does not define a flag "
00107           "with that name");
00108 
00109 namespace absl {
00110 namespace flags_internal {
00111 
00112 namespace {
00113 
00114 class ArgsList {
00115  public:
00116   ArgsList() : next_arg_(0) {}
00117   ArgsList(int argc, char* argv[]) : args_(argv, argv + argc), next_arg_(0) {}
00118   explicit ArgsList(const std::vector<std::string>& args)
00119       : args_(args), next_arg_(0) {}
00120 
00121   // Returns success status: true if parsing successful, false otherwise.
00122   bool ReadFromFlagfile(const std::string& flag_file_name);
00123 
00124   int Size() const { return args_.size() - next_arg_; }
00125   int FrontIndex() const { return next_arg_; }
00126   absl::string_view Front() const { return args_[next_arg_]; }
00127   void PopFront() { next_arg_++; }
00128 
00129  private:
00130   std::vector<std::string> args_;
00131   int next_arg_;
00132 };
00133 
00134 bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) {
00135   std::ifstream flag_file(flag_file_name);
00136 
00137   if (!flag_file) {
00138     flags_internal::ReportUsageError(
00139         absl::StrCat("Can't open flagfile ", flag_file_name), true);
00140 
00141     return false;
00142   }
00143 
00144   // This argument represents fake argv[0], which should be present in all arg
00145   // lists.
00146   args_.push_back("");
00147 
00148   std::string line;
00149   bool success = true;
00150 
00151   while (std::getline(flag_file, line)) {
00152     absl::string_view stripped = absl::StripLeadingAsciiWhitespace(line);
00153 
00154     if (stripped.empty() || stripped[0] == '#') {
00155       // Comment or empty line; just ignore.
00156       continue;
00157     }
00158 
00159     if (stripped[0] == '-') {
00160       if (stripped == "--") {
00161         flags_internal::ReportUsageError(
00162             "Flagfile can't contain position arguments or --", true);
00163 
00164         success = false;
00165         break;
00166       }
00167 
00168       args_.push_back(std::string(stripped));
00169       continue;
00170     }
00171 
00172     flags_internal::ReportUsageError(
00173         absl::StrCat("Unexpected line in the flagfile ", flag_file_name, ": ",
00174                      line),
00175         true);
00176 
00177     success = false;
00178   }
00179 
00180   return success;
00181 }
00182 
00183 // --------------------------------------------------------------------
00184 
00185 // Reads the environment variable with name `name` and stores results in
00186 // `value`. If variable is not present in environment returns false, otherwise
00187 // returns true.
00188 bool GetEnvVar(const char* var_name, std::string* var_value) {
00189 #ifdef _WIN32
00190   char buf[1024];
00191   auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
00192   if (get_res >= sizeof(buf)) {
00193     return false;
00194   }
00195 
00196   if (get_res == 0) {
00197     return false;
00198   }
00199 
00200   *var_value = std::string(buf, get_res);
00201 #else
00202   const char* val = ::getenv(var_name);
00203   if (val == nullptr) {
00204     return false;
00205   }
00206 
00207   *var_value = val;
00208 #endif
00209 
00210   return true;
00211 }
00212 
00213 // --------------------------------------------------------------------
00214 
00215 // Returns:
00216 //  Flag name or empty if arg= --
00217 //  Flag value after = in --flag=value (empty if --foo)
00218 //  "Is empty value" status. True if arg= --foo=, false otherwise. This is
00219 //  required to separate --foo from --foo=.
00220 // For example:
00221 //      arg           return values
00222 //   "--foo=bar" -> {"foo", "bar", false}.
00223 //   "--foo"     -> {"foo", "", false}.
00224 //   "--foo="    -> {"foo", "", true}.
00225 std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue(
00226     absl::string_view arg) {
00227   // Allow -foo and --foo
00228   absl::ConsumePrefix(&arg, "-");
00229 
00230   if (arg.empty()) {
00231     return std::make_tuple("", "", false);
00232   }
00233 
00234   auto equal_sign_pos = arg.find("=");
00235 
00236   absl::string_view flag_name = arg.substr(0, equal_sign_pos);
00237 
00238   absl::string_view value;
00239   bool is_empty_value = false;
00240 
00241   if (equal_sign_pos != absl::string_view::npos) {
00242     value = arg.substr(equal_sign_pos + 1);
00243     is_empty_value = value.empty();
00244   }
00245 
00246   return std::make_tuple(flag_name, value, is_empty_value);
00247 }
00248 
00249 // --------------------------------------------------------------------
00250 
00251 // Returns:
00252 //  found flag or nullptr
00253 //  is negative in case of --nofoo
00254 std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
00255   CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
00256   bool is_negative = false;
00257 
00258   if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
00259     flag = flags_internal::FindCommandLineFlag(flag_name);
00260     is_negative = true;
00261   }
00262 
00263   return std::make_tuple(flag, is_negative);
00264 }
00265 
00266 // --------------------------------------------------------------------
00267 
00268 // Verify that default values of typed flags must be convertible to string and
00269 // back.
00270 void CheckDefaultValuesParsingRoundtrip() {
00271 #ifndef NDEBUG
00272   flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
00273     if (flag->IsRetired()) return;
00274 
00275 #define IGNORE_TYPE(T) \
00276   if (flag->IsOfType<T>()) return;
00277 
00278     ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(IGNORE_TYPE)
00279     IGNORE_TYPE(std::string)
00280     IGNORE_TYPE(std::vector<std::string>)
00281 #undef IGNORE_TYPE
00282 
00283     absl::MutexLock lock(InitFlagIfNecessary(flag));
00284 
00285     std::string v = flag->DefaultValue();
00286     void* dst = Clone(flag->op, flag->def);
00287     std::string error;
00288     if (!flags_internal::Parse(flag->marshalling_op, v, dst, &error)) {
00289       ABSL_INTERNAL_LOG(
00290           FATAL,
00291           absl::StrCat("Flag ", flag->Name(), " (from ", flag->Filename(),
00292                        "): std::string form of default value '", v,
00293                        "' could not be parsed; error=", error));
00294     }
00295 
00296     // We do not compare dst to def since parsing/unparsing may make
00297     // small changes, e.g., precision loss for floating point types.
00298     Delete(flag->op, dst);
00299   });
00300 #endif
00301 }
00302 
00303 // --------------------------------------------------------------------
00304 
00305 // Returns success status, which is true if we successfully read all flag files,
00306 // in which case new ArgLists are appended to the input_args in a reverse order
00307 // of file names in the input flagfiles list. This order ensures that flags from
00308 // the first flagfile in the input list are processed before the second flagfile
00309 // etc.
00310 bool ReadFlagfiles(const std::vector<std::string>& flagfiles,
00311                    std::vector<ArgsList>* input_args) {
00312   bool success = true;
00313   for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
00314     ArgsList al;
00315 
00316     if (al.ReadFromFlagfile(*it)) {
00317       input_args->push_back(al);
00318     } else {
00319       success = false;
00320     }
00321   }
00322 
00323   return success;
00324 }
00325 
00326 // Returns success status, which is true if were able to locate all environment
00327 // variables correctly or if fail_on_absent_in_env is false. The environment
00328 // variable names are expected to be of the form `FLAGS_<flag_name>`, where
00329 // `flag_name` is a string from the input flag_names list. If successful we
00330 // append a single ArgList at the end of the input_args.
00331 bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names,
00332                       std::vector<ArgsList>* input_args,
00333                       bool fail_on_absent_in_env) {
00334   bool success = true;
00335   std::vector<std::string> args;
00336 
00337   // This argument represents fake argv[0], which should be present in all arg
00338   // lists.
00339   args.push_back("");
00340 
00341   for (const auto& flag_name : flag_names) {
00342     // Avoid infinite recursion.
00343     if (flag_name == "fromenv" || flag_name == "tryfromenv") {
00344       flags_internal::ReportUsageError(
00345           absl::StrCat("Infinite recursion on flag ", flag_name), true);
00346 
00347       success = false;
00348       continue;
00349     }
00350 
00351     const std::string envname = absl::StrCat("FLAGS_", flag_name);
00352     std::string envval;
00353     if (!GetEnvVar(envname.c_str(), &envval)) {
00354       if (fail_on_absent_in_env) {
00355         flags_internal::ReportUsageError(
00356             absl::StrCat(envname, " not found in environment"), true);
00357 
00358         success = false;
00359       }
00360 
00361       continue;
00362     }
00363 
00364     args.push_back(absl::StrCat("--", flag_name, "=", envval));
00365   }
00366 
00367   if (success) {
00368     input_args->emplace_back(args);
00369   }
00370 
00371   return success;
00372 }
00373 
00374 // --------------------------------------------------------------------
00375 
00376 // Returns success status, which is true if were able to handle all generator
00377 // flags (flagfile, fromenv, tryfromemv) successfully.
00378 bool HandleGeneratorFlags(std::vector<ArgsList>* input_args,
00379                           std::vector<std::string>* flagfile_value) {
00380   bool success = true;
00381 
00382   absl::MutexLock l(&flags_internal::processing_checks_guard);
00383 
00384   // flagfile could have been set either on a command line or
00385   // programmatically before invoking ParseCommandLine. Note that we do not
00386   // actually process arguments specified in the flagfile, but instead
00387   // create a secondary arguments list to be processed along with the rest
00388   // of the comamnd line arguments. Since we always the process most recently
00389   // created list of arguments first, this will result in flagfile argument
00390   // being processed before any other argument in the command line. If
00391   // FLAGS_flagfile contains more than one file name we create multiple new
00392   // levels of arguments in a reverse order of file names. Thus we always
00393   // process arguments from first file before arguments containing in a
00394   // second file, etc. If flagfile contains another
00395   // --flagfile inside of it, it will produce new level of arguments and
00396   // processed before the rest of the flagfile. We are also collecting all
00397   // flagfiles set on original command line. Unlike the rest of the flags,
00398   // this flag can be set multiple times and is expected to be handled
00399   // multiple times. We are collecting them all into a single list and set
00400   // the value of FLAGS_flagfile to that value at the end of the parsing.
00401   if (flags_internal::flagfile_needs_processing) {
00402     auto flagfiles = absl::GetFlag(FLAGS_flagfile);
00403 
00404     if (input_args->size() == 1) {
00405       flagfile_value->insert(flagfile_value->end(), flagfiles.begin(),
00406                              flagfiles.end());
00407     }
00408 
00409     success &= ReadFlagfiles(flagfiles, input_args);
00410 
00411     flags_internal::flagfile_needs_processing = false;
00412   }
00413 
00414   // Similar to flagfile fromenv/tryfromemv can be set both
00415   // programmatically and at runtime on a command line. Unlike flagfile these
00416   // can't be recursive.
00417   if (flags_internal::fromenv_needs_processing) {
00418     auto flags_list = absl::GetFlag(FLAGS_fromenv);
00419 
00420     success &= ReadFlagsFromEnv(flags_list, input_args, true);
00421 
00422     flags_internal::fromenv_needs_processing = false;
00423   }
00424 
00425   if (flags_internal::tryfromenv_needs_processing) {
00426     auto flags_list = absl::GetFlag(FLAGS_tryfromenv);
00427 
00428     success &= ReadFlagsFromEnv(flags_list, input_args, false);
00429 
00430     flags_internal::tryfromenv_needs_processing = false;
00431   }
00432 
00433   return success;
00434 }
00435 
00436 // --------------------------------------------------------------------
00437 
00438 void ResetGeneratorFlags(const std::vector<std::string>& flagfile_value) {
00439   // Setting flagfile to the value which collates all the values set on a
00440   // command line and programmatically. So if command line looked like
00441   // --flagfile=f1 --flagfile=f2 the final value of the FLAGS_flagfile flag is
00442   // going to be {"f1", "f2"}
00443   if (!flagfile_value.empty()) {
00444     absl::SetFlag(&FLAGS_flagfile, flagfile_value);
00445     absl::MutexLock l(&flags_internal::processing_checks_guard);
00446     flags_internal::flagfile_needs_processing = false;
00447   }
00448 
00449   // fromenv/tryfromenv are set to <undefined> value.
00450   if (!absl::GetFlag(FLAGS_fromenv).empty()) {
00451     absl::SetFlag(&FLAGS_fromenv, {});
00452   }
00453   if (!absl::GetFlag(FLAGS_tryfromenv).empty()) {
00454     absl::SetFlag(&FLAGS_tryfromenv, {});
00455   }
00456 
00457   absl::MutexLock l(&flags_internal::processing_checks_guard);
00458   flags_internal::fromenv_needs_processing = false;
00459   flags_internal::tryfromenv_needs_processing = false;
00460 }
00461 
00462 // --------------------------------------------------------------------
00463 
00464 // Returns:
00465 //  success status
00466 //  deduced value
00467 // We are also mutating curr_list in case if we need to get a hold of next
00468 // argument in the input.
00469 std::tuple<bool, absl::string_view> DeduceFlagValue(const CommandLineFlag& flag,
00470                                                     absl::string_view value,
00471                                                     bool is_negative,
00472                                                     bool is_empty_value,
00473                                                     ArgsList* curr_list) {
00474   // Value is either an argument suffix after `=` in "--foo=<value>"
00475   // or separate argument in case of "--foo" "<value>".
00476 
00477   // boolean flags have these forms:
00478   //   --foo
00479   //   --nofoo
00480   //   --foo=true
00481   //   --foo=false
00482   //   --nofoo=<value> is not supported
00483   //   --foo <value> is not supported
00484 
00485   // non boolean flags have these forms:
00486   // --foo=<value>
00487   // --foo <value>
00488   // --nofoo is not supported
00489 
00490   if (flag.IsOfType<bool>()) {
00491     if (value.empty()) {
00492       if (is_empty_value) {
00493         // "--bool_flag=" case
00494         flags_internal::ReportUsageError(
00495             absl::StrCat(
00496                 "Missing the value after assignment for the boolean flag '",
00497                 flag.Name(), "'"),
00498             true);
00499         return std::make_tuple(false, "");
00500       }
00501 
00502       // "--bool_flag" case
00503       value = is_negative ? "0" : "1";
00504     } else if (is_negative) {
00505       // "--nobool_flag=Y" case
00506       flags_internal::ReportUsageError(
00507           absl::StrCat("Negative form with assignment is not valid for the "
00508                        "boolean flag '",
00509                        flag.Name(), "'"),
00510           true);
00511       return std::make_tuple(false, "");
00512     }
00513   } else if (is_negative) {
00514     // "--noint_flag=1" case
00515     flags_internal::ReportUsageError(
00516         absl::StrCat("Negative form is not valid for the flag '", flag.Name(),
00517                      "'"),
00518         true);
00519     return std::make_tuple(false, "");
00520   } else if (value.empty() && (!is_empty_value)) {
00521     if (curr_list->Size() == 1) {
00522       // "--int_flag" case
00523       flags_internal::ReportUsageError(
00524           absl::StrCat("Missing the value for the flag '", flag.Name(), "'"),
00525           true);
00526       return std::make_tuple(false, "");
00527     }
00528 
00529     // "--int_flag" "10" case
00530     curr_list->PopFront();
00531     value = curr_list->Front();
00532 
00533     // Heuristic to detect the case where someone treats a std::string arg
00534     // like a bool or just forgets to pass a value:
00535     // --my_string_var --foo=bar
00536     // We look for a flag of std::string type, whose value begins with a
00537     // dash and corresponds to known flag or standalone --.
00538     if (value[0] == '-' && flag.IsOfType<std::string>()) {
00539       auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
00540 
00541       if (maybe_flag_name.empty() ||
00542           std::get<0>(LocateFlag(maybe_flag_name)) != nullptr) {
00543         // "--string_flag" "--known_flag" case
00544         ABSL_INTERNAL_LOG(
00545             WARNING,
00546             absl::StrCat("Did you really mean to set flag '", flag.Name(),
00547                          "' to the value '", value, "'?"));
00548       }
00549     }
00550   }
00551 
00552   return std::make_tuple(true, value);
00553 }
00554 
00555 // --------------------------------------------------------------------
00556 
00557 bool CanIgnoreUndefinedFlag(absl::string_view flag_name) {
00558   auto undefok = absl::GetFlag(FLAGS_undefok);
00559   if (std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
00560     return true;
00561   }
00562 
00563   if (absl::ConsumePrefix(&flag_name, "no") &&
00564       std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
00565     return true;
00566   }
00567 
00568   return false;
00569 }
00570 
00571 }  // namespace
00572 
00573 // --------------------------------------------------------------------
00574 
00575 std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
00576                                         ArgvListAction arg_list_act,
00577                                         UsageFlagsAction usage_flag_act,
00578                                         OnUndefinedFlag on_undef_flag) {
00579   ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
00580 
00581   // This routine does not return anything since we abort on failure.
00582   CheckDefaultValuesParsingRoundtrip();
00583 
00584   std::vector<std::string> flagfile_value;
00585 
00586   std::vector<ArgsList> input_args;
00587   input_args.push_back(ArgsList(argc, argv));
00588 
00589   std::vector<char*> output_args;
00590   std::vector<char*> positional_args;
00591   output_args.reserve(argc);
00592 
00593   // This is the list of undefined flags. The element of the list is the pair
00594   // consisting of boolean indicating if flag came from command line (vs from
00595   // some flag file we've read) and flag name.
00596   // TODO(rogeeff): Eliminate the first element in the pair after cleanup.
00597   std::vector<std::pair<bool, std::string>> undefined_flag_names;
00598 
00599   // Set program invocation name if it is not set before.
00600   if (ProgramInvocationName() == "UNKNOWN") {
00601     flags_internal::SetProgramInvocationName(argv[0]);
00602   }
00603   output_args.push_back(argv[0]);
00604 
00605   // Iterate through the list of the input arguments. First level are arguments
00606   // originated from argc/argv. Following levels are arguments originated from
00607   // recursive parsing of flagfile(s).
00608   bool success = true;
00609   while (!input_args.empty()) {
00610     // 10. First we process the built-in generator flags.
00611     success &= HandleGeneratorFlags(&input_args, &flagfile_value);
00612 
00613     // 30. Select top-most (most recent) arguments list. If it is empty drop it
00614     // and re-try.
00615     ArgsList& curr_list = input_args.back();
00616 
00617     curr_list.PopFront();
00618 
00619     if (curr_list.Size() == 0) {
00620       input_args.pop_back();
00621       continue;
00622     }
00623 
00624     // 40. Pick up the front remaining argument in the current list. If current
00625     // stack of argument lists contains only one element - we are processing an
00626     // argument from the original argv.
00627     absl::string_view arg(curr_list.Front());
00628     bool arg_from_argv = input_args.size() == 1;
00629 
00630     // 50. If argument does not start with - or is just "-" - this is
00631     // positional argument.
00632     if (!absl::ConsumePrefix(&arg, "-") || arg.empty()) {
00633       ABSL_INTERNAL_CHECK(arg_from_argv,
00634                           "Flagfile cannot contain positional argument");
00635 
00636       positional_args.push_back(argv[curr_list.FrontIndex()]);
00637       continue;
00638     }
00639 
00640     if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs)) {
00641       output_args.push_back(argv[curr_list.FrontIndex()]);
00642     }
00643 
00644     // 60. Split the current argument on '=' to figure out the argument
00645     // name and value. If flag name is empty it means we've got "--". value
00646     // can be empty either if there were no '=' in argument std::string at all or
00647     // an argument looked like "--foo=". In a latter case is_empty_value is
00648     // true.
00649     absl::string_view flag_name;
00650     absl::string_view value;
00651     bool is_empty_value = false;
00652 
00653     std::tie(flag_name, value, is_empty_value) = SplitNameAndValue(arg);
00654 
00655     // 70. "--" alone means what it does for GNU: stop flags parsing. We do
00656     // not support positional arguments in flagfiles, so we just drop them.
00657     if (flag_name.empty()) {
00658       ABSL_INTERNAL_CHECK(arg_from_argv,
00659                           "Flagfile cannot contain positional argument");
00660 
00661       curr_list.PopFront();
00662       break;
00663     }
00664 
00665     // 80. Locate the flag based on flag name. Handle both --foo and --nofoo
00666     CommandLineFlag* flag = nullptr;
00667     bool is_negative = false;
00668     std::tie(flag, is_negative) = LocateFlag(flag_name);
00669 
00670     if (flag == nullptr) {
00671       if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
00672         undefined_flag_names.emplace_back(arg_from_argv,
00673                                           std::string(flag_name));
00674       }
00675       continue;
00676     }
00677 
00678     // 90. Deduce flag's value (from this or next argument)
00679     auto curr_index = curr_list.FrontIndex();
00680     bool value_success = true;
00681     std::tie(value_success, value) =
00682         DeduceFlagValue(*flag, value, is_negative, is_empty_value, &curr_list);
00683     success &= value_success;
00684 
00685     // If above call consumed an argument, it was a standalone value
00686     if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs) &&
00687         (curr_index != curr_list.FrontIndex())) {
00688       output_args.push_back(argv[curr_list.FrontIndex()]);
00689     }
00690 
00691     // 100. Set the located flag to a new new value, unless it is retired.
00692     // Setting retired flag fails, but we ignoring it here.
00693     if (flag->IsRetired()) continue;
00694 
00695     std::string error;
00696     if (!flag->SetFromString(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
00697       flags_internal::ReportUsageError(error, true);
00698       success = false;
00699     }
00700   }
00701 
00702   for (const auto& flag_name : undefined_flag_names) {
00703     if (CanIgnoreUndefinedFlag(flag_name.second)) continue;
00704 
00705     flags_internal::ReportUsageError(
00706         absl::StrCat("Unknown command line flag '", flag_name.second, "'"),
00707         true);
00708 
00709     success = false;
00710   }
00711 
00712 #if ABSL_FLAGS_STRIP_NAMES
00713   if (!success) {
00714     flags_internal::ReportUsageError(
00715         "NOTE: command line flags are disabled in this build", true);
00716   }
00717 #endif
00718 
00719   if (!success) {
00720     flags_internal::HandleUsageFlags(std::cout);
00721     std::exit(1);
00722   }
00723 
00724   if (usage_flag_act == UsageFlagsAction::kHandleUsage) {
00725     int exit_code = flags_internal::HandleUsageFlags(std::cout);
00726 
00727     if (exit_code != -1) {
00728       std::exit(exit_code);
00729     }
00730   }
00731 
00732   ResetGeneratorFlags(flagfile_value);
00733 
00734   // Reinstate positional args which were intermixed with flags in the arguments
00735   // list.
00736   for (auto arg : positional_args) {
00737     output_args.push_back(arg);
00738   }
00739 
00740   // All the remaining arguments are positional.
00741   if (!input_args.empty()) {
00742     for (int arg_index = input_args.back().FrontIndex(); arg_index < argc;
00743          ++arg_index) {
00744       output_args.push_back(argv[arg_index]);
00745     }
00746   }
00747 
00748   return output_args;
00749 }
00750 
00751 }  // namespace flags_internal
00752 
00753 // --------------------------------------------------------------------
00754 
00755 std::vector<char*> ParseCommandLine(int argc, char* argv[]) {
00756   return flags_internal::ParseCommandLineImpl(
00757       argc, argv, flags_internal::ArgvListAction::kRemoveParsedArgs,
00758       flags_internal::UsageFlagsAction::kHandleUsage,
00759       flags_internal::OnUndefinedFlag::kAbortIfUndefined);
00760 }
00761 
00762 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15