diff options
Diffstat (limited to 'absl')
-rw-r--r-- | absl/log/CMakeLists.txt | 31 | ||||
-rw-r--r-- | absl/log/internal/BUILD.bazel | 23 | ||||
-rw-r--r-- | absl/log/internal/fnmatch.cc | 53 | ||||
-rw-r--r-- | absl/log/internal/fnmatch.h | 35 | ||||
-rw-r--r-- | absl/log/internal/fnmatch_test.cc | 59 |
5 files changed, 201 insertions, 0 deletions
diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 2fc34d01..2c3307dc 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt @@ -671,6 +671,22 @@ absl_cc_library( PUBLIC ) +absl_cc_library( + NAME + log_internal_fnmatch + SRCS + "internal/fnmatch.cc" + HDRS + "internal/fnmatch.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::config + absl::strings +) + # Test targets absl_cc_test( @@ -1041,3 +1057,18 @@ absl_cc_test( GTest::gmock GTest::gtest_main ) + +absl_cc_test( + NAME + internal_fnmatch_test + SRCS + "internal/fnmatch_test.cc" + COPTS + ${ABSL_TEST_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::log_internal_fnmatch + GTest::gmock + GTest::gtest_main +)
\ No newline at end of file diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel index 555c5e5c..b8077a77 100644 --- a/absl/log/internal/BUILD.bazel +++ b/absl/log/internal/BUILD.bazel @@ -357,6 +357,18 @@ cc_library( ], ) +cc_library( + name = "fnmatch", + srcs = ["fnmatch.cc"], + hdrs = ["fnmatch.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + "//absl/base:config", + "//absl/strings", + ], +) + # Test targets cc_test( name = "stderr_log_sink_test", @@ -381,3 +393,14 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "fnmatch_test", + srcs = ["fnmatch_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":fnmatch", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/absl/log/internal/fnmatch.cc b/absl/log/internal/fnmatch.cc new file mode 100644 index 00000000..be4e4b1c --- /dev/null +++ b/absl/log/internal/fnmatch.cc @@ -0,0 +1,53 @@ +// Copyright 2023 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/log/internal/fnmatch.h" + +#include "absl/base/config.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace log_internal { +bool FNMatch(absl::string_view pattern, absl::string_view str) { + while (true) { + if (pattern.empty()) { + // `pattern` is exhausted; succeed if all of `str` was consumed matching + // it. + return str.empty(); + } + if (str.empty()) { + // `str` is exhausted; succeed if `pattern` is empty or all '*'s. + return pattern.find_first_not_of('*') == pattern.npos; + } + if (pattern.front() == '*') { + pattern.remove_prefix(1); + if (pattern.empty()) return true; + do { + if (FNMatch(pattern, str)) return true; + str.remove_prefix(1); + } while (!str.empty()); + return false; + } + if (pattern.front() == '?' || pattern.front() == str.front()) { + pattern.remove_prefix(1); + str.remove_prefix(1); + continue; + } + return false; + } +} +} // namespace log_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/absl/log/internal/fnmatch.h b/absl/log/internal/fnmatch.h new file mode 100644 index 00000000..4ea147cc --- /dev/null +++ b/absl/log/internal/fnmatch.h @@ -0,0 +1,35 @@ +// Copyright 2023 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. + +#ifndef ABSL_LOG_INTERNAL_FNMATCH_H_ +#define ABSL_LOG_INTERNAL_FNMATCH_H_ + +#include "absl/base/config.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace log_internal { +// Like POSIX `fnmatch`, but: +// * accepts `string_view` +// * does not allocate any dynamic memory +// * only supports * and ? wildcards and not bracket expressions [...] +// * wildcards may match / +// * no backslash-escaping +bool FNMatch(absl::string_view pattern, absl::string_view str); +} // namespace log_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_LOG_INTERNAL_FNMATCH_H_ diff --git a/absl/log/internal/fnmatch_test.cc b/absl/log/internal/fnmatch_test.cc new file mode 100644 index 00000000..e16a64ec --- /dev/null +++ b/absl/log/internal/fnmatch_test.cc @@ -0,0 +1,59 @@ +// Copyright 2023 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/log/internal/fnmatch.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace { +using ::testing::IsFalse; +using ::testing::IsTrue; + +TEST(FNMatchTest, Works) { + using absl::log_internal::FNMatch; + EXPECT_THAT(FNMatch("foo", "foo"), IsTrue()); + EXPECT_THAT(FNMatch("foo", "bar"), IsFalse()); + EXPECT_THAT(FNMatch("foo", "fo"), IsFalse()); + EXPECT_THAT(FNMatch("foo", "foo2"), IsFalse()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo.ext"), IsTrue()); + EXPECT_THAT(FNMatch("*ba*r/fo*o.ext*", "bar/foo.ext"), IsTrue()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/baz.ext"), IsFalse()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo"), IsFalse()); + EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo.ext.zip"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*.ext", "bar/foo.ext"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/*.ext", "baZ/FOO.ext"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/*.ext", "barr/foo.ext"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*.ext", "bar/foo.ext2"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*", "bar/foo.ext2"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/*", "bar/"), IsTrue()); + EXPECT_THAT(FNMatch("ba?/?", "bar/"), IsFalse()); + EXPECT_THAT(FNMatch("ba?/*", "bar"), IsFalse()); + EXPECT_THAT(FNMatch("?x", "zx"), IsTrue()); + EXPECT_THAT(FNMatch("*b", "aab"), IsTrue()); + EXPECT_THAT(FNMatch("a*b", "aXb"), IsTrue()); + EXPECT_THAT(FNMatch("", ""), IsTrue()); + EXPECT_THAT(FNMatch("", "a"), IsFalse()); + EXPECT_THAT(FNMatch("ab*", "ab"), IsTrue()); + EXPECT_THAT(FNMatch("ab**", "ab"), IsTrue()); + EXPECT_THAT(FNMatch("ab*?", "ab"), IsFalse()); + EXPECT_THAT(FNMatch("*", "bbb"), IsTrue()); + EXPECT_THAT(FNMatch("*", ""), IsTrue()); + EXPECT_THAT(FNMatch("?", ""), IsFalse()); + EXPECT_THAT(FNMatch("***", "**p"), IsTrue()); + EXPECT_THAT(FNMatch("**", "*"), IsTrue()); + EXPECT_THAT(FNMatch("*?", "*"), IsTrue()); +} + +} // namespace |