summaryrefslogtreecommitdiffstats
path: root/Source/cmIfCommand.cxx
diff options
context:
space:
mode:
authorKen Martin <ken.martin@kitware.com>2008-06-26 17:01:35 (GMT)
committerKen Martin <ken.martin@kitware.com>2008-06-26 17:01:35 (GMT)
commit19e891532a915d1fa4fcf4cdba6254d28c2adc6c (patch)
tree8f128805f9f8e6bcef1bee2a10acf9e4b6e4bc83 /Source/cmIfCommand.cxx
parentd8e05b43a1fc0370aa3ac84f4209b1b942809b89 (diff)
downloadCMake-19e891532a915d1fa4fcf4cdba6254d28c2adc6c.zip
CMake-19e891532a915d1fa4fcf4cdba6254d28c2adc6c.tar.gz
CMake-19e891532a915d1fa4fcf4cdba6254d28c2adc6c.tar.bz2
ENH: support parenthesis as arguments and in conditionals feature request #6191
Diffstat (limited to 'Source/cmIfCommand.cxx')
-rw-r--r--Source/cmIfCommand.cxx499
1 files changed, 277 insertions, 222 deletions
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
index 517348c..0baf142 100644
--- a/Source/cmIfCommand.cxx
+++ b/Source/cmIfCommand.cxx
@@ -21,8 +21,10 @@
#include <list>
#include <cmsys/RegularExpression.hxx>
+//=========================================================================
bool cmIfFunctionBlocker::
-IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
+IsFunctionBlocked(const cmListFileFunction& lff,
+ cmMakefile &mf,
cmExecutionStatus &inStatus)
{
// Prevent recusion and don't let this blocker block its own
@@ -140,6 +142,7 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
return true;
}
+//=========================================================================
bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
cmMakefile&)
{
@@ -157,8 +160,8 @@ bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
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 "
"IF statement that was not closed properly.\nWithin the directory: ";
@@ -175,6 +178,7 @@ ScopeEnded(cmMakefile &mf)
cmSystemTools::Message(errmsg.c_str(), "Warning");
}
+//=========================================================================
bool cmIfCommand
::InvokeInitialPass(const std::vector<cmListFileArgument>& args,
cmExecutionStatus &)
@@ -221,6 +225,7 @@ bool cmIfCommand
namespace
{
+//=========================================================================
void IncrementArguments(std::list<std::string> &newArgs,
std::list<std::string>::iterator &argP1,
std::list<std::string>::iterator &argP2)
@@ -235,68 +240,108 @@ namespace
}
}
}
-}
-
-
-// order of operations,
-// IS_DIRECTORY EXISTS COMMAND DEFINED
-// MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL
-// 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 *def2;
- const char* msg = "Unknown arguments specified";
- *errorString = new char[strlen(msg) + 1];
- strcpy(*errorString, msg);
+ //=========================================================================
+ // helper function to reduce code duplication
+ void HandlePredicate(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(argP1);
+ argP1 = arg;
+ IncrementArguments(newArgs,argP1,argP2);
+ reducible = 1;
+ }
- // handle empty invocation
- if (args.size() < 1)
- {
- delete [] *errorString;
- *errorString = 0;
- return false;
- }
+ //=========================================================================
+ // 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;
+ }
- // store the reduced args in this vector
- std::list<std::string> newArgs;
+ //=========================================================================
+ // level 0 processes parenthetical expressions
+ bool HandleLevel0(std::list<std::string> &newArgs,
+ cmMakefile *makefile,
+ char **errorString)
+ {
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
{
reducible = 0;
std::list<std::string>::iterator arg = newArgs.begin();
while (arg != newArgs.end())
{
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- // does a file exist
- if (*arg == "EXISTS" && argP1 != newArgs.end())
+ if (*arg == "(")
{
- if(cmSystemTools::FileExists((argP1)->c_str()))
+ // 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";
}
@@ -304,75 +349,70 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
{
*arg = "0";
}
- newArgs.erase(argP1);
argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ 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())
+ {
+ argP1 = arg;
+ IncrementArguments(newArgs,argP1,argP2);
+ // does a file exist
+ if (*arg == "EXISTS" && argP1 != newArgs.end())
+ {
+ HandlePredicate(
+ cmSystemTools::FileExists((argP1)->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
}
// does a directory with this name exist
if (*arg == "IS_DIRECTORY" && argP1 != newArgs.end())
{
- if(cmSystemTools::FileIsDirectory((argP1)->c_str()))
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandlePredicate(
+ cmSystemTools::FileIsDirectory((argP1)->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
}
// is the given path an absolute path ?
if (*arg == "IS_ABSOLUTE" && argP1 != newArgs.end())
{
- if(cmSystemTools::FileIsFullPath((argP1)->c_str()))
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandlePredicate(
+ cmSystemTools::FileIsFullPath((argP1)->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
}
// does a command exist
if (*arg == "COMMAND" && argP1 != newArgs.end())
{
- if(makefile->CommandExists((argP1)->c_str()))
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandlePredicate(
+ makefile->CommandExists((argP1)->c_str()),
+ reducible, arg, newArgs, argP1, argP2);
}
// does a policy exist
if (*arg == "POLICY" && argP1 != newArgs.end())
{
cmPolicies::PolicyID pid;
- if(makefile->GetPolicies()->GetPolicyID((argP1)->c_str(), pid))
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandlePredicate(
+ makefile->GetPolicies()->GetPolicyID((argP1)->c_str(), pid),
+ reducible, arg, newArgs, argP1, argP2);
}
// is a variable defined
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());
}
- if(bdef)
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
}
++arg;
}
}
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 two handles most binary operations except for AND OR
+ bool HandleLevel2(std::list<std::string> &newArgs,
+ cmMakefile *makefile,
+ char **errorString)
+ {
+ int reducible;
+ const char *def;
+ const char *def2;
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())
{
argP1 = arg;
@@ -468,49 +506,26 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
double lhs;
double rhs;
+ bool result;
if(sscanf(def, "%lg", &lhs) != 1 ||
sscanf(def2, "%lg", &rhs) != 1)
{
- *arg = "0";
+ result = false;
}
else if (*(argP1) == "LESS")
{
- if(lhs < rhs)
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
+ result = (lhs < rhs);
}
else if (*(argP1) == "GREATER")
{
- if(lhs > rhs)
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
+ result = (lhs > rhs);
}
else
{
- if(lhs == rhs)
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
+ result = (lhs == rhs);
}
- newArgs.erase(argP2);
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandleBinaryOp(result,
+ reducible, arg, newArgs, argP1, argP2);
}
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);
def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
int val = strcmp(def,def2);
- int result;
+ bool result;
if (*(argP1) == "STRLESS")
{
result = (val < 0);
@@ -534,19 +549,8 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
{
result = (val == 0);
}
- if(result)
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
- newArgs.erase(argP2);
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandleBinaryOp(result,
+ reducible, arg, newArgs, argP1, argP2);
}
// 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(),
(argP2)->c_str(),
&fileIsNewer);
- if(success==false || fileIsNewer==1 || fileIsNewer==0)
- {
- *arg = "1";
- }
- else
- {
- *arg = "0";
- }
- newArgs.erase(argP2);
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandleBinaryOp(
+ (success==false || fileIsNewer==1 || fileIsNewer==0),
+ reducible, arg, newArgs, argP1, argP2);
}
++arg;
}
}
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 3 handles NOT
+ bool HandleLevel3(std::list<std::string> &newArgs,
+ cmMakefile *makefile,
+ char **)
+ {
+ int reducible;
+ const char *def;
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())
{
argP1 = arg;
@@ -591,30 +594,31 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
if (argP1 != newArgs.end() && *arg == "NOT")
{
def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
- if(!cmSystemTools::IsOff(def))
- {
- *arg = "0";
- }
- else
- {
- *arg = "1";
- }
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandlePredicate(cmSystemTools::IsOff(def),
+ reducible, arg, newArgs, argP1, argP2);
}
++arg;
}
}
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
{
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())
{
argP1 = arg;
@@ -624,19 +628,9 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
{
def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
- if(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2))
- {
- *arg = "0";
- }
- else
- {
- *arg = "1";
- }
- newArgs.erase(argP2);
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandleBinaryOp(
+ !(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2)),
+ reducible, arg, newArgs, argP1, argP2);
}
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);
def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
- if(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2))
- {
- *arg = "0";
- }
- else
- {
- *arg = "1";
- }
- newArgs.erase(argP2);
- newArgs.erase(argP1);
- argP1 = arg;
- IncrementArguments(newArgs,argP1,argP2);
- reducible = 1;
+ HandleBinaryOp(
+ !(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2)),
+ reducible, arg, newArgs, argP1, argP2);
}
-
++arg;
}
}
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
if (newArgs.size() == 1)
@@ -687,6 +740,7 @@ bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
return true;
}
+//=========================================================================
const char* cmIfCommand::GetVariableOrString(const char* str,
const cmMakefile* mf)
{
@@ -698,6 +752,7 @@ const char* cmIfCommand::GetVariableOrString(const char* str,
return def;
}
+//=========================================================================
const char* cmIfCommand::GetVariableOrNumber(const char* str,
const cmMakefile* mf)
{