1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmForEachCommand.cxx,v $
6 Date: $Date: 2009-03-17 19:10:15 $
7 Version: $Revision: 1.31 $
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());
77 // restore the variable to its prior value
78 mf
.AddDefinition(this->Args
[0].c_str(),oldDef
.c_str());
83 // close out a nested foreach
89 this->Functions
.push_back(lff
);
95 bool cmForEachFunctionBlocker::
96 ShouldRemove(const cmListFileFunction
& lff
, cmMakefile
& mf
)
98 if(!cmSystemTools::Strucmp(lff
.Name
.c_str(),"endforeach"))
100 std::vector
<std::string
> expandedArguments
;
101 mf
.ExpandArguments(lff
.Arguments
, expandedArguments
);
102 // if the endforeach has arguments then make sure
103 // they match the begin foreach arguments
104 if ((expandedArguments
.empty() ||
105 (expandedArguments
[0] == this->Args
[0])))
113 bool cmForEachCommand
114 ::InitialPass(std::vector
<std::string
> const& args
, cmExecutionStatus
&)
118 this->SetError("called with incorrect number of arguments");
121 if(args
.size() > 1 && args
[1] == "IN")
123 return this->HandleInMode(args
);
126 // create a function blocker
127 cmForEachFunctionBlocker
*f
= new cmForEachFunctionBlocker();
128 if ( args
.size() > 1 )
130 if ( args
[1] == "RANGE" )
135 if ( args
.size() == 3 )
137 stop
= atoi(args
[2].c_str());
139 if ( args
.size() == 4 )
141 start
= atoi(args
[2].c_str());
142 stop
= atoi(args
[3].c_str());
144 if ( args
.size() == 5 )
146 start
= atoi(args
[2].c_str());
147 stop
= atoi(args
[3].c_str());
148 step
= atoi(args
[4].c_str());
162 (start
> stop
&& step
> 0) ||
163 (start
< stop
&& step
< 0) ||
168 str
<< "called with incorrect range specification: start ";
169 str
<< start
<< ", stop " << stop
<< ", step " << step
;
170 this->SetError(str
.str().c_str());
173 std::vector
<std::string
> range
;
175 range
.push_back(args
[0]);
177 for ( cc
= start
; ; cc
+= step
)
179 if ( (step
> 0 && cc
> stop
) || (step
< 0 && cc
< stop
) )
183 sprintf(buffer
, "%d", cc
);
184 range
.push_back(buffer
);
201 this->Makefile
->AddFunctionBlocker(f
);
206 //----------------------------------------------------------------------------
207 bool cmForEachCommand::HandleInMode(std::vector
<std::string
> const& args
)
209 cmsys::auto_ptr
<cmForEachFunctionBlocker
> f(new cmForEachFunctionBlocker());
210 f
->Args
.push_back(args
[0]);
212 enum Doing
{ DoingNone
, DoingLists
, DoingItems
};
213 Doing doing
= DoingNone
;
214 for(unsigned int i
=2; i
< args
.size(); ++i
)
216 if(doing
== DoingItems
)
218 f
->Args
.push_back(args
[i
]);
220 else if(args
[i
] == "LISTS")
224 else if(args
[i
] == "ITEMS")
228 else if(doing
== DoingLists
)
230 const char* value
= this->Makefile
->GetDefinition(args
[i
].c_str());
233 cmSystemTools::ExpandListArgument(value
, f
->Args
, true);
239 e
<< "Unknown argument:\n" << " " << args
[i
] << "\n";
240 this->Makefile
->IssueMessage(cmake::FATAL_ERROR
, e
.str());
245 this->Makefile
->AddFunctionBlocker(f
.release()); // TODO: pass auto_ptr