summaryrefslogtreecommitdiff
path: root/absl/flags
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags')
-rw-r--r--absl/flags/internal/flag.h64
-rw-r--r--absl/flags/internal/parse.h7
-rw-r--r--absl/flags/parse.cc40
-rw-r--r--absl/flags/parse_test.cc22
4 files changed, 119 insertions, 14 deletions
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index f53f484f..b060199e 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -40,6 +40,30 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
+
+// Forward declaration of absl::Flag<T> public API.
+namespace flags_internal {
+template <typename T>
+class Flag;
+} // namespace flags_internal
+
+#if defined(_MSC_VER) && !defined(__clang__)
+template <typename T>
+class Flag;
+#else
+template <typename T>
+using Flag = flags_internal::Flag<T>;
+#endif
+
+template <typename T>
+ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
+
+template <typename T>
+void SetFlag(absl::Flag<T>* flag, const T& v);
+
+template <typename T, typename V>
+void SetFlag(absl::Flag<T>* flag, const V& v);
+
namespace flags_internal {
///////////////////////////////////////////////////////////////////////////////
@@ -596,6 +620,32 @@ class Flag {
flags_internal::StorageKind<T>(), default_arg),
value_() {}
+ // CommandLineFlag interface
+ absl::string_view Name() const { return impl_.Name(); }
+ std::string Filename() const { return impl_.Filename(); }
+ std::string Help() const { return impl_.Help(); }
+ bool IsSpecifiedOnCommandLine() const {
+ return impl_.IsSpecifiedOnCommandLine();
+ }
+ std::string DefaultValue() const { return impl_.DefaultValue(); }
+ std::string CurrentValue() const { return impl_.CurrentValue(); }
+
+ private:
+ template <typename U, bool do_register>
+ friend class FlagRegistrar;
+
+#if !defined(_MSC_VER) || defined(__clang__)
+ template <typename U>
+ friend U absl::GetFlag(const flags_internal::Flag<U>& flag);
+ template <typename U>
+ friend void absl::SetFlag(flags_internal::Flag<U>* flag, const U& v);
+ template <typename U, typename V>
+ friend void absl::SetFlag(flags_internal::Flag<U>* flag, const V& v);
+#else
+ template <typename U>
+ friend class absl::Flag;
+#endif
+
T Get() const {
// See implementation notes in CommandLineFlag::Get().
union U {
@@ -617,20 +667,6 @@ class Flag {
impl_.Write(&v);
}
- // CommandLineFlag interface
- absl::string_view Name() const { return impl_.Name(); }
- std::string Filename() const { return impl_.Filename(); }
- std::string Help() const { return impl_.Help(); }
- bool IsSpecifiedOnCommandLine() const {
- return impl_.IsSpecifiedOnCommandLine();
- }
- std::string DefaultValue() const { return impl_.DefaultValue(); }
- std::string CurrentValue() const { return impl_.CurrentValue(); }
-
- private:
- template <typename U, bool do_register>
- friend class FlagRegistrar;
-
// Flag's data
// The implementation depends on value_ field to be placed exactly after the
// impl_ field, so that impl_ can figure out the offset to the value and
diff --git a/absl/flags/internal/parse.h b/absl/flags/internal/parse.h
index 03e8a07b..d259be73 100644
--- a/absl/flags/internal/parse.h
+++ b/absl/flags/internal/parse.h
@@ -44,6 +44,13 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
UsageFlagsAction usage_flag_act,
OnUndefinedFlag on_undef_flag);
+// --------------------------------------------------------------------
+// Inspect original command line
+
+// Returns true if flag with specified name was either present on the original
+// command line or specified in flag file present on the original command line.
+bool WasPresentOnCommandLine(absl::string_view flag_name);
+
} // namespace flags_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index 66a28a93..2e8f03b4 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -67,6 +67,22 @@ ABSL_CONST_INIT bool fromenv_needs_processing
ABSL_CONST_INIT bool tryfromenv_needs_processing
ABSL_GUARDED_BY(processing_checks_guard) = false;
+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) = nullptr;
+
+struct SpecifiedFlagsCompare {
+ bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const {
+ return a->Name() < b->Name();
+ }
+ bool operator()(const CommandLineFlag* a, absl::string_view b) const {
+ return a->Name() < b;
+ }
+ bool operator()(absl::string_view a, const CommandLineFlag* b) const {
+ return a < b->Name();
+ }
+};
+
} // namespace
} // namespace flags_internal
ABSL_NAMESPACE_END
@@ -577,6 +593,17 @@ bool CanIgnoreUndefinedFlag(absl::string_view flag_name) {
// --------------------------------------------------------------------
+bool WasPresentOnCommandLine(absl::string_view flag_name) {
+ absl::MutexLock l(&specified_flags_guard);
+ ABSL_INTERNAL_CHECK(specified_flags != nullptr,
+ "ParseCommandLine is not invoked yet");
+
+ return std::binary_search(specified_flags->begin(), specified_flags->end(),
+ flag_name, SpecifiedFlagsCompare{});
+}
+
+// --------------------------------------------------------------------
+
std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
ArgvListAction arg_list_act,
UsageFlagsAction usage_flag_act,
@@ -607,6 +634,13 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
}
output_args.push_back(argv[0]);
+ absl::MutexLock l(&specified_flags_guard);
+ if (specified_flags == nullptr) {
+ specified_flags = new std::vector<const CommandLineFlag*>;
+ } else {
+ specified_flags->clear();
+ }
+
// 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).
@@ -702,6 +736,8 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
flag, value, SET_FLAGS_VALUE, kCommandLine, &error)) {
flags_internal::ReportUsageError(error, true);
success = false;
+ } else {
+ specified_flags->push_back(flag);
}
}
@@ -753,6 +789,10 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
}
}
+ // Trim and sort the vector.
+ specified_flags->shrink_to_fit();
+ std::sort(specified_flags->begin(), specified_flags->end(),
+ SpecifiedFlagsCompare{});
return output_args;
}
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
index 065f757a..e6a53ae6 100644
--- a/absl/flags/parse_test.cc
+++ b/absl/flags/parse_test.cc
@@ -869,4 +869,26 @@ TEST_F(ParseDeathTest, TestHelpFlagHandling) {
EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
}
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, WasPresentOnCommandLine) {
+ const char* in_args1[] = {
+ "testbin", "arg1", "--bool_flag",
+ "--int_flag=211", "arg2", "--double_flag=1.1",
+ "--string_flag", "asd", "--",
+ "--some_flag", "arg4",
+ };
+
+ InvokeParse(in_args1);
+
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("bool_flag"));
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("int_flag"));
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("double_flag"));
+ EXPECT_TRUE(flags::WasPresentOnCommandLine("string_flag"));
+ EXPECT_FALSE(flags::WasPresentOnCommandLine("some_flag"));
+ EXPECT_FALSE(flags::WasPresentOnCommandLine("another_flag"));
+}
+
+// --------------------------------------------------------------------
+
} // namespace