Commit 4888c088 authored by Brad King's avatar Brad King

ENH: Moved ExpandListVariables out of individual commands. Argument...

ENH: Moved ExpandListVariables out of individual commands.  Argument evaluation rules are now very consistent.  Double quotes can always be used to create exactly one argument, regardless of contents inside.
parent 5a321605
......@@ -19,7 +19,7 @@
#include "cmSourceFile.h"
// cmAbstractFilesCommand
bool cmAbstractFilesCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmAbstractFilesCommand::InitialPass(std::vector<std::string> const& args)
{
const char* versionValue
= m_Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
......@@ -29,13 +29,11 @@ bool cmAbstractFilesCommand::InitialPass(std::vector<std::string> const& argsIn)
return false;
}
if(argsIn.size() < 1 )
if(args.size() < 1 )
{
this->SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
bool ret = true;
std::string m = "could not find source file(s):\n";
......
......@@ -18,19 +18,17 @@
// cmAddCustomCommandCommand
bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmAddCustomCommandCommand::InitialPass(std::vector<std::string> const& args)
{
/* Let's complain at the end of this function about the lack of a particular
arg. For the moment, let's say that COMMAND, TARGET are always
required.
*/
if (argsIn.size() < 4)
if (args.size() < 4)
{
this->SetError("called with wrong number of arguments.");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
std::string source, command, target, comment;
std::vector<std::string> command_args, depends, outputs;
......
......@@ -17,17 +17,15 @@
#include "cmAddCustomTargetCommand.h"
// cmAddCustomTargetCommand
bool cmAddCustomTargetCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmAddCustomTargetCommand::InitialPass(std::vector<std::string> const& args)
{
bool all = false;
if(argsIn.size() < 2 )
if(args.size() < 2 )
{
this->SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
// all target option
std::string arguments;
......
......@@ -17,15 +17,13 @@
#include "cmAddDefinitionsCommand.h"
// cmAddDefinitionsCommand
bool cmAddDefinitionsCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmAddDefinitionsCommand::InitialPass(std::vector<std::string> const& args)
{
// it is OK to have no arguments
if(argsIn.size() < 1 )
if(args.size() < 1 )
{
return true;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
for(std::vector<std::string>::const_iterator i = args.begin();
i != args.end(); ++i)
......
......@@ -17,15 +17,13 @@
#include "cmAddDependenciesCommand.h"
// cmDependenciesCommand
bool cmAddDependenciesCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmAddDependenciesCommand::InitialPass(std::vector<std::string> const& args)
{
if(argsIn.size() < 2 )
if(args.size() < 2 )
{
this->SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
std::string target_name = args[0];
......
......@@ -17,16 +17,14 @@
#include "cmAddExecutableCommand.h"
// cmExecutableCommand
bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args)
{
if(argsIn.size() < 2 )
if(args.size() < 2 )
{
this->SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
std::vector<std::string>::iterator s = args.begin();
std::vector<std::string>::const_iterator s = args.begin();
std::string exename = *s;
......
......@@ -17,15 +17,13 @@
#include "cmAddLibraryCommand.h"
// cmLibraryCommand
bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args)
{
if(argsIn.size() < 1 )
if(args.size() < 1 )
{
this->SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
// Library type defaults to value of BUILD_SHARED_LIBS, if it exists,
// otherwise it defaults to static library.
int shared = !cmSystemTools::IsOff(m_Makefile->GetDefinition("BUILD_SHARED_LIBS"));
......
......@@ -32,8 +32,7 @@ bool cmAddTestCommand::InitialPass(std::vector<std::string> const& args)
// store the arguments for the final pass
// also expand any CMake variables
m_Args.erase(m_Args.begin(), m_Args.end());
cmSystemTools::ExpandListArguments(args, m_Args);
m_Args = args;
return true;
}
......
......@@ -296,12 +296,14 @@ void cmExecuteCommand(void *arg, const char *name,
{
cmMakefile *mf = static_cast<cmMakefile *>(arg);
std::vector<std::string> args2;
int i;
for (i = 0; i < numArgs; ++i)
cmListFileFunction lff;
lff.m_Name = name;
for(int i = 0; i < numArgs; ++i)
{
args2.push_back(args[i]);
// Assume all arguments are quoted.
lff.m_Arguments.push_back(cmListFileArgument(args[i], true));
}
mf->ExecuteCommand(std::string(name), args2);
mf->ExecuteCommand(lff);
}
void cmExpandSourceListArguments(void *arg,
......
......@@ -18,7 +18,8 @@
#define cmCommand_h
#include "cmStandardIncludes.h"
class cmMakefile;
#include "cmListFileCache.h"
#include "cmMakefile.h"
/** \class cmCommand
* \brief Superclass for all commands in CMake.
......@@ -50,6 +51,18 @@ public:
void SetMakefile(cmMakefile*m)
{m_Makefile = m; }
/**
* This is called by the cmMakefile when the command is first
* encountered in the CMakeLists.txt file. It expands the command's
* arguments and then invokes the InitialPass.
*/
virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args)
{
std::vector<std::string> expandedArguments;
m_Makefile->ExpandArguments(args, expandedArguments);
return this->InitialPass(expandedArguments);
}
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
......@@ -159,13 +172,14 @@ private:
// All subclasses of cmCommand should invoke this macro.
#define cmTypeMacro(thisClass,superclass) \
typedef superclass Superclass; \
static bool IsTypeOf(const char *type) \
{ \
if ( !strcmp(#thisClass,type) ) \
{ \
return true; \
} \
return superclass::IsTypeOf(type); \
return Superclass::IsTypeOf(type); \
} \
virtual bool IsA(const char *type) \
{ \
......
......@@ -18,18 +18,16 @@
#include "cmSourceFile.h"
// cmCreateTestSourceList
bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& argsIn)
bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& args)
{
if (argsIn.size() < 3)
if (args.size() < 3)
{
this->SetError("called with wrong number of arguments.");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
std::vector<std::string>::iterator i = args.begin();
std::vector<std::string>::const_iterator i = args.begin();
std::string extraInclude;
std::string function;
std::vector<std::string> tests;
......@@ -120,7 +118,7 @@ bool cmCreateTestSourceList::InitialPass(std::vector<std::string> const& argsIn)
"/* Forward declare test functions. */\n"
"\n";
std::vector<std::string>::iterator testsBegin = i;
std::vector<std::string>::const_iterator testsBegin = i;
std::vector<std::string> tests_func_name;
// The rest of the arguments consist of a list of test source files.
......
......@@ -16,7 +16,7 @@
=========================================================================*/
#include "cmEndForEachCommand.h"
bool cmEndForEachCommand::InitialPass(std::vector<std::string> const& args)
bool cmEndForEachCommand::InvokeInitialPass(std::vector<cmListFileArgument> const& args)
{
if(args.size() < 1 )
{
......@@ -25,7 +25,10 @@ bool cmEndForEachCommand::InitialPass(std::vector<std::string> const& args)
}
// remove any function blockers for this define
m_Makefile->RemoveFunctionBlocker("ENDFOREACH",args);
cmListFileFunction lff;
lff.m_Name = "ENDFOREACH";
lff.m_Arguments = args;
m_Makefile->RemoveFunctionBlocker(lff);
return true;
}
......
......@@ -36,11 +36,17 @@ public:
return new cmEndForEachCommand;
}
/**
* Override cmCommand::InvokeInitialPass to get arguments before
* expansion.
*/
virtual bool InvokeInitialPass(std::vector<cmListFileArgument> const&);
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
virtual bool InitialPass(std::vector<std::string> const& args);
virtual bool InitialPass(std::vector<std::string> const&) {}
/**
* This determines if the command gets propagated down
......
......@@ -31,12 +31,12 @@ bool cmFindFileCommand::InitialPass(std::vector<std::string> const& argsIn)
std::string helpString = "Where can the ";
helpString += argsIn[1] + " file be found";
size_t size = argsIn.size();
std::vector<std::string> argst;
std::vector<std::string> args;
for(unsigned int j = 0; j < size; ++j)
{
if(argsIn[j] != "DOC")
{
argst.push_back(argsIn[j]);
args.push_back(argsIn[j]);
}
else
{
......@@ -47,8 +47,6 @@ bool cmFindFileCommand::InitialPass(std::vector<std::string> const& argsIn)
break;
}
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argst, args);
std::vector<std::string>::const_iterator i = args.begin();
// Use the first argument as the name of something to be defined
......
......@@ -27,12 +27,12 @@ bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
}
std::string helpString;
size_t size = argsIn.size();
std::vector<std::string> argst;
std::vector<std::string> args;
for(unsigned int j = 0; j < size; ++j)
{
if(argsIn[j] != "DOC")
{
argst.push_back(argsIn[j]);
args.push_back(argsIn[j]);
}
else
{
......@@ -43,8 +43,6 @@ bool cmFindLibraryCommand::InitialPass(std::vector<std::string> const& argsIn)
break;
}
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argst, args);
std::vector<std::string> path;
std::vector<std::string> names;
......
......@@ -30,13 +30,13 @@ bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn)
// already, if so use that value and don't look for the program
std::string helpString = "What is the path where the file ";
helpString += argsIn[1] + " can be found";
std::vector<std::string> argst;
std::vector<std::string> args;
size_t size = argsIn.size();
for(unsigned int j = 0; j < size; ++j)
{
if(argsIn[j] != "DOC")
{
argst.push_back(argsIn[j]);
args.push_back(argsIn[j]);
}
else
{
......@@ -47,8 +47,6 @@ bool cmFindPathCommand::InitialPass(std::vector<std::string> const& argsIn)
break;
}
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argst, args);
const char* cacheValue
= m_Makefile->GetDefinition(args[0].c_str());
......
......@@ -30,12 +30,12 @@ bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
}
std::string doc = "Path to a program.";
size_t size = argsIn.size();
std::vector<std::string> argst;
std::vector<std::string> args;
for(unsigned int j = 0; j < size; ++j)
{
if(argsIn[j] != "DOC")
{
argst.push_back(argsIn[j]);
args.push_back(argsIn[j]);
}
else
{
......@@ -46,9 +46,6 @@ bool cmFindProgramCommand::InitialPass(std::vector<std::string> const& argsIn)
break;
}
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argst, args);
std::vector<std::string>::iterator i = args.begin();
// Use the first argument as the name of something to be defined
......
......@@ -17,68 +17,71 @@
#include "cmForEachCommand.h"
bool cmForEachFunctionBlocker::
IsFunctionBlocked(const char *name, const std::vector<std::string> &args,
cmMakefile &mf)
IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
{
// prevent recusion and don't let this blobker blobk its own commands
// Prevent recusion and don't let this blobker block its own
// commands.
if (m_Executing)
{
return false;
}
// at end of for each execute recorded commands
if (!strcmp(name,"ENDFOREACH") && args[0] == m_Args[0])
if (lff.m_Name == "ENDFOREACH")
{
m_Executing = true;
std::string variable = "${";
variable += m_Args[0];
variable += "}";
std::vector<std::string>::const_iterator j = m_Args.begin();
++j;
for( ; j != m_Args.end(); ++j)
{
// perform string replace
for(unsigned int c = 0; c < m_Commands.size(); ++c)
{
std::vector<std::string> newArgs;
for (std::vector<std::string>::const_iterator k =
m_CommandArguments[c].begin();
k != m_CommandArguments[c].end(); ++k)
std::vector<std::string> expandedArguments;
mf.ExpandArguments(lff.m_Arguments, expandedArguments);
if(!expandedArguments.empty() && (expandedArguments[0] == m_Args[0]))
{
m_Executing = true;
std::string variable = "${";
variable += m_Args[0];
variable += "}";
std::vector<std::string>::const_iterator j = m_Args.begin();
++j;
for( ; j != m_Args.end(); ++j)
{
// Invoke all the functions that were collected in the block.
for(unsigned int c = 0; c < m_Functions.size(); ++c)
{
std::string tmps = *k;
cmSystemTools::ReplaceString(tmps, variable.c_str(),
j->c_str());
newArgs.push_back(tmps);
// Replace the loop variable and then invoke the command.
cmListFileFunction newLFF;
newLFF.m_Name = m_Functions[c].m_Name;
for (std::vector<cmListFileArgument>::const_iterator k =
m_Functions[c].m_Arguments.begin();
k != m_Functions[c].m_Arguments.end(); ++k)
{
std::string tmps = k->Value;
cmSystemTools::ReplaceString(tmps, variable.c_str(), j->c_str());
cmListFileArgument arg(tmps, k->Quoted);
newLFF.m_Arguments.push_back(arg);
}
mf.ExecuteCommand(newLFF);
}
// execute command
mf.ExecuteCommand(m_Commands[c],newArgs);
}
return false;
}
return false;
}
// record the command
m_Commands.push_back(name);
std::vector<std::string> newArgs;
for(std::vector<std::string>::const_iterator j = args.begin();
j != args.end(); ++j)
{
newArgs.push_back(*j);
}
m_CommandArguments.push_back(newArgs);
m_Functions.push_back(lff);
// always return true
return true;
}
bool cmForEachFunctionBlocker::
ShouldRemove(const char *name, const std::vector<std::string> &args,
cmMakefile &)
ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf)
{
if (!strcmp(name,"ENDFOREACH") && args[0] == m_Args[0])
if(lff.m_Name == "ENDFOREACH")
{
return true;
std::vector<std::string> expandedArguments;
mf.ExpandArguments(lff.m_Arguments, expandedArguments);
if(!expandedArguments.empty() && (expandedArguments[0] == m_Args[0]))
{
return true;
}
}
return false;
}
......@@ -90,11 +93,8 @@ ScopeEnded(cmMakefile &mf)
mf.GetCurrentDirectory());
}
bool cmForEachCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmForEachCommand::InitialPass(std::vector<std::string> const& args)
{
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
if(args.size() < 1)
{
this->SetError("called with incorrect number of arguments");
......@@ -103,11 +103,7 @@ bool cmForEachCommand::InitialPass(std::vector<std::string> const& argsIn)
// create a function blocker
cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
for(std::vector<std::string>::const_iterator j = args.begin();
j != args.end(); ++j)
{
f->m_Args.push_back(*j);
}
f->m_Args = args;
m_Makefile->AddFunctionBlocker(f);
return true;
......
......@@ -20,6 +20,7 @@
#include "cmStandardIncludes.h"
#include "cmCommand.h"
#include "cmFunctionBlocker.h"
#include "cmListFileCache.h"
/** \class cmForEachFunctionBlocker
* \brief subclass of function blocker
......@@ -31,19 +32,13 @@ class cmForEachFunctionBlocker : public cmFunctionBlocker
public:
cmForEachFunctionBlocker() {m_Executing = false;}
virtual ~cmForEachFunctionBlocker() {}
virtual bool IsFunctionBlocked(const char *name,
const std::vector<std::string> &args,
virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
cmMakefile &mf);
virtual bool ShouldRemove(const char *name,
const std::vector<std::string> &args,
cmMakefile &mf);
virtual bool ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf);
virtual void ScopeEnded(cmMakefile &mf);
virtual int NeedExpandedVariables () { return 0; };
std::vector<std::string> m_Args;
std::vector<std::string> m_Commands;
std::vector<std::vector<std::string> > m_CommandArguments;
std::vector<cmListFileFunction> m_Functions;
bool m_Executing;
};
......
......@@ -31,15 +31,14 @@ public:
/**
* should a function be blocked
*/
virtual bool IsFunctionBlocked(const char *name, const std::vector<std::string> &args,
virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
cmMakefile&mf) = 0;
/**
* should this function blocker be removed, useful when one function adds a
* blocker and another must remove it
*/
virtual bool ShouldRemove(const char *,
const std::vector<std::string>&,
virtual bool ShouldRemove(const cmListFileFunction& lff,
cmMakefile&) {return false;}
/**
......@@ -50,8 +49,6 @@ public:
virtual void ScopeEnded(cmMakefile&) {}
virtual ~cmFunctionBlocker() {}
virtual int NeedExpandedVariables () { return 1; };
};
#endif
......@@ -59,15 +59,13 @@ cmITKWrapTclCommand::AddDependencies(cmDependInformation const *info,
}
// cmITKWrapTclCommand
bool cmITKWrapTclCommand::InitialPass(std::vector<std::string> const& argsIn)
bool cmITKWrapTclCommand::InitialPass(std::vector<std::string> const& args)
{
if(argsIn.size() < 2 )
if(args.size() < 2 )
{
this->SetError("called with incorrect number of arguments");
return false;
}
std::vector<std::string> args;
cmSystemTools::ExpandListArguments(argsIn, args);
// keep the target name
m_TargetName = args[0];
m_Target = &m_Makefile->GetTargets()[m_TargetName.c_str()];
......
......@@ -17,9 +17,10 @@
#include "cmIfCommand.h"
bool cmIfFunctionBlocker::
IsFunctionBlocked(const char *name, const std::vector<std::string> &args,
cmMakefile &mf)
IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
{
const char* name = lff.m_Name.c_str();
const std::vector<cmListFileArgument>& args = lff.m_Arguments;
// always let if statements through
if (!strcmp(name,"IF"))
{
......@@ -40,7 +41,7 @@ IsFunctionBlocked(const char *name, const std::vector<std::string> &args,
}
// otherwise it must be an ENDIF statement, in that case remove the
// function blocker
mf.RemoveFunctionBlocker("ENDIF",args);
mf.RemoveFunctionBlocker(lff);
return true;
}
else if(args.empty())
......@@ -50,10 +51,12 @@ IsFunctionBlocked(const char *name, const std::vector<std::string> &args,
err += ". Did you mean ";
err += name;
err += "( ";
for(std::vector<std::string>::const_iterator a = m_Args.begin();
for(std::vector<cmListFileArgument>::const_iterator a = m_Args.begin();
a != m_Args.end();++a)
{
err += *a;
err += (a->Quoted?"\"":"");
err += a->Value;
err += (a->Quoted?"\"":"");
err += " ";
}
err += ")?";
......@@ -63,13 +66,12 @@ IsFunctionBlocked(const char *name, const std::vector<std::string> &args,
return m_IsBlocking;
}
bool cmIfFunctionBlocker::
ShouldRemove(const char *name, const std::vector<std::string> &args,
cmMakefile &)
bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
cmMakefile&)
{
if (!strcmp(name,"ENDIF"))
if (lff.m_Name == "ENDIF")
{
if (args == m_Args)
if (lff.m_Arguments == m_Args)
{
return true;
}
......@@ -90,19 +92,24 @@ 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: ";
errmsg += mf.GetCurrentDirectory();
errmsg += "\nThe arguments are: ";
for(std::vector<std::string>::const_iterator j = m_Args.begin();
for(std::vector<cmListFileArgument>::const_iterator j = m_Args.begin();
j != m_Args.end(); ++j)
{
errmsg += *j;
errmsg += (j->Quoted?"\"":"");
errmsg += j->Value;
errmsg += (j->Quoted?"\"":"");
errmsg += " ";
}
cmSystemTools::Error(errmsg.c_str());
}
bool cmIfCommand::InitialPass(std::vector<std::string> const& args)
bool cmIfCommand::InvokeInitialPass(const std::vector<cmListFileArgument>& args)
{
bool isValid;
bool isTrue = cmIfCommand::IsTrue(args,isValid,m_Makefile);
std::vector<std::string> expandedArguments;
m_Makefile->ExpandArguments(args, expandedArguments);
bool isTrue = cmIfCommand::IsTrue(expandedArguments,isValid,m_Makefile);
if (!isValid)
{
......@@ -110,7 +117,9 @@ bool cmIfCommand::InitialPass(std::vector<std::string> const& args)
unsigned int i;
for(i =0; i < args.size(); ++i)
{
err += args[i];
err += (args[i].Quoted?"\"":"");
err += args[i].Value;
err += (args[i].Quoted?"\"":"");
err += " ";
}
this->SetError(err.c_str());
......@@ -120,25 +129,21 @@ bool cmIfCommand::InitialPass(std::vector<std::string> const& args)
cmIfFunctionBlocker *f = new cmIfFunctionBlocker();
// if is isn't true block the commands
f->m_IsBlocking = !isTrue;
for(std::vector<std::string>::const_iterator j = args.begin();
j != args.end(); ++j)
{
f->m_Args.push_back(*j);
}
f->m_Args = args;