summaryrefslogtreecommitdiff
path: root/absl/flags/parse.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2019-08-08 10:56:58 -0700
committerGravatar CJ Johnson <johnsoncj@google.com>2019-08-08 14:19:45 -0400
commitaa844899c937bde5d2b24f276b59997e5b668bde (patch)
treecd18e64150abc74b85bbbf6abf990f66fa47cacd /absl/flags/parse.cc
parentfcb104594b0bb4b8ac306cb2f55ecdad40974683 (diff)
Creation of LTS branch "lts_2019_08_08"20190808
- 9ee91d3e430fb33a4590486573792eb0fa146c2d Export of internal Abseil changes by Abseil Team <absl-team@google.com> - 8efba58a3b656e9b41fb0471ae6453425a61c520 Export of internal Abseil changes by Abseil Team <absl-team@google.com> - b49b8d16b67ec6912899684b732e6367f258cfdb Export of internal Abseil changes by Abseil Team <absl-team@google.com> - 67222ffc4c83d918ce8395aa61769eeb77df4c4d Export of internal Abseil changes by Abseil Team <absl-team@google.com> - c5c4db4f5191fe5e76cbf68dcc71fb28702f7d2b Export of internal Abseil changes by Abseil Team <absl-team@google.com> - 14550beb3b7b97195e483fb74b5efb906395c31e Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 52e88ee56b72cf32bc66534d942c7398ce481331 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 36d37ab992038f52276ca66b9da80c1cf0f57dc2 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - ad1485c8986246b2ae9105e512738d0e97aec887 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - f3840bc5e33ce4932e35986cf3718450c6f02af2 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 278b26058c036833a4f7f3047d3f4d9296527f87 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - c6c3c1b498e4ee939b24be59cae29d59c3863be8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 44efe96dfca674a17b45ca53fc77fb69f1e29bf4 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 3c98fcc0461bd2a4b9c149d4748a7373a225cf4b Merge pull request #340 from jtsylve/macos_cxx17_fix by Matt Calabrese <38107210+mattcalabrese-google@users.noreply.github.com> - 74d91756c11bc22f9b0108b94da9326f7f9e376f Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - e6b050212c859fbaf67abac76105da10ec348274 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - c964fcffac27bd4a9ff67fe393410dd1146ef8b8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 72e09a54d993b192db32be14c65adf7e9bd08c31 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - d65e19dfcd8697076f68598c0131c6930cdcd74d Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 5162fc83d2f3b79a9753ed59594c43966afdd37a Merge pull request #336 from shields/patch-2 by Shaindel Schwartz <31392632+shaindelschwartz@users.noreply.github.com> - 0389f7bf58fa41f35b3ad60be61d32f31e4f8ed6 Merge pull request #335 from shields/patch-1 by Shaindel Schwartz <31392632+shaindelschwartz@users.noreply.github.com> - e9324d926a9189e222741fce6e676f0944661a72 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 43ef2148c0936ebf7cb4be6b19927a9d9d145b8f Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - a13d3df2b3ba68aeead92e2d078fba0510d55024 Merge pull request #323 from gosnik/master by Gennadiy Rozental <rogeeff@google.com> - 310a11865c97c5cdcc42a4ee2c2e3578423afe69 Merge pull request #324 from RasPat1/patch-1 by Gennadiy Rozental <rogeeff@google.com> - 8f11724067248acc330b4d1f12f0c76d03f2cfb1 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - b1dd425423380126f6441ce4fbb6f8f6c75b793a Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 361cb8a9db2f2130442389fd80593255be26d681 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 0238ab0a831f179518c1a814f9584e99da2d75a3 Merge pull request #321 from christoph-cullmann/c4245_fix... by Xiaoyi Zhang <zhangxy988@gmail.com> - 61c9bf3e3e1c28a4aa6d7f1be4b37fd473bb5529 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - bc9101f9982391019521161a36179b52555ed212 Merge pull request #320 from christoph-cullmann/master by Xiaoyi Zhang <zhangxy988@gmail.com> - 2f76a9bf50046e396138cc8eeb3cdc17b7a5ac24 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 4adaf5490921f13028b55018c9f550277de5aebb Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 27c30ec671cb7b5ba84c4e79feff7fd0b0ac6338 Avoid undefined behavior when nullptr is passed to memcpy... by Roman Gershman <romange@gmail.com> - ce65f5ac3cbf897bb5e3de1a51d80fd00866abaa Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - a18fc7461e7409c2ad64e28537261db1e02e76fa Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 8a394b19c149cab50534b04c5e21d42bc2217a7d Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - daf381e8535a1f1f1b8a75966a74e7cca63dee89 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - fa00c321073c7ea40a4fc3dfc8a06309eae3d025 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 436ba6c4a0ea3a06eca6e055f9c8d296bf3bae12 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 0cbdc774b97f7e80ab60dbe2ed4eaca3b2e33fc8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 27c2f6e2f3b5929fbd322b0f0ca392eb02efd9f8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - aa468ad75539619b47979911297efbb629c52e44 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - cd86d0d20ab167c33b23d3875db68d1d4bad3a3b Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 33841c5c963aa9c3f096ef8e6c1e71624b941940 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - ca3f87560a0eef716195cadf66dc6b938a579ec6 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - d902eb869bcfacc1bad14933ed9af4bed006d481 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - a02f62f456f2c4a7ecf2be3104fe0c6e16fbad9a Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 0b545b460141b882b244a1efcef7621d59278160 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - dbae8764fbd429bf7d7745e24bcf73962177a7c0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 044da8a29c923506af0f0b46bc46f43c1e1300b5 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 6cc6ac44e065b9e8975fadfd6ccb99cbcf89aac4 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 666fc1266bccfd8e6eaaa084e7b42580bb8eb199 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 93dfcf74cb5fccae3da07897d8613ae6cab958a0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 2c8421e1c6cef0da9e8a20b01c15256ec9ec116d Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 5b65c4af5107176555b23a638e5947686410ac1f Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - eab2078b53c9e3d9d240135c09d27e3393acb50a Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 253eb7416421661873afbaa33828a850db978541 [CMake] Set correct flags for clang-cl (#278) by Loo Rong Jie <loorongjie@gmail.com> - e75672f6afc7e8f23ee7b532e86d1b3b9be3984e Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - bf29470384a101b307873b26d358433138c857fc Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 6fd827124facd8336981e73218997f9e73029b4f Merge pull request #280 from chiumichael/master by Derek Mauro <761129+derekmauro@users.noreply.github.com> - 7c7754fb3ed9ffb57d35fe8658f3ba4d73a31e72 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 256be563447a315f2a7993ec669460ba475fa86a Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 88a152ae747c3c42dc9167d46c590929b048d436 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - c1cecb25a94c075725e9d2640f6b978a8f61957b Implement Span::first and Span::last from C++20 (#274) by Girts <girtsf@users.noreply.github.com> - 38b704384cd2f17590b3922b97744be0b43622c9 Changed HTTP URLs to HTTPS where possible (#270) by nik7273 <nik8470@gmail.com> - febc5ee6a92d0eb7dac1fceaa6c648cf6521b4dc Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 9fdf5e5b805412cb2a2e624d3e9a11588120465f Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 419f3184f8ebcdb23105295eadd2a569f3351eb9 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - b312c3cb53a0aad75a85ac2bf57c4a614fbd48d4 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 308ce31528a7edfa39f5f6d36142278a0ae1bf45 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 93d155bc4414f6c121bb1f19dba9fdb27c8943bc Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 426eaa4aa44e4580418bee46c1bd13911151bfb1 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 2901ec32a919311384d6ad4194e2d927c06831f7 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - d78310fe5a82f2e0e6e16509ef8079c8d7e4674e Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - a4cb1c8ba61531a63f9d309eea01ac1d43d8371d Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 540e2537b92cd4abfae6ceddfe24304345461f32 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 89ea0c5ff34aaa5855cfc7aa41f323b8a0ef0ede Merge pull request #255 from uilianries/hotfix/conan by ahedberg <ahedberg@google.com> - 5e0dcf72c64fae912184d2e0de87195fe8f0a425 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 0dffca4e36791c7beeda04da10460b534283948a Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 6b4201f9ef650637510a21b8d6cbcc3bee4a606f Fix GCC8 warnings by Boris Staletic <boris.staletic@gmail.com> - 0b1e6d417b414aad9282e32e8c49c719edeb63c1 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - efccc502606bed768e50a6cd5806d8eb13e4e935 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 5e6a78131f7bd5940218462c07d88cdefdd75dbe Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 5eea0f713c14ac17788b83e496f11903f8e2bbb0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 66f9becbb98ecc083f4db349b4b1e0ca9de93b15 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 018b4db1d73ec8238e6dc4b17fd9e1fd7468d0ed Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 9449ae94397f2fd683851348e25ed8c93f75b3b9 Merge pull request #243 from ThomsonTan/FixIntrinsic by Alex Strelnikov <strel@google.com> - b16aeb6756bdab08cdf12d40baab5b51f7d15b16 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 7ffbe09f3d85504bd018783bbe1e2c12992fe47c Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 01b471d9f3ebef27f5aaca14b66509099fa8cd6c Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 7bd8f36c741c7cbe311611d7981bf38ba04c6fef Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 968a34ffdaadd7db062a9621dfbdf8b2d16e05af Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 3e2e9b5557e76d098de4b8a2a659125b98ca519b Merge pull request #231 from uilianries/feature/conan by Mark Barolak <mbxx@users.noreply.github.com> - 111ca7060a6ff50115ca85b59f6b5d8c8c5e9105 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 389ec3f906f018661a5308458d623d01f96d7b23 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 8fbcdb90952c57828c4a9c2f6d79fcd7cae9088f Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 455dc17ba1af9635f0b60155bc565bc572a1e722 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - f197d7c72a54064cfde5a2058f1513a4a0ee36fb Export of internal Abseil changes. by Abseil Team <absl-team@google.com> - 284378a71b32dfb3af4e3661f585e671d1b603a3 Export of internal Abseil changes. by Abseil Team <absl-team@google.com> GitOrigin-RevId: 9ee91d3e430fb33a4590486573792eb0fa146c2d Change-Id: Ia06e548bc106cc9d136f6c65714be6645317aced
Diffstat (limited to 'absl/flags/parse.cc')
-rw-r--r--absl/flags/parse.cc755
1 files changed, 755 insertions, 0 deletions
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
new file mode 100644
index 00000000..fd80a0c8
--- /dev/null
+++ b/absl/flags/parse.cc
@@ -0,0 +1,755 @@
+//
+// 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 <fstream>
+#include <iostream>
+#include <tuple>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/program_name.h"
+#include "absl/flags/internal/registry.h"
+#include "absl/flags/internal/usage.h"
+#include "absl/flags/usage.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/strip.h"
+#include "absl/synchronization/mutex.h"
+
+// --------------------------------------------------------------------
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+namespace {
+
+ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit);
+
+ABSL_CONST_INIT bool flagfile_needs_processing
+ GUARDED_BY(processing_checks_guard) = false;
+ABSL_CONST_INIT bool fromenv_needs_processing
+ GUARDED_BY(processing_checks_guard) = false;
+ABSL_CONST_INIT bool tryfromenv_needs_processing
+ GUARDED_BY(processing_checks_guard) = false;
+
+} // namespace
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+ABSL_FLAG(std::vector<std::string>, flagfile, {},
+ "comma-separated list of files to load flags from")
+ .OnUpdate([]() {
+ if (absl::GetFlag(FLAGS_flagfile).empty()) return;
+
+ absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+
+ // Setting this flag twice before it is handled most likely an internal
+ // error and should be reviewed by developers.
+ if (absl::flags_internal::flagfile_needs_processing) {
+ ABSL_INTERNAL_LOG(WARNING, "flagfile set twice before it is handled");
+ }
+
+ absl::flags_internal::flagfile_needs_processing = true;
+ });
+ABSL_FLAG(std::vector<std::string>, fromenv, {},
+ "comma-separated list of flags to set from the environment"
+ " [use 'export FLAGS_flag1=value']")
+ .OnUpdate([]() {
+ if (absl::GetFlag(FLAGS_fromenv).empty()) return;
+
+ absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+
+ // Setting this flag twice before it is handled most likely an internal
+ // error and should be reviewed by developers.
+ if (absl::flags_internal::fromenv_needs_processing) {
+ ABSL_INTERNAL_LOG(WARNING, "fromenv set twice before it is handled.");
+ }
+
+ absl::flags_internal::fromenv_needs_processing = true;
+ });
+ABSL_FLAG(std::vector<std::string>, tryfromenv, {},
+ "comma-separated list of flags to try to set from the environment if "
+ "present")
+ .OnUpdate([]() {
+ if (absl::GetFlag(FLAGS_tryfromenv).empty()) return;
+
+ absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+
+ // Setting this flag twice before it is handled most likely an internal
+ // error and should be reviewed by developers.
+ if (absl::flags_internal::tryfromenv_needs_processing) {
+ ABSL_INTERNAL_LOG(WARNING,
+ "tryfromenv set twice before it is handled.");
+ }
+
+ absl::flags_internal::tryfromenv_needs_processing = true;
+ });
+
+ABSL_FLAG(std::vector<std::string>, undefok, {},
+ "comma-separated list of flag names that it is okay to specify "
+ "on the command line even if the program does not define a flag "
+ "with that name");
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+namespace {
+
+class ArgsList {
+ public:
+ ArgsList() : next_arg_(0) {}
+ ArgsList(int argc, char* argv[]) : args_(argv, argv + argc), next_arg_(0) {}
+ explicit ArgsList(const std::vector<std::string>& args)
+ : args_(args), next_arg_(0) {}
+
+ // Returns success status: true if parsing successful, false otherwise.
+ bool ReadFromFlagfile(const std::string& flag_file_name);
+
+ int Size() const { return args_.size() - next_arg_; }
+ int FrontIndex() const { return next_arg_; }
+ absl::string_view Front() const { return args_[next_arg_]; }
+ void PopFront() { next_arg_++; }
+
+ private:
+ std::vector<std::string> args_;
+ int next_arg_;
+};
+
+bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) {
+ std::ifstream flag_file(flag_file_name);
+
+ if (!flag_file) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Can't open flagfile ", flag_file_name), true);
+
+ return false;
+ }
+
+ // This argument represents fake argv[0], which should be present in all arg
+ // lists.
+ args_.push_back("");
+
+ std::string line;
+ bool success = true;
+
+ while (std::getline(flag_file, line)) {
+ absl::string_view stripped = absl::StripLeadingAsciiWhitespace(line);
+
+ if (stripped.empty() || stripped[0] == '#') {
+ // Comment or empty line; just ignore.
+ continue;
+ }
+
+ if (stripped[0] == '-') {
+ if (stripped == "--") {
+ flags_internal::ReportUsageError(
+ "Flagfile can't contain position arguments or --", true);
+
+ success = false;
+ break;
+ }
+
+ args_.push_back(std::string(stripped));
+ continue;
+ }
+
+ flags_internal::ReportUsageError(
+ absl::StrCat("Unexpected line in the flagfile ", flag_file_name, ": ",
+ line),
+ true);
+
+ success = false;
+ }
+
+ return success;
+}
+
+// --------------------------------------------------------------------
+
+// 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) {
+#ifdef _WIN32
+ char buf[1024];
+ auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
+ if (get_res >= sizeof(buf)) {
+ return false;
+ }
+
+ if (get_res == 0) {
+ return false;
+ }
+
+ *var_value = std::string(buf, get_res);
+#else
+ const char* val = ::getenv(var_name);
+ if (val == nullptr) {
+ return false;
+ }
+
+ *var_value = val;
+#endif
+
+ return true;
+}
+
+// --------------------------------------------------------------------
+
+// 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) {
+ // Allow -foo and --foo
+ absl::ConsumePrefix(&arg, "-");
+
+ if (arg.empty()) {
+ return std::make_tuple("", "", false);
+ }
+
+ auto equal_sign_pos = arg.find("=");
+
+ absl::string_view flag_name = arg.substr(0, equal_sign_pos);
+
+ absl::string_view value;
+ bool is_empty_value = false;
+
+ if (equal_sign_pos != absl::string_view::npos) {
+ value = arg.substr(equal_sign_pos + 1);
+ is_empty_value = value.empty();
+ }
+
+ return std::make_tuple(flag_name, value, is_empty_value);
+}
+
+// --------------------------------------------------------------------
+
+// Returns:
+// found flag or nullptr
+// is negative in case of --nofoo
+std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
+ bool is_negative = false;
+
+ if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
+ flag = flags_internal::FindCommandLineFlag(flag_name);
+ is_negative = true;
+ }
+
+ return std::make_tuple(flag, is_negative);
+}
+
+// --------------------------------------------------------------------
+
+// Verify that default values of typed flags must be convertible to string and
+// back.
+void CheckDefaultValuesParsingRoundtrip() {
+#ifndef NDEBUG
+ flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
+ if (flag->IsRetired()) return;
+
+#define IGNORE_TYPE(T) \
+ if (flag->IsOfType<T>()) return;
+
+ ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(IGNORE_TYPE)
+ IGNORE_TYPE(std::string)
+ IGNORE_TYPE(std::vector<std::string>)
+#undef IGNORE_TYPE
+
+ flag->CheckDefaultValueParsingRoundtrip();
+ });
+#endif
+}
+
+// --------------------------------------------------------------------
+
+// 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) {
+ bool success = true;
+ for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
+ ArgsList al;
+
+ if (al.ReadFromFlagfile(*it)) {
+ input_args->push_back(al);
+ } else {
+ success = false;
+ }
+ }
+
+ return success;
+}
+
+// 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) {
+ bool success = true;
+ std::vector<std::string> args;
+
+ // This argument represents fake argv[0], which should be present in all arg
+ // lists.
+ args.push_back("");
+
+ for (const auto& flag_name : flag_names) {
+ // Avoid infinite recursion.
+ if (flag_name == "fromenv" || flag_name == "tryfromenv") {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Infinite recursion on flag ", flag_name), true);
+
+ success = false;
+ continue;
+ }
+
+ const std::string envname = absl::StrCat("FLAGS_", flag_name);
+ std::string envval;
+ if (!GetEnvVar(envname.c_str(), &envval)) {
+ if (fail_on_absent_in_env) {
+ flags_internal::ReportUsageError(
+ absl::StrCat(envname, " not found in environment"), true);
+
+ success = false;
+ }
+
+ continue;
+ }
+
+ args.push_back(absl::StrCat("--", flag_name, "=", envval));
+ }
+
+ if (success) {
+ input_args->emplace_back(args);
+ }
+
+ return success;
+}
+
+// --------------------------------------------------------------------
+
+// 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) {
+ bool success = true;
+
+ absl::MutexLock l(&flags_internal::processing_checks_guard);
+
+ // flagfile could have been set either on a command line or
+ // programmatically before invoking ParseCommandLine. Note that we do not
+ // actually process arguments specified in the flagfile, but instead
+ // create a secondary arguments list to be processed along with the rest
+ // of the comamnd line arguments. Since we always the process most recently
+ // created list of arguments first, this will result in flagfile argument
+ // being processed before any other argument in the command line. If
+ // FLAGS_flagfile contains more than one file name we create multiple new
+ // levels of arguments in a reverse order of file names. Thus we always
+ // process arguments from first file before arguments containing in a
+ // second file, etc. If flagfile contains another
+ // --flagfile inside of it, it will produce new level of arguments and
+ // processed before the rest of the flagfile. We are also collecting all
+ // flagfiles set on original command line. Unlike the rest of the flags,
+ // this flag can be set multiple times and is expected to be handled
+ // multiple times. We are collecting them all into a single list and set
+ // the value of FLAGS_flagfile to that value at the end of the parsing.
+ if (flags_internal::flagfile_needs_processing) {
+ auto flagfiles = absl::GetFlag(FLAGS_flagfile);
+
+ if (input_args->size() == 1) {
+ flagfile_value->insert(flagfile_value->end(), flagfiles.begin(),
+ flagfiles.end());
+ }
+
+ success &= ReadFlagfiles(flagfiles, input_args);
+
+ flags_internal::flagfile_needs_processing = false;
+ }
+
+ // Similar to flagfile fromenv/tryfromemv can be set both
+ // programmatically and at runtime on a command line. Unlike flagfile these
+ // can't be recursive.
+ if (flags_internal::fromenv_needs_processing) {
+ auto flags_list = absl::GetFlag(FLAGS_fromenv);
+
+ success &= ReadFlagsFromEnv(flags_list, input_args, true);
+
+ flags_internal::fromenv_needs_processing = false;
+ }
+
+ if (flags_internal::tryfromenv_needs_processing) {
+ auto flags_list = absl::GetFlag(FLAGS_tryfromenv);
+
+ success &= ReadFlagsFromEnv(flags_list, input_args, false);
+
+ flags_internal::tryfromenv_needs_processing = false;
+ }
+
+ return success;
+}
+
+// --------------------------------------------------------------------
+
+void ResetGeneratorFlags(const std::vector<std::string>& flagfile_value) {
+ // Setting flagfile to the value which collates all the values set on a
+ // command line and programmatically. So if command line looked like
+ // --flagfile=f1 --flagfile=f2 the final value of the FLAGS_flagfile flag is
+ // going to be {"f1", "f2"}
+ if (!flagfile_value.empty()) {
+ absl::SetFlag(&FLAGS_flagfile, flagfile_value);
+ absl::MutexLock l(&flags_internal::processing_checks_guard);
+ flags_internal::flagfile_needs_processing = false;
+ }
+
+ // fromenv/tryfromenv are set to <undefined> value.
+ if (!absl::GetFlag(FLAGS_fromenv).empty()) {
+ absl::SetFlag(&FLAGS_fromenv, {});
+ }
+ if (!absl::GetFlag(FLAGS_tryfromenv).empty()) {
+ absl::SetFlag(&FLAGS_tryfromenv, {});
+ }
+
+ absl::MutexLock l(&flags_internal::processing_checks_guard);
+ flags_internal::fromenv_needs_processing = false;
+ flags_internal::tryfromenv_needs_processing = false;
+}
+
+// --------------------------------------------------------------------
+
+// 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) {
+ // Value is either an argument suffix after `=` in "--foo=<value>"
+ // or separate argument in case of "--foo" "<value>".
+
+ // boolean flags have these forms:
+ // --foo
+ // --nofoo
+ // --foo=true
+ // --foo=false
+ // --nofoo=<value> is not supported
+ // --foo <value> is not supported
+
+ // non boolean flags have these forms:
+ // --foo=<value>
+ // --foo <value>
+ // --nofoo is not supported
+
+ if (flag.IsOfType<bool>()) {
+ if (value.empty()) {
+ if (is_empty_value) {
+ // "--bool_flag=" case
+ flags_internal::ReportUsageError(
+ absl::StrCat(
+ "Missing the value after assignment for the boolean flag '",
+ flag.Name(), "'"),
+ true);
+ return std::make_tuple(false, "");
+ }
+
+ // "--bool_flag" case
+ value = is_negative ? "0" : "1";
+ } else if (is_negative) {
+ // "--nobool_flag=Y" case
+ flags_internal::ReportUsageError(
+ absl::StrCat("Negative form with assignment is not valid for the "
+ "boolean flag '",
+ flag.Name(), "'"),
+ true);
+ return std::make_tuple(false, "");
+ }
+ } else if (is_negative) {
+ // "--noint_flag=1" case
+ flags_internal::ReportUsageError(
+ absl::StrCat("Negative form is not valid for the flag '", flag.Name(),
+ "'"),
+ true);
+ return std::make_tuple(false, "");
+ } else if (value.empty() && (!is_empty_value)) {
+ if (curr_list->Size() == 1) {
+ // "--int_flag" case
+ flags_internal::ReportUsageError(
+ absl::StrCat("Missing the value for the flag '", flag.Name(), "'"),
+ true);
+ return std::make_tuple(false, "");
+ }
+
+ // "--int_flag" "10" case
+ curr_list->PopFront();
+ value = curr_list->Front();
+
+ // Heuristic to detect the case where someone treats a std::string arg
+ // like a bool or just forgets to pass a value:
+ // --my_string_var --foo=bar
+ // We look for a flag of std::string type, whose value begins with a
+ // dash and corresponds to known flag or standalone --.
+ if (value[0] == '-' && flag.IsOfType<std::string>()) {
+ auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
+
+ if (maybe_flag_name.empty() ||
+ std::get<0>(LocateFlag(maybe_flag_name)) != nullptr) {
+ // "--string_flag" "--known_flag" case
+ ABSL_INTERNAL_LOG(
+ WARNING,
+ absl::StrCat("Did you really mean to set flag '", flag.Name(),
+ "' to the value '", value, "'?"));
+ }
+ }
+ }
+
+ return std::make_tuple(true, value);
+}
+
+// --------------------------------------------------------------------
+
+bool CanIgnoreUndefinedFlag(absl::string_view flag_name) {
+ auto undefok = absl::GetFlag(FLAGS_undefok);
+ if (std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
+ return true;
+ }
+
+ if (absl::ConsumePrefix(&flag_name, "no") &&
+ std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+// --------------------------------------------------------------------
+
+std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
+ ArgvListAction arg_list_act,
+ UsageFlagsAction usage_flag_act,
+ OnUndefinedFlag on_undef_flag) {
+ ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
+
+ // This routine does not return anything since we abort on failure.
+ CheckDefaultValuesParsingRoundtrip();
+
+ std::vector<std::string> flagfile_value;
+
+ std::vector<ArgsList> input_args;
+ input_args.push_back(ArgsList(argc, argv));
+
+ std::vector<char*> output_args;
+ std::vector<char*> positional_args;
+ output_args.reserve(argc);
+
+ // This is the list of undefined flags. The element of the list is the pair
+ // consisting of boolean indicating if flag came from command line (vs from
+ // some flag file we've read) and flag name.
+ // TODO(rogeeff): Eliminate the first element in the pair after cleanup.
+ std::vector<std::pair<bool, std::string>> undefined_flag_names;
+
+ // Set program invocation name if it is not set before.
+ if (ProgramInvocationName() == "UNKNOWN") {
+ flags_internal::SetProgramInvocationName(argv[0]);
+ }
+ output_args.push_back(argv[0]);
+
+ // Iterate through the list of the input arguments. First level are arguments
+ // originated from argc/argv. Following levels are arguments originated from
+ // recursive parsing of flagfile(s).
+ bool success = true;
+ while (!input_args.empty()) {
+ // 10. First we process the built-in generator flags.
+ success &= HandleGeneratorFlags(&input_args, &flagfile_value);
+
+ // 30. Select top-most (most recent) arguments list. If it is empty drop it
+ // and re-try.
+ ArgsList& curr_list = input_args.back();
+
+ curr_list.PopFront();
+
+ if (curr_list.Size() == 0) {
+ input_args.pop_back();
+ continue;
+ }
+
+ // 40. Pick up the front remaining argument in the current list. If current
+ // stack of argument lists contains only one element - we are processing an
+ // argument from the original argv.
+ absl::string_view arg(curr_list.Front());
+ bool arg_from_argv = input_args.size() == 1;
+
+ // 50. If argument does not start with - or is just "-" - this is
+ // positional argument.
+ if (!absl::ConsumePrefix(&arg, "-") || arg.empty()) {
+ ABSL_INTERNAL_CHECK(arg_from_argv,
+ "Flagfile cannot contain positional argument");
+
+ positional_args.push_back(argv[curr_list.FrontIndex()]);
+ continue;
+ }
+
+ if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs)) {
+ output_args.push_back(argv[curr_list.FrontIndex()]);
+ }
+
+ // 60. Split the current argument on '=' to figure out the argument
+ // name and value. If flag name is empty it means we've got "--". value
+ // can be empty either if there were no '=' in argument std::string at all or
+ // an argument looked like "--foo=". In a latter case is_empty_value is
+ // true.
+ absl::string_view flag_name;
+ absl::string_view value;
+ bool is_empty_value = false;
+
+ std::tie(flag_name, value, is_empty_value) = SplitNameAndValue(arg);
+
+ // 70. "--" alone means what it does for GNU: stop flags parsing. We do
+ // not support positional arguments in flagfiles, so we just drop them.
+ if (flag_name.empty()) {
+ ABSL_INTERNAL_CHECK(arg_from_argv,
+ "Flagfile cannot contain positional argument");
+
+ curr_list.PopFront();
+ break;
+ }
+
+ // 80. Locate the flag based on flag name. Handle both --foo and --nofoo
+ CommandLineFlag* flag = nullptr;
+ bool is_negative = false;
+ std::tie(flag, is_negative) = LocateFlag(flag_name);
+
+ if (flag == nullptr) {
+ if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
+ undefined_flag_names.emplace_back(arg_from_argv,
+ std::string(flag_name));
+ }
+ continue;
+ }
+
+ // 90. Deduce flag's value (from this or next argument)
+ auto curr_index = curr_list.FrontIndex();
+ bool value_success = true;
+ std::tie(value_success, value) =
+ DeduceFlagValue(*flag, value, is_negative, is_empty_value, &curr_list);
+ success &= value_success;
+
+ // If above call consumed an argument, it was a standalone value
+ if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs) &&
+ (curr_index != curr_list.FrontIndex())) {
+ output_args.push_back(argv[curr_list.FrontIndex()]);
+ }
+
+ // 100. Set the located flag to a new new value, unless it is retired.
+ // Setting retired flag fails, but we ignoring it here.
+ if (flag->IsRetired()) continue;
+
+ std::string error;
+ if (!flag->SetFromString(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
+ flags_internal::ReportUsageError(error, true);
+ success = false;
+ }
+ }
+
+ for (const auto& flag_name : undefined_flag_names) {
+ if (CanIgnoreUndefinedFlag(flag_name.second)) continue;
+
+ flags_internal::ReportUsageError(
+ absl::StrCat("Unknown command line flag '", flag_name.second, "'"),
+ true);
+
+ success = false;
+ }
+
+#if ABSL_FLAGS_STRIP_NAMES
+ if (!success) {
+ flags_internal::ReportUsageError(
+ "NOTE: command line flags are disabled in this build", true);
+ }
+#endif
+
+ if (!success) {
+ flags_internal::HandleUsageFlags(std::cout,
+ ProgramUsageMessage());
+ std::exit(1);
+ }
+
+ if (usage_flag_act == UsageFlagsAction::kHandleUsage) {
+ int exit_code = flags_internal::HandleUsageFlags(
+ std::cout, ProgramUsageMessage());
+
+ if (exit_code != -1) {
+ std::exit(exit_code);
+ }
+ }
+
+ ResetGeneratorFlags(flagfile_value);
+
+ // Reinstate positional args which were intermixed with flags in the arguments
+ // list.
+ for (auto arg : positional_args) {
+ output_args.push_back(arg);
+ }
+
+ // All the remaining arguments are positional.
+ if (!input_args.empty()) {
+ for (int arg_index = input_args.back().FrontIndex(); arg_index < argc;
+ ++arg_index) {
+ output_args.push_back(argv[arg_index]);
+ }
+ }
+
+ return output_args;
+}
+
+} // namespace flags_internal
+
+// --------------------------------------------------------------------
+
+std::vector<char*> ParseCommandLine(int argc, char* argv[]) {
+ return flags_internal::ParseCommandLineImpl(
+ argc, argv, flags_internal::ArgvListAction::kRemoveParsedArgs,
+ flags_internal::UsageFlagsAction::kHandleUsage,
+ flags_internal::OnUndefinedFlag::kAbortIfUndefined);
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl