[cmake-developers] [PATCH] Added FILTER subcommand to list command
Ashley Whetter
ashley at awhetter.co.uk
Sat Jan 16 12:10:07 EST 2016
In response to issue 0003986, I've implemented a FILTER subcommand to the "list"
command that filters a list using a regular expression.
This doesn't implement an optional "OUTPUT_VARIABLE" parameter.
There was a discussion on the issue as to whether or not the user using a macro
would be a better option. Therefore I've submitted a sample macro for the
reporter on the issue as well if this patch isn't accepted.
---
Help/command/list.rst | 12 +++--
Source/cmListCommand.cxx | 54 ++++++++++++++++++++++
Source/cmListCommand.h | 1 +
Tests/RunCMake/list/EmptyFilter-result.txt | 1 +
Tests/RunCMake/list/EmptyFilter-stderr.txt | 0
Tests/RunCMake/list/EmptyFilter.cmake | 2 +
Tests/RunCMake/list/FILTER-InvalidRegex-result.txt | 1 +
Tests/RunCMake/list/FILTER-InvalidRegex-stderr.txt | 4 ++
Tests/RunCMake/list/FILTER-InvalidRegex.cmake | 2 +
Tests/RunCMake/list/FILTER-NotList-result.txt | 1 +
Tests/RunCMake/list/FILTER-NotList-stderr.txt | 4 ++
Tests/RunCMake/list/FILTER-NotList.cmake | 2 +
.../list/FILTER-TooManyArguments-result.txt | 1 +
.../list/FILTER-TooManyArguments-stderr.txt | 4 ++
Tests/RunCMake/list/FILTER-TooManyArguments.cmake | 1 +
Tests/RunCMake/list/FILTER-Valid0-result.txt | 1 +
Tests/RunCMake/list/FILTER-Valid0-stderr.txt | 2 +
Tests/RunCMake/list/FILTER-Valid0.cmake | 4 ++
Tests/RunCMake/list/RunCMakeTest.cmake | 6 +++
19 files changed, 100 insertions(+), 3 deletions(-)
create mode 100644 Tests/RunCMake/list/EmptyFilter-result.txt
create mode 100644 Tests/RunCMake/list/EmptyFilter-stderr.txt
create mode 100644 Tests/RunCMake/list/EmptyFilter.cmake
create mode 100644 Tests/RunCMake/list/FILTER-InvalidRegex-result.txt
create mode 100644 Tests/RunCMake/list/FILTER-InvalidRegex-stderr.txt
create mode 100644 Tests/RunCMake/list/FILTER-InvalidRegex.cmake
create mode 100644 Tests/RunCMake/list/FILTER-NotList-result.txt
create mode 100644 Tests/RunCMake/list/FILTER-NotList-stderr.txt
create mode 100644 Tests/RunCMake/list/FILTER-NotList.cmake
create mode 100644 Tests/RunCMake/list/FILTER-TooManyArguments-result.txt
create mode 100644 Tests/RunCMake/list/FILTER-TooManyArguments-stderr.txt
create mode 100644 Tests/RunCMake/list/FILTER-TooManyArguments.cmake
create mode 100644 Tests/RunCMake/list/FILTER-Valid0-result.txt
create mode 100644 Tests/RunCMake/list/FILTER-Valid0-stderr.txt
create mode 100644 Tests/RunCMake/list/FILTER-Valid0.cmake
diff --git a/Help/command/list.rst b/Help/command/list.rst
index a7a05c7..797cc14 100644
--- a/Help/command/list.rst
+++ b/Help/command/list.rst
@@ -9,6 +9,7 @@ List operations.
list(GET <list> <element index> [<element index> ...]
<output variable>)
list(APPEND <list> [<element> ...])
+ list(FILTER <list> <regular_expression>)
list(FIND <list> <value> <output variable>)
list(INSERT <list> <element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value> [<value> ...])
@@ -23,6 +24,11 @@ List operations.
``APPEND`` will append elements to the list.
+``FILTER`` will remove the items from the list that match the given regular
+expression.
+For more information on regular expressions see also the :command:`string`
+command.
+
``FIND`` will return the index of the element specified in the list or -1
if it wasn't found.
@@ -38,9 +44,9 @@ difference is that ``REMOVE_ITEM`` will remove the given items, while
``SORT`` sorts the list in-place alphabetically.
-The list subcommands ``APPEND``, ``INSERT``, ``REMOVE_AT``, ``REMOVE_ITEM``,
-``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create new values for
-the list within the current CMake variable scope. Similar to the
+The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``REMOVE_AT``,
+``REMOVE_ITEM``, ``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create new
+values for the list within the current CMake variable scope. Similar to the
:command:`set` command, the LIST command creates new variable values in the
current scope, even if the list itself is actually defined in a parent
scope. To propagate the results of these operations upwards, use
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index 6041fb7..bafd647 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -14,6 +14,7 @@
#include <cmsys/SystemTools.hxx>
#include "cmAlgorithms.h"
+#include <algorithm>
#include <stdlib.h> // required for atoi
#include <ctype.h>
#include <assert.h>
@@ -68,6 +69,10 @@ bool cmListCommand
{
return this->HandleReverseCommand(args);
}
+ if(subCommand == "FILTER")
+ {
+ return this->HandleFilterCommand(args);
+ }
std::string e = "does not recognize sub-command "+subCommand;
this->SetError(e);
@@ -517,3 +522,52 @@ bool cmListCommand::HandleRemoveAtCommand(
return true;
}
+//----------------------------------------------------------------------------
+class MatchesRegex {
+public:
+ MatchesRegex(cmsys::RegularExpression& in_regex) : regex(in_regex) {}
+
+ bool operator()(const std::string& target) {
+ return regex.find(target);
+ }
+
+private:
+ cmsys::RegularExpression& regex;
+};
+
+bool cmListCommand::HandleFilterCommand(
+ std::vector<std::string> const& args)
+{
+ if(args.size() != 3)
+ {
+ this->SetError("sub-command FILTER requires two arguments.");
+ return false;
+ }
+
+ const std::string& listName = args[1];
+ // expand the variable
+ std::vector<std::string> varArgsExpanded;
+ if ( !this->GetList(varArgsExpanded, listName) )
+ {
+ this->SetError("sub-command FILTER requires list to be present.");
+ return false;
+ }
+
+ const std::string& pattern = args[2];
+ cmsys::RegularExpression regex(pattern);
+ if(!regex.is_valid())
+ {
+ this->SetError(
+ "sub-command FILTER failed to compile regex \"" + pattern + "\".");
+ return false;
+ }
+
+ std::vector<std::string>::iterator argsBegin = varArgsExpanded.begin();
+ std::vector<std::string>::iterator argsEnd = varArgsExpanded.end();
+ std::vector<std::string>::iterator newArgsEnd =
+ std::remove_if(argsBegin, argsEnd, MatchesRegex(regex));
+
+ std::string value = cmJoin(cmMakeRange(argsBegin, newArgsEnd), ";");
+ this->Makefile->AddDefinition(listName, value.c_str());
+ return true;
+}
diff --git a/Source/cmListCommand.h b/Source/cmListCommand.h
index 5ea1d9f..e66b480 100644
--- a/Source/cmListCommand.h
+++ b/Source/cmListCommand.h
@@ -58,6 +58,7 @@ protected:
bool HandleRemoveDuplicatesCommand(std::vector<std::string> const& args);
bool HandleSortCommand(std::vector<std::string> const& args);
bool HandleReverseCommand(std::vector<std::string> const& args);
+ bool HandleFilterCommand(std::vector<std::string> const& args);
bool GetList(std::vector<std::string>& list, const std::string& var);
diff --git a/Tests/RunCMake/list/EmptyFilter-result.txt b/Tests/RunCMake/list/EmptyFilter-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/list/EmptyFilter-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/list/EmptyFilter-stderr.txt b/Tests/RunCMake/list/EmptyFilter-stderr.txt
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/list/EmptyFilter.cmake b/Tests/RunCMake/list/EmptyFilter.cmake
new file mode 100644
index 0000000..4048414
--- /dev/null
+++ b/Tests/RunCMake/list/EmptyFilter.cmake
@@ -0,0 +1,2 @@
+set(mylist "")
+list(FILTER mylist "^FILTER_THIS_.+")
diff --git a/Tests/RunCMake/list/FILTER-InvalidRegex-result.txt b/Tests/RunCMake/list/FILTER-InvalidRegex-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-InvalidRegex-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/FILTER-InvalidRegex-stderr.txt b/Tests/RunCMake/list/FILTER-InvalidRegex-stderr.txt
new file mode 100644
index 0000000..77151aa
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-InvalidRegex-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at FILTER-InvalidRegex.cmake:2 \(list\):
+ list sub-command FILTER failed to compile regex "UHOH!\)\(".
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/FILTER-InvalidRegex.cmake b/Tests/RunCMake/list/FILTER-InvalidRegex.cmake
new file mode 100644
index 0000000..5cee0a6
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-InvalidRegex.cmake
@@ -0,0 +1,2 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+list(FILTER mylist "UHOH!)(")
diff --git a/Tests/RunCMake/list/FILTER-NotList-result.txt b/Tests/RunCMake/list/FILTER-NotList-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-NotList-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/FILTER-NotList-stderr.txt b/Tests/RunCMake/list/FILTER-NotList-stderr.txt
new file mode 100644
index 0000000..159c28d
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-NotList-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at FILTER-NotList.cmake:2 \(list\):
+ list sub-command FILTER requires list to be present.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/FILTER-NotList.cmake b/Tests/RunCMake/list/FILTER-NotList.cmake
new file mode 100644
index 0000000..87ab82e
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-NotList.cmake
@@ -0,0 +1,2 @@
+unset(nosuchlist)
+list(FILTER nosuchlist "^FILTER_THIS_.+")
diff --git a/Tests/RunCMake/list/FILTER-TooManyArguments-result.txt b/Tests/RunCMake/list/FILTER-TooManyArguments-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-TooManyArguments-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/list/FILTER-TooManyArguments-stderr.txt b/Tests/RunCMake/list/FILTER-TooManyArguments-stderr.txt
new file mode 100644
index 0000000..44ab8ab
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-TooManyArguments-stderr.txt
@@ -0,0 +1,4 @@
+^CMake Error at FILTER-TooManyArguments.cmake:1 \(list\):
+ list sub-command FILTER requires two arguments.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)$
diff --git a/Tests/RunCMake/list/FILTER-TooManyArguments.cmake b/Tests/RunCMake/list/FILTER-TooManyArguments.cmake
new file mode 100644
index 0000000..65df1da
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-TooManyArguments.cmake
@@ -0,0 +1 @@
+list(FILTER mylist "^FILTER_THIS_.+" one_too_many)
diff --git a/Tests/RunCMake/list/FILTER-Valid0-result.txt b/Tests/RunCMake/list/FILTER-Valid0-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-Valid0-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/list/FILTER-Valid0-stderr.txt b/Tests/RunCMake/list/FILTER-Valid0-stderr.txt
new file mode 100644
index 0000000..d9ba38d
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-Valid0-stderr.txt
@@ -0,0 +1,2 @@
+^mylist was: FILTER_THIS_BIT;DO_NOT_FILTER_THIS;thisisanitem;FILTER_THIS_THING
+mylist is: DO_NOT_FILTER_THIS;thisisanitem$
diff --git a/Tests/RunCMake/list/FILTER-Valid0.cmake b/Tests/RunCMake/list/FILTER-Valid0.cmake
new file mode 100644
index 0000000..41f0e9e
--- /dev/null
+++ b/Tests/RunCMake/list/FILTER-Valid0.cmake
@@ -0,0 +1,4 @@
+set(mylist FILTER_THIS_BIT DO_NOT_FILTER_THIS thisisanitem FILTER_THIS_THING)
+message("mylist was: ${mylist}")
+list(FILTER mylist "^FILTER_THIS_.+")
+message("mylist is: ${mylist}")
diff --git a/Tests/RunCMake/list/RunCMakeTest.cmake b/Tests/RunCMake/list/RunCMakeTest.cmake
index 25d6a03..c7d5311 100644
--- a/Tests/RunCMake/list/RunCMakeTest.cmake
+++ b/Tests/RunCMake/list/RunCMakeTest.cmake
@@ -1,5 +1,6 @@
include(RunCMake)
+run_cmake(EmptyFilter)
run_cmake(EmptyGet0)
run_cmake(EmptyRemoveAt0)
run_cmake(EmptyInsert-1)
@@ -8,17 +9,22 @@ run_cmake(NoArguments)
run_cmake(InvalidSubcommand)
run_cmake(GET-CMP0007-WARN)
+run_cmake(FILTER-InvalidRegex)
run_cmake(GET-InvalidIndex)
run_cmake(INSERT-InvalidIndex)
run_cmake(REMOVE_AT-InvalidIndex)
+run_cmake(FILTER-TooManyArguments)
run_cmake(LENGTH-TooManyArguments)
run_cmake(REMOVE_DUPLICATES-TooManyArguments)
run_cmake(REVERSE-TooManyArguments)
run_cmake(SORT-TooManyArguments)
+run_cmake(FILTER-NotList)
run_cmake(REMOVE_AT-NotList)
run_cmake(REMOVE_DUPLICATES-NotList)
run_cmake(REMOVE_ITEM-NotList)
run_cmake(REVERSE-NotList)
run_cmake(SORT-NotList)
+
+run_cmake(FILTER-Valid0)
--
2.6.4
More information about the cmake-developers
mailing list