summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apt-pkg/cachefilter-patterns.cc28
-rw-r--r--apt-pkg/cachefilter-patterns.h2
-rw-r--r--doc/apt-patterns.7.xml2
-rw-r--r--test/libapt/pattern_test.cc1
4 files changed, 31 insertions, 2 deletions
diff --git a/apt-pkg/cachefilter-patterns.cc b/apt-pkg/cachefilter-patterns.cc
index 11ad5d723..9fab0281d 100644
--- a/apt-pkg/cachefilter-patterns.cc
+++ b/apt-pkg/cachefilter-patterns.cc
@@ -67,6 +67,32 @@ std::unique_ptr<PatternTreeParser::Node> PatternTreeParser::parseTop()
// Parse any pattern
std::unique_ptr<PatternTreeParser::Node> PatternTreeParser::parse()
{
+ return parseUnary();
+}
+
+std::unique_ptr<PatternTreeParser::Node> PatternTreeParser::parseUnary()
+{
+
+ if (sentence[state.offset] != '!')
+ return parsePrimary();
+
+ auto start = ++state.offset;
+ auto primary = parsePrimary();
+
+ if (primary == nullptr)
+ throw Error{Node{start, sentence.size()}, "Expected pattern"};
+
+ auto node = std::make_unique<PatternNode>();
+ node->start = start;
+ node->end = primary->end;
+ node->term = "?not";
+ node->arguments.push_back(std::move(primary));
+ node->haveArgumentList = true;
+ return node;
+}
+
+std::unique_ptr<PatternTreeParser::Node> PatternTreeParser::parsePrimary()
+{
std::unique_ptr<Node> node;
if ((node = parseShortPattern()) != nullptr)
return node;
@@ -198,7 +224,7 @@ std::unique_ptr<PatternTreeParser::Node> PatternTreeParser::parseQuotedWord()
// Parse a bare word atom
std::unique_ptr<PatternTreeParser::Node> PatternTreeParser::parseWord()
{
- static const constexpr auto DISALLOWED_START = "?~,()\0"_sv;
+ static const constexpr auto DISALLOWED_START = "!?~,()\0"_sv;
static const constexpr auto DISALLOWED = ",()\0"_sv;
if (DISALLOWED_START.find(sentence[state.offset]) != APT::StringView::npos)
return nullptr;
diff --git a/apt-pkg/cachefilter-patterns.h b/apt-pkg/cachefilter-patterns.h
index 0d6e9d99e..76318eafa 100644
--- a/apt-pkg/cachefilter-patterns.h
+++ b/apt-pkg/cachefilter-patterns.h
@@ -95,6 +95,8 @@ struct PatternTreeParser
private:
std::unique_ptr<Node> parse();
+ std::unique_ptr<Node> parseUnary();
+ std::unique_ptr<Node> parsePrimary();
std::unique_ptr<Node> parsePattern();
std::unique_ptr<Node> parseShortPattern();
std::unique_ptr<Node> parseWord();
diff --git a/doc/apt-patterns.7.xml b/doc/apt-patterns.7.xml
index f18fe6a19..72f1ccbce 100644
--- a/doc/apt-patterns.7.xml
+++ b/doc/apt-patterns.7.xml
@@ -49,7 +49,7 @@
<varlistentry><term><code>?false</code></term><term><code>~F</code></term>
<listitem><para>Selects nothing.</para></listitem>
</varlistentry>
- <varlistentry><term><code>?not(PATTERN)</code></term>
+ <varlistentry><term><code>?not(PATTERN)</code></term><term><code>!PATTERN</code></term>
<listitem><para>Selects objects where PATTERN does not match.</para></listitem>
</varlistentry>
<varlistentry><term><code>?or(PATTERN, PATTERN, ...)</code></term>
diff --git a/test/libapt/pattern_test.cc b/test/libapt/pattern_test.cc
index 492a29eac..39959cd31 100644
--- a/test/libapt/pattern_test.cc
+++ b/test/libapt/pattern_test.cc
@@ -158,4 +158,5 @@ TEST(TreeParserTest, ParseShortPattern)
EXPECT_PATTERN_EQ_ATOMIC("~U", "?upgradable");
EXPECT_PATTERN_EQ("~Vverstr", "?version(verstr)");
EXPECT_PATTERN_EQ_ATOMIC("~v", "?virtual");
+ EXPECT_PATTERN_EQ("!foo", "?not(foo)");
}