ENH: support parenthesis as arguments and in conditionals feature request #6191
This commit is contained in:
parent
d8e05b43a1
commit
19e891532a
|
@ -21,8 +21,10 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <cmsys/RegularExpression.hxx>
|
#include <cmsys/RegularExpression.hxx>
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
bool cmIfFunctionBlocker::
|
bool cmIfFunctionBlocker::
|
||||||
IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
IsFunctionBlocked(const cmListFileFunction& lff,
|
||||||
|
cmMakefile &mf,
|
||||||
cmExecutionStatus &inStatus)
|
cmExecutionStatus &inStatus)
|
||||||
{
|
{
|
||||||
// Prevent recusion and don't let this blocker block its own
|
// Prevent recusion and don't let this blocker block its own
|
||||||
|
@ -140,6 +142,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
|
bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
|
||||||
cmMakefile&)
|
cmMakefile&)
|
||||||
{
|
{
|
||||||
|
@ -157,8 +160,8 @@ bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmIfFunctionBlocker::
|
//=========================================================================
|
||||||
ScopeEnded(cmMakefile &mf)
|
void cmIfFunctionBlocker::ScopeEnded(cmMakefile &mf)
|
||||||
{
|
{
|
||||||
std::string errmsg = "The end of a CMakeLists file was reached with an "
|
std::string errmsg = "The end of a CMakeLists file was reached with an "
|
||||||
"IF statement that was not closed properly.\nWithin the directory: ";
|
"IF statement that was not closed properly.\nWithin the directory: ";
|
||||||
|
@ -175,6 +178,7 @@ ScopeEnded(cmMakefile &mf)
|
||||||
cmSystemTools::Message(errmsg.c_str(), "Warning");
|
cmSystemTools::Message(errmsg.c_str(), "Warning");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
bool cmIfCommand
|
bool cmIfCommand
|
||||||
::InvokeInitialPass(const std::vector<cmListFileArgument>& args,
|
::InvokeInitialPass(const std::vector<cmListFileArgument>& args,
|
||||||
cmExecutionStatus &)
|
cmExecutionStatus &)
|
||||||
|
@ -221,6 +225,7 @@ bool cmIfCommand
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
//=========================================================================
|
||||||
void IncrementArguments(std::list<std::string> &newArgs,
|
void IncrementArguments(std::list<std::string> &newArgs,
|
||||||
std::list<std::string>::iterator &argP1,
|
std::list<std::string>::iterator &argP1,
|
||||||
std::list<std::string>::iterator &argP2)
|
std::list<std::string>::iterator &argP2)
|
||||||
|
@ -235,60 +240,140 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
// order of operations,
|
// helper function to reduce code duplication
|
||||||
// IS_DIRECTORY EXISTS COMMAND DEFINED
|
void HandlePredicate(bool value, int &reducible,
|
||||||
// MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL
|
std::list<std::string>::iterator &arg,
|
||||||
// AND OR
|
std::list<std::string> &newArgs,
|
||||||
//
|
std::list<std::string>::iterator &argP1,
|
||||||
// There is an issue on whether the arguments should be values of references,
|
std::list<std::string>::iterator &argP2)
|
||||||
// for example IF (FOO AND BAR) should that compare the strings FOO and BAR
|
|
||||||
// or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
|
|
||||||
// EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
|
|
||||||
// take numeric values or variable names. STRLESS and STRGREATER take
|
|
||||||
// variable names but if the variable name is not found it will use the name
|
|
||||||
// directly. AND OR take variables or the values 0 or 1.
|
|
||||||
|
|
||||||
|
|
||||||
bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
|
||||||
char **errorString, cmMakefile *makefile)
|
|
||||||
{
|
|
||||||
// check for the different signatures
|
|
||||||
const char *def;
|
|
||||||
const char *def2;
|
|
||||||
const char* msg = "Unknown arguments specified";
|
|
||||||
*errorString = new char[strlen(msg) + 1];
|
|
||||||
strcpy(*errorString, msg);
|
|
||||||
|
|
||||||
// handle empty invocation
|
|
||||||
if (args.size() < 1)
|
|
||||||
{
|
{
|
||||||
delete [] *errorString;
|
if(value)
|
||||||
*errorString = 0;
|
{
|
||||||
return false;
|
*arg = "1";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*arg = "0";
|
||||||
|
}
|
||||||
|
newArgs.erase(argP1);
|
||||||
|
argP1 = arg;
|
||||||
|
IncrementArguments(newArgs,argP1,argP2);
|
||||||
|
reducible = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the reduced args in this vector
|
//=========================================================================
|
||||||
std::list<std::string> newArgs;
|
// helper function to reduce code duplication
|
||||||
|
void HandleBinaryOp(bool value, int &reducible,
|
||||||
|
std::list<std::string>::iterator &arg,
|
||||||
|
std::list<std::string> &newArgs,
|
||||||
|
std::list<std::string>::iterator &argP1,
|
||||||
|
std::list<std::string>::iterator &argP2)
|
||||||
|
{
|
||||||
|
if(value)
|
||||||
|
{
|
||||||
|
*arg = "1";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*arg = "0";
|
||||||
|
}
|
||||||
|
newArgs.erase(argP2);
|
||||||
|
newArgs.erase(argP1);
|
||||||
|
argP1 = arg;
|
||||||
|
IncrementArguments(newArgs,argP1,argP2);
|
||||||
|
reducible = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// level 0 processes parenthetical expressions
|
||||||
|
bool HandleLevel0(std::list<std::string> &newArgs,
|
||||||
|
cmMakefile *makefile,
|
||||||
|
char **errorString)
|
||||||
|
{
|
||||||
int reducible;
|
int reducible;
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
// copy to the list structure
|
|
||||||
for(i = 0; i < args.size(); ++i)
|
|
||||||
{
|
|
||||||
newArgs.push_back(args[i]);
|
|
||||||
}
|
|
||||||
std::list<std::string>::iterator argP1;
|
|
||||||
std::list<std::string>::iterator argP2;
|
|
||||||
|
|
||||||
// now loop through the arguments and see if we can reduce any of them
|
|
||||||
// we do this multiple times. Once for each level of precedence
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
reducible = 0;
|
reducible = 0;
|
||||||
std::list<std::string>::iterator arg = newArgs.begin();
|
std::list<std::string>::iterator arg = newArgs.begin();
|
||||||
|
while (arg != newArgs.end())
|
||||||
|
{
|
||||||
|
if (*arg == "(")
|
||||||
|
{
|
||||||
|
// search for the closing paren for this opening one
|
||||||
|
std::list<std::string>::iterator argClose;
|
||||||
|
argClose = arg;
|
||||||
|
argClose++;
|
||||||
|
unsigned int depth = 1;
|
||||||
|
while (argClose != newArgs.end() && depth)
|
||||||
|
{
|
||||||
|
if (*argClose == "(")
|
||||||
|
{
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
if (*argClose == ")")
|
||||||
|
{
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
argClose++;
|
||||||
|
}
|
||||||
|
if (depth)
|
||||||
|
{
|
||||||
|
cmOStringStream error;
|
||||||
|
error << "mismatched parenthesis in condition";
|
||||||
|
delete [] *errorString;
|
||||||
|
*errorString = new char[error.str().size() + 1];
|
||||||
|
strcpy(*errorString, error.str().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// store the reduced args in this vector
|
||||||
|
std::vector<std::string> newArgs2;
|
||||||
|
|
||||||
|
// copy to the list structure
|
||||||
|
std::list<std::string>::iterator argP1 = arg;
|
||||||
|
argP1++;
|
||||||
|
for(; argP1 != argClose; argP1++)
|
||||||
|
{
|
||||||
|
newArgs2.push_back(*argP1);
|
||||||
|
}
|
||||||
|
newArgs2.pop_back();
|
||||||
|
// now recursively invoke IsTrue to handle the values inside the parenthetical expression
|
||||||
|
bool value =
|
||||||
|
cmIfCommand::IsTrue(newArgs2, errorString, makefile);
|
||||||
|
if(value)
|
||||||
|
{
|
||||||
|
*arg = "1";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*arg = "0";
|
||||||
|
}
|
||||||
|
argP1 = arg;
|
||||||
|
argP1++;
|
||||||
|
// remove the now evaluated parenthetical expression
|
||||||
|
newArgs.erase(argP1,argClose);
|
||||||
|
}
|
||||||
|
++arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (reducible);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// level one handles most predicates except for NOT
|
||||||
|
bool HandleLevel1(std::list<std::string> &newArgs,
|
||||||
|
cmMakefile *makefile,
|
||||||
|
char **)
|
||||||
|
{
|
||||||
|
int reducible;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
reducible = 0;
|
||||||
|
std::list<std::string>::iterator arg = newArgs.begin();
|
||||||
|
std::list<std::string>::iterator argP1;
|
||||||
|
std::list<std::string>::iterator argP2;
|
||||||
while (arg != newArgs.end())
|
while (arg != newArgs.end())
|
||||||
{
|
{
|
||||||
argP1 = arg;
|
argP1 = arg;
|
||||||
|
@ -296,83 +381,38 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
// does a file exist
|
// does a file exist
|
||||||
if (*arg == "EXISTS" && argP1 != newArgs.end())
|
if (*arg == "EXISTS" && argP1 != newArgs.end())
|
||||||
{
|
{
|
||||||
if(cmSystemTools::FileExists((argP1)->c_str()))
|
HandlePredicate(
|
||||||
{
|
cmSystemTools::FileExists((argP1)->c_str()),
|
||||||
*arg = "1";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
// does a directory with this name exist
|
// does a directory with this name exist
|
||||||
if (*arg == "IS_DIRECTORY" && argP1 != newArgs.end())
|
if (*arg == "IS_DIRECTORY" && argP1 != newArgs.end())
|
||||||
{
|
{
|
||||||
if(cmSystemTools::FileIsDirectory((argP1)->c_str()))
|
HandlePredicate(
|
||||||
{
|
cmSystemTools::FileIsDirectory((argP1)->c_str()),
|
||||||
*arg = "1";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
// is the given path an absolute path ?
|
// is the given path an absolute path ?
|
||||||
if (*arg == "IS_ABSOLUTE" && argP1 != newArgs.end())
|
if (*arg == "IS_ABSOLUTE" && argP1 != newArgs.end())
|
||||||
{
|
{
|
||||||
if(cmSystemTools::FileIsFullPath((argP1)->c_str()))
|
HandlePredicate(
|
||||||
{
|
cmSystemTools::FileIsFullPath((argP1)->c_str()),
|
||||||
*arg = "1";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
// does a command exist
|
// does a command exist
|
||||||
if (*arg == "COMMAND" && argP1 != newArgs.end())
|
if (*arg == "COMMAND" && argP1 != newArgs.end())
|
||||||
{
|
{
|
||||||
if(makefile->CommandExists((argP1)->c_str()))
|
HandlePredicate(
|
||||||
{
|
makefile->CommandExists((argP1)->c_str()),
|
||||||
*arg = "1";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
// does a policy exist
|
// does a policy exist
|
||||||
if (*arg == "POLICY" && argP1 != newArgs.end())
|
if (*arg == "POLICY" && argP1 != newArgs.end())
|
||||||
{
|
{
|
||||||
cmPolicies::PolicyID pid;
|
cmPolicies::PolicyID pid;
|
||||||
if(makefile->GetPolicies()->GetPolicyID((argP1)->c_str(), pid))
|
HandlePredicate(
|
||||||
{
|
makefile->GetPolicies()->GetPolicyID((argP1)->c_str(), pid),
|
||||||
*arg = "1";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
// is a variable defined
|
// is a variable defined
|
||||||
if (*arg == "DEFINED" && argP1 != newArgs.end())
|
if (*arg == "DEFINED" && argP1 != newArgs.end())
|
||||||
|
@ -389,32 +429,30 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
{
|
{
|
||||||
bdef = makefile->IsDefinitionSet((argP1)->c_str());
|
bdef = makefile->IsDefinitionSet((argP1)->c_str());
|
||||||
}
|
}
|
||||||
if(bdef)
|
HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
|
||||||
{
|
|
||||||
*arg = "1";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
++arg;
|
++arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (reducible);
|
while (reducible);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
// now loop through the arguments and see if we can reduce any of them
|
// level two handles most binary operations except for AND OR
|
||||||
// we do this multiple times. Once for each level of precedence
|
bool HandleLevel2(std::list<std::string> &newArgs,
|
||||||
|
cmMakefile *makefile,
|
||||||
|
char **errorString)
|
||||||
|
{
|
||||||
|
int reducible;
|
||||||
|
const char *def;
|
||||||
|
const char *def2;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
reducible = 0;
|
reducible = 0;
|
||||||
std::list<std::string>::iterator arg = newArgs.begin();
|
std::list<std::string>::iterator arg = newArgs.begin();
|
||||||
|
std::list<std::string>::iterator argP1;
|
||||||
|
std::list<std::string>::iterator argP2;
|
||||||
while (arg != newArgs.end())
|
while (arg != newArgs.end())
|
||||||
{
|
{
|
||||||
argP1 = arg;
|
argP1 = arg;
|
||||||
|
@ -468,49 +506,26 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
|
def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
|
||||||
double lhs;
|
double lhs;
|
||||||
double rhs;
|
double rhs;
|
||||||
|
bool result;
|
||||||
if(sscanf(def, "%lg", &lhs) != 1 ||
|
if(sscanf(def, "%lg", &lhs) != 1 ||
|
||||||
sscanf(def2, "%lg", &rhs) != 1)
|
sscanf(def2, "%lg", &rhs) != 1)
|
||||||
{
|
{
|
||||||
*arg = "0";
|
result = false;
|
||||||
}
|
}
|
||||||
else if (*(argP1) == "LESS")
|
else if (*(argP1) == "LESS")
|
||||||
{
|
{
|
||||||
if(lhs < rhs)
|
result = (lhs < rhs);
|
||||||
{
|
|
||||||
*arg = "1";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (*(argP1) == "GREATER")
|
else if (*(argP1) == "GREATER")
|
||||||
{
|
{
|
||||||
if(lhs > rhs)
|
result = (lhs > rhs);
|
||||||
{
|
|
||||||
*arg = "1";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*arg = "0";
|
result = (lhs == rhs);
|
||||||
}
|
}
|
||||||
}
|
HandleBinaryOp(result,
|
||||||
else
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
{
|
|
||||||
if(lhs == rhs)
|
|
||||||
{
|
|
||||||
*arg = "1";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newArgs.erase(argP2);
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
|
if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
|
||||||
|
@ -521,7 +536,7 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
|
def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
|
||||||
def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
|
def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
|
||||||
int val = strcmp(def,def2);
|
int val = strcmp(def,def2);
|
||||||
int result;
|
bool result;
|
||||||
if (*(argP1) == "STRLESS")
|
if (*(argP1) == "STRLESS")
|
||||||
{
|
{
|
||||||
result = (val < 0);
|
result = (val < 0);
|
||||||
|
@ -534,19 +549,8 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
{
|
{
|
||||||
result = (val == 0);
|
result = (val == 0);
|
||||||
}
|
}
|
||||||
if(result)
|
HandleBinaryOp(result,
|
||||||
{
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
*arg = "1";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP2);
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// is file A newer than file B
|
// is file A newer than file B
|
||||||
|
@ -557,33 +561,32 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
bool success=cmSystemTools::FileTimeCompare(arg->c_str(),
|
bool success=cmSystemTools::FileTimeCompare(arg->c_str(),
|
||||||
(argP2)->c_str(),
|
(argP2)->c_str(),
|
||||||
&fileIsNewer);
|
&fileIsNewer);
|
||||||
if(success==false || fileIsNewer==1 || fileIsNewer==0)
|
HandleBinaryOp(
|
||||||
{
|
(success==false || fileIsNewer==1 || fileIsNewer==0),
|
||||||
*arg = "1";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP2);
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++arg;
|
++arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (reducible);
|
while (reducible);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
// now loop through the arguments and see if we can reduce any of them
|
// level 3 handles NOT
|
||||||
// we do this multiple times. Once for each level of precedence
|
bool HandleLevel3(std::list<std::string> &newArgs,
|
||||||
|
cmMakefile *makefile,
|
||||||
|
char **)
|
||||||
|
{
|
||||||
|
int reducible;
|
||||||
|
const char *def;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
reducible = 0;
|
reducible = 0;
|
||||||
std::list<std::string>::iterator arg = newArgs.begin();
|
std::list<std::string>::iterator arg = newArgs.begin();
|
||||||
|
std::list<std::string>::iterator argP1;
|
||||||
|
std::list<std::string>::iterator argP2;
|
||||||
while (arg != newArgs.end())
|
while (arg != newArgs.end())
|
||||||
{
|
{
|
||||||
argP1 = arg;
|
argP1 = arg;
|
||||||
|
@ -591,30 +594,31 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
if (argP1 != newArgs.end() && *arg == "NOT")
|
if (argP1 != newArgs.end() && *arg == "NOT")
|
||||||
{
|
{
|
||||||
def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
|
def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
|
||||||
if(!cmSystemTools::IsOff(def))
|
HandlePredicate(cmSystemTools::IsOff(def),
|
||||||
{
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
*arg = "0";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "1";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
++arg;
|
++arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (reducible);
|
while (reducible);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// now loop through the arguments and see if we can reduce any of them
|
//=========================================================================
|
||||||
// we do this multiple times. Once for each level of precedence
|
// level 4 handles AND OR
|
||||||
|
bool HandleLevel4(std::list<std::string> &newArgs,
|
||||||
|
cmMakefile *makefile,
|
||||||
|
char **)
|
||||||
|
{
|
||||||
|
int reducible;
|
||||||
|
const char *def;
|
||||||
|
const char *def2;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
reducible = 0;
|
reducible = 0;
|
||||||
std::list<std::string>::iterator arg = newArgs.begin();
|
std::list<std::string>::iterator arg = newArgs.begin();
|
||||||
|
std::list<std::string>::iterator argP1;
|
||||||
|
std::list<std::string>::iterator argP2;
|
||||||
while (arg != newArgs.end())
|
while (arg != newArgs.end())
|
||||||
{
|
{
|
||||||
argP1 = arg;
|
argP1 = arg;
|
||||||
|
@ -624,19 +628,9 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
{
|
{
|
||||||
def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
|
def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
|
||||||
def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
|
def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
|
||||||
if(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2))
|
HandleBinaryOp(
|
||||||
{
|
!(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2)),
|
||||||
*arg = "0";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "1";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP2);
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argP1 != newArgs.end() && *(argP1) == "OR" &&
|
if (argP1 != newArgs.end() && *(argP1) == "OR" &&
|
||||||
|
@ -644,25 +638,84 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
{
|
{
|
||||||
def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
|
def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
|
||||||
def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
|
def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
|
||||||
if(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2))
|
HandleBinaryOp(
|
||||||
{
|
!(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2)),
|
||||||
*arg = "0";
|
reducible, arg, newArgs, argP1, argP2);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
*arg = "1";
|
|
||||||
}
|
|
||||||
newArgs.erase(argP2);
|
|
||||||
newArgs.erase(argP1);
|
|
||||||
argP1 = arg;
|
|
||||||
IncrementArguments(newArgs,argP1,argP2);
|
|
||||||
reducible = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
++arg;
|
++arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (reducible);
|
while (reducible);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// order of operations,
|
||||||
|
// 1. ( ) -- parenthetical groups
|
||||||
|
// 2. IS_DIRECTORY EXISTS COMMAND DEFINED etc predicates
|
||||||
|
// 3. MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL etc binary ops
|
||||||
|
// 4. NOT
|
||||||
|
// 5. AND OR
|
||||||
|
//
|
||||||
|
// There is an issue on whether the arguments should be values of references,
|
||||||
|
// for example IF (FOO AND BAR) should that compare the strings FOO and BAR
|
||||||
|
// or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
|
||||||
|
// EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
|
||||||
|
// take numeric values or variable names. STRLESS and STRGREATER take
|
||||||
|
// variable names but if the variable name is not found it will use the name
|
||||||
|
// directly. AND OR take variables or the values 0 or 1.
|
||||||
|
|
||||||
|
|
||||||
|
bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
|
char **errorString, cmMakefile *makefile)
|
||||||
|
{
|
||||||
|
// check for the different signatures
|
||||||
|
const char *def;
|
||||||
|
const char* msg = "Unknown arguments specified";
|
||||||
|
*errorString = new char[strlen(msg) + 1];
|
||||||
|
strcpy(*errorString, msg);
|
||||||
|
|
||||||
|
// handle empty invocation
|
||||||
|
if (args.size() < 1)
|
||||||
|
{
|
||||||
|
delete [] *errorString;
|
||||||
|
*errorString = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// store the reduced args in this vector
|
||||||
|
std::list<std::string> newArgs;
|
||||||
|
|
||||||
|
// copy to the list structure
|
||||||
|
for(unsigned int i = 0; i < args.size(); ++i)
|
||||||
|
{
|
||||||
|
newArgs.push_back(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now loop through the arguments and see if we can reduce any of them
|
||||||
|
// we do this multiple times. Once for each level of precedence
|
||||||
|
if (!HandleLevel0(newArgs, makefile, errorString)) // parens
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!HandleLevel1(newArgs, makefile, errorString)) //predicates
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!HandleLevel2(newArgs, makefile, errorString)) // binary ops
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!HandleLevel3(newArgs, makefile, errorString)) // NOT
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!HandleLevel4(newArgs, makefile, errorString)) // AND OR
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// now at the end there should only be one argument left
|
// now at the end there should only be one argument left
|
||||||
if (newArgs.size() == 1)
|
if (newArgs.size() == 1)
|
||||||
|
@ -687,6 +740,7 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
const char* cmIfCommand::GetVariableOrString(const char* str,
|
const char* cmIfCommand::GetVariableOrString(const char* str,
|
||||||
const cmMakefile* mf)
|
const cmMakefile* mf)
|
||||||
{
|
{
|
||||||
|
@ -698,6 +752,7 @@ const char* cmIfCommand::GetVariableOrString(const char* str,
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
const char* cmIfCommand::GetVariableOrNumber(const char* str,
|
const char* cmIfCommand::GetVariableOrNumber(const char* str,
|
||||||
const cmMakefile* mf)
|
const cmMakefile* mf)
|
||||||
{
|
{
|
||||||
|
|
|
@ -242,12 +242,27 @@ bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
|
||||||
|
|
||||||
// Arguments.
|
// Arguments.
|
||||||
unsigned long lastLine = cmListFileLexer_GetCurrentLine(lexer);
|
unsigned long lastLine = cmListFileLexer_GetCurrentLine(lexer);
|
||||||
|
unsigned long parenDepth = 0;
|
||||||
while((token = cmListFileLexer_Scan(lexer)))
|
while((token = cmListFileLexer_Scan(lexer)))
|
||||||
{
|
{
|
||||||
if(token->type == cmListFileLexer_Token_ParenRight)
|
if(token->type == cmListFileLexer_Token_ParenLeft)
|
||||||
|
{
|
||||||
|
parenDepth++;
|
||||||
|
cmListFileArgument a("(",
|
||||||
|
false, filename, token->line);
|
||||||
|
function.Arguments.push_back(a);
|
||||||
|
}
|
||||||
|
else if(token->type == cmListFileLexer_Token_ParenRight)
|
||||||
|
{
|
||||||
|
if (parenDepth == 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
parenDepth--;
|
||||||
|
cmListFileArgument a(")",
|
||||||
|
false, filename, token->line);
|
||||||
|
function.Arguments.push_back(a);
|
||||||
|
}
|
||||||
else if(token->type == cmListFileLexer_Token_Identifier ||
|
else if(token->type == cmListFileLexer_Token_Identifier ||
|
||||||
token->type == cmListFileLexer_Token_ArgumentUnquoted)
|
token->type == cmListFileLexer_Token_ArgumentUnquoted)
|
||||||
{
|
{
|
||||||
|
|
|
@ -336,6 +336,12 @@ if (NOT ELSEIF_RESULT EQUAL 2)
|
||||||
set (ELSEIF_RESULT 0)
|
set (ELSEIF_RESULT 0)
|
||||||
endif (NOT ELSEIF_RESULT EQUAL 2)
|
endif (NOT ELSEIF_RESULT EQUAL 2)
|
||||||
|
|
||||||
|
# test handling of parenthetical groups in conditionals
|
||||||
|
if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
|
||||||
|
set(CONDITIONAL_PARENTHESES 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Configure file
|
# Configure file
|
||||||
# (plug vars to #define so that they can be tested)
|
# (plug vars to #define so that they can be tested)
|
||||||
|
|
|
@ -369,6 +369,12 @@ int main()
|
||||||
cmFailed("ELSEIF did not work");
|
cmFailed("ELSEIF did not work");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONDITIONAL_PARENTHESES
|
||||||
|
cmPassed("CONDITIONAL_PARENTHESES did work");
|
||||||
|
#else
|
||||||
|
cmFailed("CONDITIONAL_PARENTHESES did not work");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(file2() != 1)
|
if(file2() != 1)
|
||||||
{
|
{
|
||||||
cmFailed("Call to file2 function from library failed.");
|
cmFailed("Call to file2 function from library failed.");
|
||||||
|
|
|
@ -81,3 +81,7 @@
|
||||||
|
|
||||||
// test elseif
|
// test elseif
|
||||||
#cmakedefine ELSEIF_RESULT
|
#cmakedefine ELSEIF_RESULT
|
||||||
|
|
||||||
|
// test parenthesis in conditionals
|
||||||
|
#cmakedefine CONDITIONAL_PARENTHESES
|
||||||
|
|
||||||
|
|
|
@ -336,6 +336,12 @@ if (NOT ELSEIF_RESULT EQUAL 2)
|
||||||
set (ELSEIF_RESULT 0)
|
set (ELSEIF_RESULT 0)
|
||||||
endif (NOT ELSEIF_RESULT EQUAL 2)
|
endif (NOT ELSEIF_RESULT EQUAL 2)
|
||||||
|
|
||||||
|
# test handling of parenthetical groups in conditionals
|
||||||
|
if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
|
||||||
|
set(CONDITIONAL_PARENTHESES 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Configure file
|
# Configure file
|
||||||
# (plug vars to #define so that they can be tested)
|
# (plug vars to #define so that they can be tested)
|
||||||
|
|
|
@ -369,6 +369,12 @@ int main()
|
||||||
cmFailed("ELSEIF did not work");
|
cmFailed("ELSEIF did not work");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONDITIONAL_PARENTHESES
|
||||||
|
cmPassed("CONDITIONAL_PARENTHESES did work");
|
||||||
|
#else
|
||||||
|
cmFailed("CONDITIONAL_PARENTHESES did not work");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(file2() != 1)
|
if(file2() != 1)
|
||||||
{
|
{
|
||||||
cmFailed("Call to file2 function from library failed.");
|
cmFailed("Call to file2 function from library failed.");
|
||||||
|
|
|
@ -81,3 +81,7 @@
|
||||||
|
|
||||||
// test elseif
|
// test elseif
|
||||||
#cmakedefine ELSEIF_RESULT
|
#cmakedefine ELSEIF_RESULT
|
||||||
|
|
||||||
|
// test parenthesis in conditionals
|
||||||
|
#cmakedefine CONDITIONAL_PARENTHESES
|
||||||
|
|
||||||
|
|
|
@ -336,6 +336,12 @@ if (NOT ELSEIF_RESULT EQUAL 2)
|
||||||
set (ELSEIF_RESULT 0)
|
set (ELSEIF_RESULT 0)
|
||||||
endif (NOT ELSEIF_RESULT EQUAL 2)
|
endif (NOT ELSEIF_RESULT EQUAL 2)
|
||||||
|
|
||||||
|
# test handling of parenthetical groups in conditionals
|
||||||
|
if (2 GREATER 1 AND (4 LESS 3 OR 5 LESS 6) AND NOT (7 GREATER 8))
|
||||||
|
set(CONDITIONAL_PARENTHESES 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Configure file
|
# Configure file
|
||||||
# (plug vars to #define so that they can be tested)
|
# (plug vars to #define so that they can be tested)
|
||||||
|
|
|
@ -369,6 +369,12 @@ int main()
|
||||||
cmFailed("ELSEIF did not work");
|
cmFailed("ELSEIF did not work");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONDITIONAL_PARENTHESES
|
||||||
|
cmPassed("CONDITIONAL_PARENTHESES did work");
|
||||||
|
#else
|
||||||
|
cmFailed("CONDITIONAL_PARENTHESES did not work");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(file2() != 1)
|
if(file2() != 1)
|
||||||
{
|
{
|
||||||
cmFailed("Call to file2 function from library failed.");
|
cmFailed("Call to file2 function from library failed.");
|
||||||
|
|
|
@ -81,3 +81,7 @@
|
||||||
|
|
||||||
// test elseif
|
// test elseif
|
||||||
#cmakedefine ELSEIF_RESULT
|
#cmakedefine ELSEIF_RESULT
|
||||||
|
|
||||||
|
// test parenthesis in conditionals
|
||||||
|
#cmakedefine CONDITIONAL_PARENTHESES
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue