1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmForEachCommand.h"
14 #include <cmsys/auto_ptr.hxx>
16 bool cmForEachFunctionBlocker::
17 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
18 cmExecutionStatus &inStatus)
20 if (!cmSystemTools::Strucmp(lff.Name.c_str(),"foreach"))
22 // record the number of nested foreach commands
25 else if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
27 // if this is the endofreach for this statement
30 // Remove the function blocker for this scope or bail.
31 cmsys::auto_ptr<cmFunctionBlocker>
32 fb(mf.RemoveFunctionBlocker(this, lff));
33 if(!fb.get()) { return false; }
35 // at end of for each execute recorded commands
36 // store the old value
38 if (mf.GetDefinition(this->Args[0].c_str()))
40 oldDef = mf.GetDefinition(this->Args[0].c_str());
42 std::vector<std::string>::const_iterator j = this->Args.begin();
46 cmListFileArgument arg;
47 for( ; j != this->Args.end(); ++j)
49 // set the variable to the loop value
50 mf.AddDefinition(this->Args[0].c_str(),j->c_str());
51 // Invoke all the functions that were collected in the block.
52 cmExecutionStatus status;
53 for(unsigned int c = 0; c < this->Functions.size(); ++c)
56 mf.ExecuteCommand(this->Functions[c],status);
57 if (status.GetReturnInvoked())
59 inStatus.SetReturnInvoked(true);
60 // restore the variable to its prior value
61 mf.AddDefinition(this->Args[0].c_str(),oldDef.c_str());
64 if (status.GetBreakInvoked())
66 // restore the variable to its prior value
67 mf.AddDefinition(this->Args[0].c_str(),oldDef.c_str());
70 if(cmSystemTools::GetFatalErrorOccured() )
76 // restore the variable to its prior value
77 mf.AddDefinition(this->Args[0].c_str(),oldDef.c_str());
82 // close out a nested foreach
88 this->Functions.push_back(lff);
94 bool cmForEachFunctionBlocker::
95 ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf)
97 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
99 std::vector<std::string> expandedArguments;
100 mf.ExpandArguments(lff.Arguments, expandedArguments);
101 // if the endforeach has arguments then make sure
102 // they match the begin foreach arguments
103 if ((expandedArguments.empty() ||
104 (expandedArguments[0] == this->Args[0])))
112 bool cmForEachCommand
113 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
117 this->SetError("called with incorrect number of arguments");
120 if(args.size() > 1 && args[1] == "IN")
122 return this->HandleInMode(args);
125 // create a function blocker
126 cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
127 if ( args.size() > 1 )
129 if ( args[1] == "RANGE" )
134 if ( args.size() == 3 )
136 stop = atoi(args[2].c_str());
138 if ( args.size() == 4 )
140 start = atoi(args[2].c_str());
141 stop = atoi(args[3].c_str());
143 if ( args.size() == 5 )
145 start = atoi(args[2].c_str());
146 stop = atoi(args[3].c_str());
147 step = atoi(args[4].c_str());
161 (start > stop && step > 0) ||
162 (start < stop && step < 0) ||
167 str << "called with incorrect range specification: start ";
168 str << start << ", stop " << stop << ", step " << step;
169 this->SetError(str.str().c_str());
172 std::vector<std::string> range;
174 range.push_back(args[0]);
176 for ( cc = start; ; cc += step )
178 if ( (step > 0 && cc > stop) || (step < 0 && cc < stop) )
182 sprintf(buffer, "%d", cc);
183 range.push_back(buffer);
200 this->Makefile->AddFunctionBlocker(f);
205 //----------------------------------------------------------------------------
206 bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args)
208 cmsys::auto_ptr<cmForEachFunctionBlocker> f(new cmForEachFunctionBlocker());
209 f->Args.push_back(args[0]);
211 enum Doing { DoingNone, DoingLists, DoingItems };
212 Doing doing = DoingNone;
213 for(unsigned int i=2; i < args.size(); ++i)
215 if(doing == DoingItems)
217 f->Args.push_back(args[i]);
219 else if(args[i] == "LISTS")
223 else if(args[i] == "ITEMS")
227 else if(doing == DoingLists)
229 const char* value = this->Makefile->GetDefinition(args[i].c_str());
232 cmSystemTools::ExpandListArgument(value, f->Args, true);
238 e << "Unknown argument:\n" << " " << args[i] << "\n";
239 this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
244 this->Makefile->AddFunctionBlocker(f.release()); // TODO: pass auto_ptr