// // Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/flags/parse.h" #include <stdlib.h> #include <algorithm> #include <cstdint> #include <cstdlib> #include <fstream> #include <iostream> #include <ostream> #include <string> #include <tuple> #include <utility> #include <vector> #ifdef _WIN32 #include <windows.h> #endif #include "absl/algorithm/container.h" #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/const_init.h" #include "absl/base/thread_annotations.h" #include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" #include "absl/flags/flag.h" #include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/parse.h" #include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/internal/program_name.h" #include "absl/flags/internal/usage.h" #include "absl/flags/reflection.h" #include "absl/flags/usage.h" #include "absl/flags/usage_config.h" #include "absl/strings/ascii.h" #include "absl/strings/internal/damerau_levenshtein_distance.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" #include "absl/synchronization/mutex.h" // -------------------------------------------------------------------- namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { namespace { ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit); ABSL_CONST_INIT bool flagfile_needs_processing ABSL_GUARDED_BY(processing_checks_guard) = …; ABSL_CONST_INIT bool fromenv_needs_processing ABSL_GUARDED_BY(processing_checks_guard) = …; ABSL_CONST_INIT bool tryfromenv_needs_processing ABSL_GUARDED_BY(processing_checks_guard) = …; ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit); ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags ABSL_GUARDED_BY(specified_flags_guard) = …; // Suggesting at most kMaxHints flags in case of misspellings. ABSL_CONST_INIT const size_t kMaxHints = …; // Suggesting only flags which have a smaller distance than kMaxDistance. ABSL_CONST_INIT const size_t kMaxDistance = …; struct SpecifiedFlagsCompare { … }; } // namespace } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl // These flags influence how command line flags are parsed and are only intended // to be set on the command line. Avoid reading or setting them from C++ code. ABSL_FLAG(…); ABSL_FLAG(…); ABSL_FLAG(…); // Rather than reading or setting --undefok from C++ code, please consider using // ABSL_RETIRED_FLAG instead. ABSL_FLAG(…); namespace absl { ABSL_NAMESPACE_BEGIN namespace flags_internal { namespace { class ArgsList { … }; bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) { … } // -------------------------------------------------------------------- // Reads the environment variable with name `name` and stores results in // `value`. If variable is not present in environment returns false, otherwise // returns true. bool GetEnvVar(const char* var_name, std::string& var_value) { … } // -------------------------------------------------------------------- // Returns: // Flag name or empty if arg= -- // Flag value after = in --flag=value (empty if --foo) // "Is empty value" status. True if arg= --foo=, false otherwise. This is // required to separate --foo from --foo=. // For example: // arg return values // "--foo=bar" -> {"foo", "bar", false}. // "--foo" -> {"foo", "", false}. // "--foo=" -> {"foo", "", true}. std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue( absl::string_view arg) { … } // -------------------------------------------------------------------- // Returns: // found flag or nullptr // is negative in case of --nofoo std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) { … } // -------------------------------------------------------------------- // Verify that default values of typed flags must be convertible to string and // back. void CheckDefaultValuesParsingRoundtrip() { … } // -------------------------------------------------------------------- // Returns success status, which is true if we successfully read all flag files, // in which case new ArgLists are appended to the input_args in a reverse order // of file names in the input flagfiles list. This order ensures that flags from // the first flagfile in the input list are processed before the second flagfile // etc. bool ReadFlagfiles(const std::vector<std::string>& flagfiles, std::vector<ArgsList>& input_args) { … } // Returns success status, which is true if were able to locate all environment // variables correctly or if fail_on_absent_in_env is false. The environment // variable names are expected to be of the form `FLAGS_<flag_name>`, where // `flag_name` is a string from the input flag_names list. If successful we // append a single ArgList at the end of the input_args. bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names, std::vector<ArgsList>& input_args, bool fail_on_absent_in_env) { … } // -------------------------------------------------------------------- // Returns success status, which is true if were able to handle all generator // flags (flagfile, fromenv, tryfromemv) successfully. bool HandleGeneratorFlags(std::vector<ArgsList>& input_args, std::vector<std::string>& flagfile_value) { … } // -------------------------------------------------------------------- void ResetGeneratorFlags(const std::vector<std::string>& flagfile_value) { … } // -------------------------------------------------------------------- // Returns: // success status // deduced value // We are also mutating curr_list in case if we need to get a hold of next // argument in the input. std::tuple<bool, absl::string_view> DeduceFlagValue(const CommandLineFlag& flag, absl::string_view value, bool is_negative, bool is_empty_value, ArgsList* curr_list) { … } // -------------------------------------------------------------------- bool CanIgnoreUndefinedFlag(absl::string_view flag_name) { … } // -------------------------------------------------------------------- void ReportUnrecognizedFlags( const std::vector<UnrecognizedFlag>& unrecognized_flags, bool report_as_fatal_error) { … } } // namespace // -------------------------------------------------------------------- bool WasPresentOnCommandLine(absl::string_view flag_name) { … } // -------------------------------------------------------------------- struct BestHints { … }; // Return the list of flags with the smallest Damerau-Levenshtein distance to // the given flag. std::vector<std::string> GetMisspellingHints(const absl::string_view flag) { … } // -------------------------------------------------------------------- std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], UsageFlagsAction usage_flag_action, OnUndefinedFlag undef_flag_action, std::ostream& error_help_output) { … } // -------------------------------------------------------------------- // This function handles all Abseil Flags and built-in usage flags and, if any // help mode was handled, it returns that help mode. The caller of this function // can decide to exit based on the returned help mode. // The caller may decide to handle unrecognized positional arguments and // unrecognized flags first before exiting. // // Returns: // * HelpMode::kFull if parsing errors were detected in recognized arguments // * The HelpMode that was handled in case when `usage_flag_action` is // UsageFlagsAction::kHandleUsage and a usage flag was specified on the // commandline // * Otherwise it returns HelpMode::kNone HelpMode ParseAbseilFlagsOnlyImpl( int argc, char* argv[], std::vector<char*>& positional_args, std::vector<UnrecognizedFlag>& unrecognized_flags, UsageFlagsAction usage_flag_action) { … } } // namespace flags_internal void ParseAbseilFlagsOnly(int argc, char* argv[], std::vector<char*>& positional_args, std::vector<UnrecognizedFlag>& unrecognized_flags) { … } // -------------------------------------------------------------------- void ReportUnrecognizedFlags( const std::vector<UnrecognizedFlag>& unrecognized_flags) { … } // -------------------------------------------------------------------- std::vector<char*> ParseCommandLine(int argc, char* argv[]) { … } ABSL_NAMESPACE_END } // namespace absl