ENH: Add RANGE support to FOREACH

This commit is contained in:
Andy Cedilnik 2004-04-29 15:12:40 -04:00
parent ae50b4bc6a
commit 8750f1c277
3 changed files with 103 additions and 2 deletions

View File

@ -106,7 +106,79 @@ bool cmForEachCommand::InitialPass(std::vector<std::string> const& args)
// create a function blocker // create a function blocker
cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker(); cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
f->m_Args = args; if ( args.size() > 1 )
{
if ( args[1] == "RANGE" )
{
int start = 0;
int stop = 0;
int step = 0;
if ( args.size() == 3 )
{
stop = atoi(args[2].c_str());
}
if ( args.size() == 4 )
{
start = atoi(args[2].c_str());
stop = atoi(args[3].c_str());
}
if ( args.size() == 5 )
{
start = atoi(args[2].c_str());
stop = atoi(args[3].c_str());
step = atoi(args[4].c_str());
}
if ( step == 0 )
{
if ( start > stop )
{
step = -1;
}
else
{
step = 1;
}
}
if (
(start > stop && step > 0) ||
(start < stop && step < 0) ||
step == 0
)
{
cmOStringStream str;
str << "called with incorrect range specification: start ";
str << start << ", stop " << stop << ", step " << step;
this->SetError(str.str().c_str());
return false;
}
std::vector<std::string> range;
char buffer[100];
range.push_back(args[0]);
int cc;
for ( cc = start; ; cc += step )
{
if ( (step > 0 && cc > stop) || (step < 0 && cc < stop) )
{
break;
}
sprintf(buffer, "%d", cc);
range.push_back(buffer);
if ( cc == stop )
{
break;
}
}
f->m_Args = range;
}
else
{
f->m_Args = args;
}
}
else
{
f->m_Args = args;
}
m_Makefile->AddFunctionBlocker(f); m_Makefile->AddFunctionBlocker(f);
return true; return true;

View File

@ -98,12 +98,22 @@ public:
" COMMAND2(ARGS ...)\n" " COMMAND2(ARGS ...)\n"
" ...\n" " ...\n"
" ENDFOREACH(loop_var)\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 " "All commands between FOREACH and the matching ENDFOREACH are recorded "
"without being invoked. Once the ENDFOREACH is evaluated, the " "without being invoked. Once the ENDFOREACH is evaluated, the "
"recorded list of commands is invoked once for each argument listed " "recorded list of commands is invoked once for each argument listed "
"in the original FOREACH command. Each recorded command is modified " "in the original FOREACH command. Each recorded command is modified "
"before invocation to replace any occurrence of \"${loop_var}\" with " "before invocation to replace any occurrence of \"${loop_var}\" with "
"the current value in the list."; "the current value in the list.\n"
"Foreach can also iterate over the range of numbers generated by "
"foreach. There are three types of this iteration:\n"
"* When specifying single number, the range will have elements "
"0 to \"total\".\n"
"* 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.";
} }
cmTypeMacro(cmForEachCommand, cmCommand); cmTypeMacro(cmForEachCommand, cmCommand);

View File

@ -73,3 +73,22 @@ FILE(GLOB src_files "${expr}")
MESSAGE("Globbed files [${src_files}].") MESSAGE("Globbed files [${src_files}].")
ADD_EXECUTABLE(StringFileTest ${src_files}) ADD_EXECUTABLE(StringFileTest ${src_files})
# Test FOREACH range
MESSAGE("Cheack if FOREACH with RANGE works")
MACRO(TEST_RANGE ARGS CHECK)
SET(r)
FOREACH(a RANGE ${ARGS})
SET(r ${r} ${a})
ENDFOREACH(a)
MESSAGE("FOREACH with RANGE ${ARGS} produces ${r}")
IF("x${r}x" MATCHES "^x${CHECK}x$")
ELSE("x${r}x" MATCHES "^x${CHECK}x$")
MESSAGE(SEND_ERROR "The range resulted in: ${r} should be ${CHECK}")
ENDIF("x${r}x" MATCHES "^x${CHECK}x$")
ENDMACRO(TEST_RANGE)
TEST_RANGE("5" "0;1;2;3;4;5")
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")