cmForEachCommand.cxx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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(cmSystemTools::GetFatalErrorOccured() )
  66. {
  67. return true;
  68. }
  69. }
  70. }
  71. // restore the variable to its prior value
  72. mf.AddDefinition(this->Args[0],oldDef.c_str());
  73. return true;
  74. }
  75. else
  76. {
  77. // close out a nested foreach
  78. this->Depth--;
  79. }
  80. }
  81. // record the command
  82. this->Functions.push_back(lff);
  83. // always return true
  84. return true;
  85. }
  86. bool cmForEachFunctionBlocker::
  87. ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf)
  88. {
  89. if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
  90. {
  91. std::vector<std::string> expandedArguments;
  92. mf.ExpandArguments(lff.Arguments, expandedArguments);
  93. // if the endforeach has arguments then make sure
  94. // they match the begin foreach arguments
  95. if ((expandedArguments.empty() ||
  96. (expandedArguments[0] == this->Args[0])))
  97. {
  98. return true;
  99. }
  100. }
  101. return false;
  102. }
  103. bool cmForEachCommand
  104. ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  105. {
  106. if(args.size() < 1)
  107. {
  108. this->SetError("called with incorrect number of arguments");
  109. return false;
  110. }
  111. if(args.size() > 1 && args[1] == "IN")
  112. {
  113. return this->HandleInMode(args);
  114. }
  115. // create a function blocker
  116. cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
  117. if ( args.size() > 1 )
  118. {
  119. if ( args[1] == "RANGE" )
  120. {
  121. int start = 0;
  122. int stop = 0;
  123. int step = 0;
  124. if ( args.size() == 3 )
  125. {
  126. stop = atoi(args[2].c_str());
  127. }
  128. if ( args.size() == 4 )
  129. {
  130. start = atoi(args[2].c_str());
  131. stop = atoi(args[3].c_str());
  132. }
  133. if ( args.size() == 5 )
  134. {
  135. start = atoi(args[2].c_str());
  136. stop = atoi(args[3].c_str());
  137. step = atoi(args[4].c_str());
  138. }
  139. if ( step == 0 )
  140. {
  141. if ( start > stop )
  142. {
  143. step = -1;
  144. }
  145. else
  146. {
  147. step = 1;
  148. }
  149. }
  150. if (
  151. (start > stop && step > 0) ||
  152. (start < stop && step < 0) ||
  153. step == 0
  154. )
  155. {
  156. cmOStringStream str;
  157. str << "called with incorrect range specification: start ";
  158. str << start << ", stop " << stop << ", step " << step;
  159. this->SetError(str.str());
  160. return false;
  161. }
  162. std::vector<std::string> range;
  163. char buffer[100];
  164. range.push_back(args[0]);
  165. int cc;
  166. for ( cc = start; ; cc += step )
  167. {
  168. if ( (step > 0 && cc > stop) || (step < 0 && cc < stop) )
  169. {
  170. break;
  171. }
  172. sprintf(buffer, "%d", cc);
  173. range.push_back(buffer);
  174. if ( cc == stop )
  175. {
  176. break;
  177. }
  178. }
  179. f->Args = range;
  180. }
  181. else
  182. {
  183. f->Args = args;
  184. }
  185. }
  186. else
  187. {
  188. f->Args = args;
  189. }
  190. this->Makefile->AddFunctionBlocker(f);
  191. this->Makefile->PushLoopBlock();
  192. return true;
  193. }
  194. //----------------------------------------------------------------------------
  195. bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args)
  196. {
  197. cmsys::auto_ptr<cmForEachFunctionBlocker> f(new cmForEachFunctionBlocker());
  198. f->Args.push_back(args[0]);
  199. enum Doing { DoingNone, DoingLists, DoingItems };
  200. Doing doing = DoingNone;
  201. for(unsigned int i=2; i < args.size(); ++i)
  202. {
  203. if(doing == DoingItems)
  204. {
  205. f->Args.push_back(args[i]);
  206. }
  207. else if(args[i] == "LISTS")
  208. {
  209. doing = DoingLists;
  210. }
  211. else if(args[i] == "ITEMS")
  212. {
  213. doing = DoingItems;
  214. }
  215. else if(doing == DoingLists)
  216. {
  217. const char* value = this->Makefile->GetDefinition(args[i]);
  218. if(value && *value)
  219. {
  220. cmSystemTools::ExpandListArgument(value, f->Args, true);
  221. }
  222. }
  223. else
  224. {
  225. cmOStringStream e;
  226. e << "Unknown argument:\n" << " " << args[i] << "\n";
  227. this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
  228. return true;
  229. }
  230. }
  231. this->Makefile->AddFunctionBlocker(f.release()); // TODO: pass auto_ptr
  232. this->Makefile->PushLoopBlock();
  233. return true;
  234. }