Imported Upstream version 2.8.9
[platform/upstream/cmake.git] / Source / cmForEachCommand.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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"
13
14 #include <cmsys/auto_ptr.hxx>
15
16 bool cmForEachFunctionBlocker::
17 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
18                   cmExecutionStatus &inStatus)
19 {
20   if (!cmSystemTools::Strucmp(lff.Name.c_str(),"foreach"))
21     {
22     // record the number of nested foreach commands
23     this->Depth++;
24     }
25   else if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
26     {
27     // if this is the endofreach for this statement
28     if (!this->Depth) 
29       {
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; }
34
35       // at end of for each execute recorded commands
36       // store the old value
37       std::string oldDef;
38       if (mf.GetDefinition(this->Args[0].c_str()))
39         {
40         oldDef = mf.GetDefinition(this->Args[0].c_str());
41         }
42       std::vector<std::string>::const_iterator j = this->Args.begin();
43       ++j;
44
45       std::string tmps;
46       cmListFileArgument arg;
47       for( ; j != this->Args.end(); ++j)
48         {   
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)
54           {
55           status.Clear();
56           mf.ExecuteCommand(this->Functions[c],status);
57           if (status.GetReturnInvoked())
58             {
59             inStatus.SetReturnInvoked(true);
60             // restore the variable to its prior value
61             mf.AddDefinition(this->Args[0].c_str(),oldDef.c_str());
62             return true;
63             }
64           if (status.GetBreakInvoked())
65             {
66             // restore the variable to its prior value
67             mf.AddDefinition(this->Args[0].c_str(),oldDef.c_str());
68             return true;
69             }
70           if(cmSystemTools::GetFatalErrorOccured() )
71             {
72             return true;
73             }
74           }
75         }
76       // restore the variable to its prior value
77       mf.AddDefinition(this->Args[0].c_str(),oldDef.c_str());
78       return true;
79       }
80     else
81       {
82       // close out a nested foreach
83       this->Depth--;
84       }
85     }
86   
87   // record the command
88   this->Functions.push_back(lff);
89   
90   // always return true
91   return true;
92 }
93
94 bool cmForEachFunctionBlocker::
95 ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf)
96 {
97   if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
98     {
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])))
105       {
106       return true;
107       }
108     }
109   return false;
110 }
111
112 bool cmForEachCommand
113 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
114 {
115   if(args.size() < 1)
116     {
117     this->SetError("called with incorrect number of arguments");
118     return false;
119     }
120   if(args.size() > 1 && args[1] == "IN")
121     {
122     return this->HandleInMode(args);
123     }
124   
125   // create a function blocker
126   cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
127   if ( args.size() > 1 )
128     {
129     if ( args[1] == "RANGE" )
130       {
131       int start = 0;
132       int stop = 0;
133       int step = 0;
134       if ( args.size() == 3 )
135         {
136         stop = atoi(args[2].c_str());
137         }
138       if ( args.size() == 4 )
139         {
140         start = atoi(args[2].c_str());
141         stop = atoi(args[3].c_str());
142         }
143       if ( args.size() == 5 )
144         {
145         start = atoi(args[2].c_str());
146         stop = atoi(args[3].c_str());
147         step = atoi(args[4].c_str());
148         }
149       if ( step == 0 )
150         {
151         if ( start > stop )
152           {
153           step = -1;
154           }
155         else
156           {
157           step = 1;
158           }
159         }
160       if ( 
161         (start > stop && step > 0) ||
162         (start < stop && step < 0) ||
163         step == 0
164         )
165         {
166         cmOStringStream str;
167         str << "called with incorrect range specification: start ";
168         str << start << ", stop " << stop << ", step " << step;
169         this->SetError(str.str().c_str());
170         return false;
171         }
172       std::vector<std::string> range;
173       char buffer[100];
174       range.push_back(args[0]);
175       int cc;
176       for ( cc = start; ; cc += step )
177         {
178         if ( (step > 0 && cc > stop) || (step < 0 && cc < stop) )
179           {
180           break;
181           }
182         sprintf(buffer, "%d", cc);
183         range.push_back(buffer);
184         if ( cc == stop )
185           {
186           break;
187           }
188         }
189       f->Args = range;
190       }
191     else
192       {
193       f->Args = args;
194       }
195     }
196   else
197     {
198     f->Args = args;
199     }
200   this->Makefile->AddFunctionBlocker(f);
201   
202   return true;
203 }
204
205 //----------------------------------------------------------------------------
206 bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args)
207 {
208   cmsys::auto_ptr<cmForEachFunctionBlocker> f(new cmForEachFunctionBlocker());
209   f->Args.push_back(args[0]);
210
211   enum Doing { DoingNone, DoingLists, DoingItems };
212   Doing doing = DoingNone;
213   for(unsigned int i=2; i < args.size(); ++i)
214     {
215     if(doing == DoingItems)
216       {
217       f->Args.push_back(args[i]);
218       }
219     else if(args[i] == "LISTS")
220       {
221       doing = DoingLists;
222       }
223     else if(args[i] == "ITEMS")
224       {
225       doing = DoingItems;
226       }
227     else if(doing == DoingLists)
228       {
229       const char* value = this->Makefile->GetDefinition(args[i].c_str());
230       if(value && *value)
231         {
232         cmSystemTools::ExpandListArgument(value, f->Args, true);
233         }
234       }
235     else
236       {
237       cmOStringStream e;
238       e << "Unknown argument:\n" << "  " << args[i] << "\n";
239       this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
240       return true;
241       }
242     }
243
244   this->Makefile->AddFunctionBlocker(f.release()); // TODO: pass auto_ptr
245   return true;
246 }