cmWhileCommand.cxx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmWhileCommand.h"
  4. #include "cm_memory.hxx"
  5. #include "cmConditionEvaluator.h"
  6. #include "cmExecutionStatus.h"
  7. #include "cmExpandedCommandArgument.h"
  8. #include "cmMakefile.h"
  9. #include "cmMessageType.h"
  10. #include "cmSystemTools.h"
  11. #include <utility>
  12. cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf)
  13. : Makefile(mf)
  14. , Depth(0)
  15. {
  16. this->Makefile->PushLoopBlock();
  17. }
  18. cmWhileFunctionBlocker::~cmWhileFunctionBlocker()
  19. {
  20. this->Makefile->PopLoopBlock();
  21. }
  22. bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
  23. cmMakefile& mf,
  24. cmExecutionStatus& inStatus)
  25. {
  26. // at end of for each execute recorded commands
  27. if (lff.Name.Lower == "while") {
  28. // record the number of while commands past this one
  29. this->Depth++;
  30. } else if (lff.Name.Lower == "endwhile") {
  31. // if this is the endwhile for this while loop then execute
  32. if (!this->Depth) {
  33. // Remove the function blocker for this scope or bail.
  34. std::unique_ptr<cmFunctionBlocker> fb(
  35. mf.RemoveFunctionBlocker(this, lff));
  36. if (!fb) {
  37. return false;
  38. }
  39. std::string errorString;
  40. std::vector<cmExpandedCommandArgument> expandedArguments;
  41. mf.ExpandArguments(this->Args, expandedArguments);
  42. MessageType messageType;
  43. cmListFileContext execContext = this->GetStartingContext();
  44. cmCommandContext commandContext;
  45. commandContext.Line = execContext.Line;
  46. commandContext.Name = execContext.Name;
  47. cmConditionEvaluator conditionEvaluator(mf, this->GetStartingContext(),
  48. mf.GetBacktrace(commandContext));
  49. bool isTrue =
  50. conditionEvaluator.IsTrue(expandedArguments, errorString, messageType);
  51. while (isTrue) {
  52. if (!errorString.empty()) {
  53. std::string err = "had incorrect arguments: ";
  54. for (cmListFileArgument const& arg : this->Args) {
  55. err += (arg.Delim ? "\"" : "");
  56. err += arg.Value;
  57. err += (arg.Delim ? "\"" : "");
  58. err += " ";
  59. }
  60. err += "(";
  61. err += errorString;
  62. err += ").";
  63. mf.IssueMessage(messageType, err);
  64. if (messageType == MessageType::FATAL_ERROR) {
  65. cmSystemTools::SetFatalErrorOccured();
  66. return true;
  67. }
  68. }
  69. // Invoke all the functions that were collected in the block.
  70. for (cmListFileFunction const& fn : this->Functions) {
  71. cmExecutionStatus status(mf);
  72. mf.ExecuteCommand(fn, status);
  73. if (status.GetReturnInvoked()) {
  74. inStatus.SetReturnInvoked();
  75. return true;
  76. }
  77. if (status.GetBreakInvoked()) {
  78. return true;
  79. }
  80. if (status.GetContinueInvoked()) {
  81. break;
  82. }
  83. if (cmSystemTools::GetFatalErrorOccured()) {
  84. return true;
  85. }
  86. }
  87. expandedArguments.clear();
  88. mf.ExpandArguments(this->Args, expandedArguments);
  89. isTrue = conditionEvaluator.IsTrue(expandedArguments, errorString,
  90. messageType);
  91. }
  92. return true;
  93. }
  94. // decrement for each nested while that ends
  95. this->Depth--;
  96. }
  97. // record the command
  98. this->Functions.push_back(lff);
  99. // always return true
  100. return true;
  101. }
  102. bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
  103. cmMakefile&)
  104. {
  105. if (lff.Name.Lower == "endwhile") {
  106. // if the endwhile has arguments, then make sure
  107. // they match the arguments of the matching while
  108. if (lff.Arguments.empty() || lff.Arguments == this->Args) {
  109. return true;
  110. }
  111. }
  112. return false;
  113. }
  114. bool cmWhileCommand::InvokeInitialPass(
  115. const std::vector<cmListFileArgument>& args, cmExecutionStatus&)
  116. {
  117. if (args.empty()) {
  118. this->SetError("called with incorrect number of arguments");
  119. return false;
  120. }
  121. // create a function blocker
  122. {
  123. auto fb = cm::make_unique<cmWhileFunctionBlocker>(this->Makefile);
  124. fb->Args = args;
  125. this->Makefile->AddFunctionBlocker(std::move(fb));
  126. }
  127. return true;
  128. }