cmForEachCommand.cxx 6.7 KB

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