cmForEachCommand.cxx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmForEachCommand.h"
  14. bool cmForEachFunctionBlocker::
  15. IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
  16. cmExecutionStatus &inStatus)
  17. {
  18. if (!cmSystemTools::Strucmp(lff.Name.c_str(),"foreach"))
  19. {
  20. // record the number of nested foreach commands
  21. this->Depth++;
  22. }
  23. else if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
  24. {
  25. // if this is the endofreach for this statement
  26. if (!this->Depth)
  27. {
  28. // Remove the function blocker for this scope or bail.
  29. cmsys::auto_ptr<cmFunctionBlocker> fb(mf.RemoveFunctionBlocker(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].c_str()))
  35. {
  36. oldDef = mf.GetDefinition(this->Args[0].c_str());
  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].c_str(),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].c_str(),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].c_str(),oldDef.c_str());
  63. return true;
  64. }
  65. }
  66. }
  67. // restore the variable to its prior value
  68. mf.AddDefinition(this->Args[0].c_str(),oldDef.c_str());
  69. return true;
  70. }
  71. else
  72. {
  73. // close out a nested foreach
  74. this->Depth--;
  75. }
  76. }
  77. // record the command
  78. this->Functions.push_back(lff);
  79. // always return true
  80. return true;
  81. }
  82. bool cmForEachFunctionBlocker::
  83. ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf)
  84. {
  85. if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endforeach"))
  86. {
  87. std::vector<std::string> expandedArguments;
  88. mf.ExpandArguments(lff.Arguments, expandedArguments);
  89. // if the endforeach has arguments then make sure
  90. // they match the begin foreach arguments
  91. if ((expandedArguments.empty() ||
  92. (expandedArguments[0] == this->Args[0])))
  93. {
  94. return true;
  95. }
  96. }
  97. return false;
  98. }
  99. bool cmForEachCommand
  100. ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  101. {
  102. if(args.size() < 1)
  103. {
  104. this->SetError("called with incorrect number of arguments");
  105. return false;
  106. }
  107. // create a function blocker
  108. cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
  109. if ( args.size() > 1 )
  110. {
  111. if ( args[1] == "RANGE" )
  112. {
  113. int start = 0;
  114. int stop = 0;
  115. int step = 0;
  116. if ( args.size() == 3 )
  117. {
  118. stop = atoi(args[2].c_str());
  119. }
  120. if ( args.size() == 4 )
  121. {
  122. start = atoi(args[2].c_str());
  123. stop = atoi(args[3].c_str());
  124. }
  125. if ( args.size() == 5 )
  126. {
  127. start = atoi(args[2].c_str());
  128. stop = atoi(args[3].c_str());
  129. step = atoi(args[4].c_str());
  130. }
  131. if ( step == 0 )
  132. {
  133. if ( start > stop )
  134. {
  135. step = -1;
  136. }
  137. else
  138. {
  139. step = 1;
  140. }
  141. }
  142. if (
  143. (start > stop && step > 0) ||
  144. (start < stop && step < 0) ||
  145. step == 0
  146. )
  147. {
  148. cmOStringStream str;
  149. str << "called with incorrect range specification: start ";
  150. str << start << ", stop " << stop << ", step " << step;
  151. this->SetError(str.str().c_str());
  152. return false;
  153. }
  154. std::vector<std::string> range;
  155. char buffer[100];
  156. range.push_back(args[0]);
  157. int cc;
  158. for ( cc = start; ; cc += step )
  159. {
  160. if ( (step > 0 && cc > stop) || (step < 0 && cc < stop) )
  161. {
  162. break;
  163. }
  164. sprintf(buffer, "%d", cc);
  165. range.push_back(buffer);
  166. if ( cc == stop )
  167. {
  168. break;
  169. }
  170. }
  171. f->Args = range;
  172. }
  173. else
  174. {
  175. f->Args = args;
  176. }
  177. }
  178. else
  179. {
  180. f->Args = args;
  181. }
  182. this->Makefile->AddFunctionBlocker(f);
  183. return true;
  184. }