Updated formatting of documentation plus a little reorganization.
[cmake.git] / Source / cmMacroCommand.cxx
blobf0d724fa16e3c6fa4572e799b9aa114733ce42a9
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMacroCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2009-01-22 18:16:47 $
7 Version: $Revision: 1.41 $
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 "cmMacroCommand.h"
19 #include "cmake.h"
21 // define the class for macro commands
22 class cmMacroHelperCommand : public cmCommand
24 public:
25 cmMacroHelperCommand() {}
27 ///! clean up any memory allocated by the macro
28 ~cmMacroHelperCommand() {};
30 /**
31 * This is a virtual constructor for the command.
33 virtual cmCommand* Clone()
35 cmMacroHelperCommand *newC = new cmMacroHelperCommand;
36 // we must copy when we clone
37 newC->Args = this->Args;
38 newC->Functions = this->Functions;
39 newC->Policies = this->Policies;
40 return newC;
43 /**
44 * This determines if the command is invoked when in script mode.
46 virtual bool IsScriptable() { return true; }
48 /**
49 * This is called when the command is first encountered in
50 * the CMakeLists.txt file.
52 virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
53 cmExecutionStatus &);
55 virtual bool InitialPass(std::vector<std::string> const&,
56 cmExecutionStatus &) { return false; };
58 /**
59 * The name of the command as specified in CMakeList.txt.
61 virtual const char* GetName() { return this->Args[0].c_str(); }
63 /**
64 * Succinct documentation.
66 virtual const char* GetTerseDocumentation()
68 std::string docs = "Macro named: ";
69 docs += this->GetName();
70 return docs.c_str();
73 /**
74 * More documentation.
76 virtual const char* GetFullDocumentation()
78 return this->GetTerseDocumentation();
81 cmTypeMacro(cmMacroHelperCommand, cmCommand);
83 std::vector<std::string> Args;
84 std::vector<cmListFileFunction> Functions;
85 cmPolicies::PolicyMap Policies;
89 bool cmMacroHelperCommand::InvokeInitialPass
90 (const std::vector<cmListFileArgument>& args,
91 cmExecutionStatus &inStatus)
93 // Expand the argument list to the macro.
94 std::vector<std::string> expandedArgs;
95 this->Makefile->ExpandArguments(args, expandedArgs);
97 std::string tmps;
98 cmListFileArgument arg;
99 std::string variable;
101 // make sure the number of arguments passed is at least the number
102 // required by the signature
103 if (expandedArgs.size() < this->Args.size() - 1)
105 std::string errorMsg =
106 "Macro invoked with incorrect arguments for macro named: ";
107 errorMsg += this->Args[0];
108 this->SetError(errorMsg.c_str());
109 return false;
112 // Enforce matching logical blocks inside the macro.
113 cmMakefile::LexicalPushPop lexScope(this->Makefile);
115 // Push a weak policy scope which restores the policies recorded at
116 // macro creation.
117 cmMakefile::PolicyPushPop polScope(this->Makefile, true, this->Policies);
119 // set the value of argc
120 cmOStringStream argcDefStream;
121 argcDefStream << expandedArgs.size();
122 std::string argcDef = argcDefStream.str();
124 // declare varuiables for ARGV ARGN but do not compute until needed
125 std::string argvDef;
126 std::string argnDef;
127 bool argnDefInitialized = false;
128 bool argvDefInitialized = false;
130 // Invoke all the functions that were collected in the block.
131 cmListFileFunction newLFF;
132 // for each function
133 for(unsigned int c = 0; c < this->Functions.size(); ++c)
135 // Replace the formal arguments and then invoke the command.
136 newLFF.Arguments.clear();
137 newLFF.Arguments.reserve(this->Functions[c].Arguments.size());
138 newLFF.Name = this->Functions[c].Name;
139 newLFF.FilePath = this->Functions[c].FilePath;
140 newLFF.Line = this->Functions[c].Line;
142 // for each argument of the current function
143 for (std::vector<cmListFileArgument>::const_iterator k =
144 this->Functions[c].Arguments.begin();
145 k != this->Functions[c].Arguments.end(); ++k)
147 tmps = k->Value;
148 // replace formal arguments
149 for (unsigned int j = 1; j < this->Args.size(); ++j)
151 variable = "${";
152 variable += this->Args[j];
153 variable += "}";
154 cmSystemTools::ReplaceString(tmps, variable.c_str(),
155 expandedArgs[j-1].c_str());
157 // replace argc
158 cmSystemTools::ReplaceString(tmps, "${ARGC}",argcDef.c_str());
160 // repleace ARGN
161 if (tmps.find("${ARGN}") != std::string::npos)
163 if (!argnDefInitialized)
165 std::vector<std::string>::const_iterator eit;
166 std::vector<std::string>::size_type cnt = 0;
167 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
169 if ( cnt >= this->Args.size()-1 )
171 if ( argnDef.size() > 0 )
173 argnDef += ";";
175 argnDef += *eit;
177 cnt ++;
179 argnDefInitialized = true;
181 cmSystemTools::ReplaceString(tmps, "${ARGN}", argnDef.c_str());
184 // if the current argument of the current function has ${ARGV in it
185 // then try replacing ARGV values
186 if (tmps.find("${ARGV") != std::string::npos)
188 char argvName[60];
190 // repleace ARGV, compute it only once
191 if (!argvDefInitialized)
193 std::vector<std::string>::const_iterator eit;
194 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
196 if ( argvDef.size() > 0 )
198 argvDef += ";";
200 argvDef += *eit;
202 argvDefInitialized = true;
204 cmSystemTools::ReplaceString(tmps, "${ARGV}", argvDef.c_str());
206 // also replace the ARGV1 ARGV2 ... etc
207 for (unsigned int t = 0; t < expandedArgs.size(); ++t)
209 sprintf(argvName,"${ARGV%i}",t);
210 cmSystemTools::ReplaceString(tmps, argvName,
211 expandedArgs[t].c_str());
215 arg.Value = tmps;
216 arg.Quoted = k->Quoted;
217 arg.FilePath = k->FilePath;
218 arg.Line = k->Line;
219 newLFF.Arguments.push_back(arg);
221 cmExecutionStatus status;
222 if(!this->Makefile->ExecuteCommand(newLFF, status) ||
223 status.GetNestedError())
225 // The error message should have already included the call stack
226 // so we do not need to report an error here.
227 lexScope.Quiet();
228 polScope.Quiet();
229 inStatus.SetNestedError(true);
230 return false;
232 if (status.GetReturnInvoked())
234 inStatus.SetReturnInvoked(true);
235 return true;
237 if (status.GetBreakInvoked())
239 inStatus.SetBreakInvoked(true);
240 return true;
243 return true;
246 bool cmMacroFunctionBlocker::
247 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
248 cmExecutionStatus &)
250 // record commands until we hit the ENDMACRO
251 // at the ENDMACRO call we shift gears and start looking for invocations
252 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"macro"))
254 this->Depth++;
256 else if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
258 // if this is the endmacro for this macro then execute
259 if (!this->Depth)
261 std::string name = this->Args[0];
262 std::vector<std::string>::size_type cc;
263 name += "(";
264 for ( cc = 0; cc < this->Args.size(); cc ++ )
266 name += " " + this->Args[cc];
268 name += " )";
269 mf.AddMacro(this->Args[0].c_str(), name.c_str());
270 // create a new command and add it to cmake
271 cmMacroHelperCommand *f = new cmMacroHelperCommand();
272 f->Args = this->Args;
273 f->Functions = this->Functions;
274 mf.RecordPolicies(f->Policies);
275 std::string newName = "_" + this->Args[0];
276 mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
277 newName.c_str());
278 mf.AddCommand(f);
280 // remove the function blocker now that the macro is defined
281 mf.RemoveFunctionBlocker(this, lff);
282 return true;
284 else
286 // decrement for each nested macro that ends
287 this->Depth--;
291 // if it wasn't an endmacro and we are not executing then we must be
292 // recording
293 this->Functions.push_back(lff);
294 return true;
298 bool cmMacroFunctionBlocker::
299 ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
301 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
303 std::vector<std::string> expandedArguments;
304 mf.ExpandArguments(lff.Arguments, expandedArguments);
305 // if the endmacro has arguments make sure they
306 // match the arguments of the macro
307 if ((expandedArguments.empty() ||
308 (expandedArguments[0] == this->Args[0])))
310 return true;
314 return false;
317 bool cmMacroCommand::InitialPass(std::vector<std::string> const& args,
318 cmExecutionStatus &)
320 if(args.size() < 1)
322 this->SetError("called with incorrect number of arguments");
323 return false;
326 // create a function blocker
327 cmMacroFunctionBlocker *f = new cmMacroFunctionBlocker();
328 for(std::vector<std::string>::const_iterator j = args.begin();
329 j != args.end(); ++j)
331 f->Args.push_back(*j);
333 this->Makefile->AddFunctionBlocker(f);
334 return true;