CVS resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmFunctionCommand.cxx
blob17ecb80530d89314945c1343132768cb6dc10ae4
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFunctionCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2008/01/23 15:27:59 $
7 Version: $Revision: 1.4 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmFunctionCommand.h"
19 #include "cmake.h"
21 // define the class for function commands
22 class cmFunctionHelperCommand : public cmCommand
24 public:
25 cmFunctionHelperCommand() {}
27 ///! clean up any memory allocated by the function
28 ~cmFunctionHelperCommand() {};
30 /**
31 * This is a virtual constructor for the command.
33 virtual cmCommand* Clone()
35 cmFunctionHelperCommand *newC = new cmFunctionHelperCommand;
36 // we must copy when we clone
37 newC->Args = this->Args;
38 newC->Functions = this->Functions;
39 return newC;
42 /**
43 * This determines if the command is invoked when in script mode.
45 virtual bool IsScriptable() { return true; }
47 /**
48 * This is called when the command is first encountered in
49 * the CMakeLists.txt file.
51 virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
52 cmExecutionStatus &);
54 virtual bool InitialPass(std::vector<std::string> const&,
55 cmExecutionStatus &) { return false; };
57 /**
58 * The name of the command as specified in CMakeList.txt.
60 virtual const char* GetName() { return this->Args[0].c_str(); }
62 /**
63 * Succinct documentation.
65 virtual const char* GetTerseDocumentation()
67 std::string docs = "Function named: ";
68 docs += this->GetName();
69 return docs.c_str();
72 /**
73 * More documentation.
75 virtual const char* GetFullDocumentation()
77 return this->GetTerseDocumentation();
80 cmTypeMacro(cmFunctionHelperCommand, cmCommand);
82 std::vector<std::string> Args;
83 std::vector<cmListFileFunction> Functions;
87 bool cmFunctionHelperCommand::InvokeInitialPass
88 (const std::vector<cmListFileArgument>& args,
89 cmExecutionStatus &)
91 // Expand the argument list to the function.
92 std::vector<std::string> expandedArgs;
93 this->Makefile->ExpandArguments(args, expandedArgs);
95 // make sure the number of arguments passed is at least the number
96 // required by the signature
97 if (expandedArgs.size() < this->Args.size() - 1)
99 std::string errorMsg =
100 "Function invoked with incorrect arguments for function named: ";
101 errorMsg += this->Args[0];
102 this->SetError(errorMsg.c_str());
103 return false;
106 // we push a scope on the makefile
107 this->Makefile->PushScope();
109 // set the value of argc
110 cmOStringStream strStream;
111 strStream << expandedArgs.size();
112 this->Makefile->AddDefinition("ARGC",strStream.str().c_str());
114 // set the values for ARGV0 ARGV1 ...
115 for (unsigned int t = 0; t < expandedArgs.size(); ++t)
117 cmOStringStream tmpStream;
118 tmpStream << "ARGV" << t;
119 this->Makefile->AddDefinition(tmpStream.str().c_str(),
120 expandedArgs[t].c_str());
123 // define the formal arguments
124 for (unsigned int j = 1; j < this->Args.size(); ++j)
126 this->Makefile->AddDefinition(this->Args[j].c_str(),
127 expandedArgs[j-1].c_str());
130 // define ARGV and ARGN
131 std::vector<std::string>::const_iterator eit;
132 std::string argvDef;
133 std::string argnDef;
134 unsigned int cnt = 0;
135 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
137 if ( argvDef.size() > 0 )
139 argvDef += ";";
141 argvDef += *eit;
142 if ( cnt >= this->Args.size()-1 )
144 if ( argnDef.size() > 0 )
146 argnDef += ";";
148 argnDef += *eit;
150 cnt ++;
152 this->Makefile->AddDefinition("ARGV", argvDef.c_str());
153 this->Makefile->AddDefinition("ARGN", argnDef.c_str());
155 // Invoke all the functions that were collected in the block.
156 // for each function
157 for(unsigned int c = 0; c < this->Functions.size(); ++c)
159 cmExecutionStatus status;
160 if (!this->Makefile->ExecuteCommand(this->Functions[c],status))
162 cmOStringStream error;
163 error << "Error in cmake code at\n"
164 << this->Functions[c].FilePath << ":"
165 << this->Functions[c].Line << ":\n"
166 << "A command failed during the invocation of function \""
167 << this->Args[0].c_str() << "\".";
168 cmSystemTools::Error(error.str().c_str());
170 // pop scope on the makefile and return
171 this->Makefile->PopScope();
172 return false;
174 if (status.GetReturnInvoked())
176 this->Makefile->PopScope();
177 return true;
181 // pop scope on the makefile
182 this->Makefile->PopScope();
183 return true;
186 bool cmFunctionFunctionBlocker::
187 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
188 cmExecutionStatus &)
190 // record commands until we hit the ENDFUNCTION
191 // at the ENDFUNCTION call we shift gears and start looking for invocations
192 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"function"))
194 this->Depth++;
196 else if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endfunction"))
198 // if this is the endfunction for this function then execute
199 if (!this->Depth)
201 std::string name = this->Args[0];
202 std::vector<std::string>::size_type cc;
203 name += "(";
204 for ( cc = 0; cc < this->Args.size(); cc ++ )
206 name += " " + this->Args[cc];
208 name += " )";
210 // create a new command and add it to cmake
211 cmFunctionHelperCommand *f = new cmFunctionHelperCommand();
212 f->Args = this->Args;
213 f->Functions = this->Functions;
215 // Set the FilePath on the arguments to match the function since it is
216 // not stored and the original values may be freed
217 for (unsigned int i = 0; i < f->Functions.size(); ++i)
219 for (unsigned int j = 0; j < f->Functions[i].Arguments.size(); ++j)
221 f->Functions[i].Arguments[j].FilePath =
222 f->Functions[i].FilePath.c_str();
226 std::string newName = "_" + this->Args[0];
227 mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
228 newName.c_str());
229 mf.AddCommand(f);
231 // remove the function blocker now that the function is defined
232 mf.RemoveFunctionBlocker(lff);
233 return true;
235 else
237 // decrement for each nested function that ends
238 this->Depth--;
242 // if it wasn't an endfunction and we are not executing then we must be
243 // recording
244 this->Functions.push_back(lff);
245 return true;
249 bool cmFunctionFunctionBlocker::
250 ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
252 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endfunction"))
254 std::vector<std::string> expandedArguments;
255 mf.ExpandArguments(lff.Arguments, expandedArguments);
256 if ((!expandedArguments.empty() &&
257 (expandedArguments[0] == this->Args[0]))
258 || cmSystemTools::IsOn
259 (mf.GetPropertyOrDefinition("CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS")))
261 return true;
265 return false;
268 void cmFunctionFunctionBlocker::
269 ScopeEnded(cmMakefile &mf)
271 // functions should end with an EndFunction
272 cmSystemTools::Error(
273 "The end of a CMakeLists file was reached with a FUNCTION statement that "
274 "was not closed properly. Within the directory: ",
275 mf.GetCurrentDirectory(), " with function ",
276 this->Args[0].c_str());
279 bool cmFunctionCommand
280 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
282 if(args.size() < 1)
284 this->SetError("called with incorrect number of arguments");
285 return false;
288 // create a function blocker
289 cmFunctionFunctionBlocker *f = new cmFunctionFunctionBlocker();
290 for(std::vector<std::string>::const_iterator j = args.begin();
291 j != args.end(); ++j)
293 f->Args.push_back(*j);
295 this->Makefile->AddFunctionBlocker(f);
296 return true;