summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/cmForEachCommand.cxx48
-rw-r--r--Source/cmForEachCommand.h17
-rw-r--r--Tests/StringFileTest/CMakeLists.txt19
3 files changed, 81 insertions, 3 deletions
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index 7a826c6..7a03523 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -16,6 +16,8 @@
=========================================================================*/
#include "cmForEachCommand.h"
+#include <cmsys/auto_ptr.hxx>
+
bool cmForEachFunctionBlocker::
IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
cmExecutionStatus &inStatus)
@@ -116,6 +118,10 @@ bool cmForEachCommand
this->SetError("called with incorrect number of arguments");
return false;
}
+ if(args.size() > 1 && args[1] == "IN")
+ {
+ return this->HandleInMode(args);
+ }
// create a function blocker
cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
@@ -197,3 +203,45 @@ bool cmForEachCommand
return true;
}
+//----------------------------------------------------------------------------
+bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args)
+{
+ cmsys::auto_ptr<cmForEachFunctionBlocker> f(new cmForEachFunctionBlocker());
+ f->Args.push_back(args[0]);
+
+ enum Doing { DoingNone, DoingLists, DoingItems };
+ Doing doing = DoingNone;
+ for(unsigned int i=2; i < args.size(); ++i)
+ {
+ if(doing == DoingItems)
+ {
+ f->Args.push_back(args[i]);
+ }
+ else if(args[i] == "LISTS")
+ {
+ doing = DoingLists;
+ }
+ else if(args[i] == "ITEMS")
+ {
+ doing = DoingItems;
+ }
+ else if(doing == DoingLists)
+ {
+ const char* value = this->Makefile->GetDefinition(args[i].c_str());
+ if(value && *value)
+ {
+ cmSystemTools::ExpandListArgument(value, f->Args, true);
+ }
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "Unknown argument:\n" << " " << args[i] << "\n";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+ return true;
+ }
+ }
+
+ this->Makefile->AddFunctionBlocker(f.release()); // TODO: pass auto_ptr
+ return true;
+}
diff --git a/Source/cmForEachCommand.h b/Source/cmForEachCommand.h
index 3e03711..ea7faa5 100644
--- a/Source/cmForEachCommand.h
+++ b/Source/cmForEachCommand.h
@@ -94,14 +94,14 @@ public:
" COMMAND2(ARGS ...)\n"
" ...\n"
" endforeach(loop_var)\n"
- " foreach(loop_var RANGE total)\n"
- " foreach(loop_var RANGE start stop [step])\n"
"All commands between foreach and the matching endforeach are recorded "
"without being invoked. Once the endforeach is evaluated, the "
"recorded list of commands is invoked once for each argument listed "
"in the original foreach command. Before each iteration of the loop "
"\"${loop_var}\" will be set as a variable with "
"the current value in the list.\n"
+ " foreach(loop_var RANGE total)\n"
+ " foreach(loop_var RANGE start stop [step])\n"
"Foreach can also iterate over a generated range of numbers. "
"There are three types of this iteration:\n"
"* When specifying single number, the range will have elements "
@@ -109,10 +109,21 @@ public:
"* When specifying two numbers, the range will have elements from "
"the first number to the second number.\n"
"* The third optional number is the increment used to iterate from "
- "the first number to the second number.";
+ "the first number to the second number."
+ "\n"
+ " foreach(loop_var IN [LISTS [list1 [...]]]\n"
+ " [ITEMS [item1 [...]]])\n"
+ "Iterates over a precise list of items. "
+ "The LISTS option names list-valued variables to be traversed, "
+ "including empty elements (an empty string is a zero-length list). "
+ "The ITEMS option ends argument parsing and includes all arguments "
+ "following it in the iteration."
+ ;
}
cmTypeMacro(cmForEachCommand, cmCommand);
+private:
+ bool HandleInMode(std::vector<std::string> const& args);
};
diff --git a/Tests/StringFileTest/CMakeLists.txt b/Tests/StringFileTest/CMakeLists.txt
index f1598d7..f2789e6 100644
--- a/Tests/StringFileTest/CMakeLists.txt
+++ b/Tests/StringFileTest/CMakeLists.txt
@@ -217,3 +217,22 @@ TEST_RANGE("3;5" "3;4;5")
TEST_RANGE("5;3" "5;4;3")
TEST_RANGE("3;10;2" "3;5;7;9")
TEST_RANGE("10;0;-3" "10;7;4;1")
+
+# Test FOREACH IN signature
+set(list1 "" a "")
+set(list2 a "" b)
+set(var_)
+set(var_a)
+set(var_b)
+foreach(item IN LISTS list1 list2 ITEMS "" a "")
+ set(var_${item} "${var_${item}}x")
+endforeach(item)
+if(NOT "${var_}" STREQUAL "xxxxx")
+ message(FATAL_ERROR "count incorrect for \"\": [${var_}]")
+endif()
+if(NOT "${var_a}" STREQUAL "xxx")
+ message(FATAL_ERROR "count incorrect for \"a\": [${var_a}]")
+endif()
+if(NOT "${var_b}" STREQUAL "x")
+ message(FATAL_ERROR "count incorrect \"b\": [${var_b}]")
+endif()