1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmForEachCommand.cxx,v $
6 Date: $Date: 2009-05-13 15:08:28 $
7 Version: $Revision: 1.32 $
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 "cmForEachCommand.h"
19 #include <cmsys/auto_ptr.hxx>
21 bool cmForEachFunctionBlocker::
22 IsFunctionBlocked(const cmListFileFunction
& lff
, cmMakefile
&mf
,
23 cmExecutionStatus
&inStatus
)
25 if (!cmSystemTools::Strucmp(lff
.Name
.c_str(),"foreach"))
27 // record the number of nested foreach commands
30 else if (!cmSystemTools::Strucmp(lff
.Name
.c_str(),"endforeach"))
32 // if this is the endofreach for this statement
35 // Remove the function blocker for this scope or bail.
36 cmsys::auto_ptr
<cmFunctionBlocker
>
37 fb(mf
.RemoveFunctionBlocker(this, lff
));
38 if(!fb
.get()) { return false; }
40 // at end of for each execute recorded commands
41 // store the old value
43 if (mf
.GetDefinition(this->Args
[0].c_str()))
45 oldDef
= mf
.GetDefinition(this->Args
[0].c_str());
47 std::vector
<std::string
>::const_iterator j
= this->Args
.begin();
51 cmListFileArgument arg
;
52 for( ; j
!= this->Args
.end(); ++j
)
54 // set the variable to the loop value
55 mf
.AddDefinition(this->Args
[0].c_str(),j
->c_str());
56 // Invoke all the functions that were collected in the block.
57 cmExecutionStatus status
;
58 for(unsigned int c
= 0; c
< this->Functions
.size(); ++c
)
61 mf
.ExecuteCommand(this->Functions
[c
],status
);
62 if (status
.GetReturnInvoked())
64 inStatus
.SetReturnInvoked(true);
65 // restore the variable to its prior value
66 mf
.AddDefinition(this->Args
[0].c_str(),oldDef
.c_str());
69 if (status
.GetBreakInvoked())
71 // restore the variable to its prior value
72 mf
.AddDefinition(this->Args
[0].c_str(),oldDef
.c_str());
75 if(cmSystemTools::GetFatalErrorOccured() )
81 // restore the variable to its prior value
82 mf
.AddDefinition(this->Args
[0].c_str(),oldDef
.c_str());
87 // close out a nested foreach
93 this->Functions
.push_back(lff
);
99 bool cmForEachFunctionBlocker::
100 ShouldRemove(const cmListFileFunction
& lff
, cmMakefile
& mf
)
102 if(!cmSystemTools::Strucmp(lff
.Name
.c_str(),"endforeach"))
104 std::vector
<std::string
> expandedArguments
;
105 mf
.ExpandArguments(lff
.Arguments
, expandedArguments
);
106 // if the endforeach has arguments then make sure
107 // they match the begin foreach arguments
108 if ((expandedArguments
.empty() ||
109 (expandedArguments
[0] == this->Args
[0])))
117 bool cmForEachCommand
118 ::InitialPass(std::vector
<std::string
> const& args
, cmExecutionStatus
&)
122 this->SetError("called with incorrect number of arguments");
125 if(args
.size() > 1 && args
[1] == "IN")
127 return this->HandleInMode(args
);
130 // create a function blocker
131 cmForEachFunctionBlocker
*f
= new cmForEachFunctionBlocker();
132 if ( args
.size() > 1 )
134 if ( args
[1] == "RANGE" )
139 if ( args
.size() == 3 )
141 stop
= atoi(args
[2].c_str());
143 if ( args
.size() == 4 )
145 start
= atoi(args
[2].c_str());
146 stop
= atoi(args
[3].c_str());
148 if ( args
.size() == 5 )
150 start
= atoi(args
[2].c_str());
151 stop
= atoi(args
[3].c_str());
152 step
= atoi(args
[4].c_str());
166 (start
> stop
&& step
> 0) ||
167 (start
< stop
&& step
< 0) ||
172 str
<< "called with incorrect range specification: start ";
173 str
<< start
<< ", stop " << stop
<< ", step " << step
;
174 this->SetError(str
.str().c_str());
177 std::vector
<std::string
> range
;
179 range
.push_back(args
[0]);
181 for ( cc
= start
; ; cc
+= step
)
183 if ( (step
> 0 && cc
> stop
) || (step
< 0 && cc
< stop
) )
187 sprintf(buffer
, "%d", cc
);
188 range
.push_back(buffer
);
205 this->Makefile
->AddFunctionBlocker(f
);
210 //----------------------------------------------------------------------------
211 bool cmForEachCommand::HandleInMode(std::vector
<std::string
> const& args
)
213 cmsys::auto_ptr
<cmForEachFunctionBlocker
> f(new cmForEachFunctionBlocker());
214 f
->Args
.push_back(args
[0]);
216 enum Doing
{ DoingNone
, DoingLists
, DoingItems
};
217 Doing doing
= DoingNone
;
218 for(unsigned int i
=2; i
< args
.size(); ++i
)
220 if(doing
== DoingItems
)
222 f
->Args
.push_back(args
[i
]);
224 else if(args
[i
] == "LISTS")
228 else if(args
[i
] == "ITEMS")
232 else if(doing
== DoingLists
)
234 const char* value
= this->Makefile
->GetDefinition(args
[i
].c_str());
237 cmSystemTools::ExpandListArgument(value
, f
->Args
, true);
243 e
<< "Unknown argument:\n" << " " << args
[i
] << "\n";
244 this->Makefile
->IssueMessage(cmake::FATAL_ERROR
, e
.str());
249 this->Makefile
->AddFunctionBlocker(f
.release()); // TODO: pass auto_ptr