diff options
Diffstat (limited to 'Source/cmForEachCommand.cxx')
-rw-r--r-- | Source/cmForEachCommand.cxx | 203 |
1 files changed, 100 insertions, 103 deletions
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index 08003eb71..44392baa7 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -2,21 +2,50 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmForEachCommand.h" -#include <memory> // IWYU pragma: keep -#include <sstream> -#include <stdio.h> -#include <stdlib.h> +#include <cstdio> +#include <cstdlib> +#include <utility> + +#include <cm/memory> +#include <cm/string_view> + +#include "cm_static_string_view.hxx" -#include "cmAlgorithms.h" #include "cmExecutionStatus.h" +#include "cmFunctionBlocker.h" +#include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" #include "cmRange.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" +namespace { +bool HandleInMode(std::vector<std::string> const& args, cmMakefile& makefile); + +class cmForEachFunctionBlocker : public cmFunctionBlocker +{ +public: + cmForEachFunctionBlocker(cmMakefile* mf); + ~cmForEachFunctionBlocker() override; + + cm::string_view StartCommandName() const override { return "foreach"_s; } + cm::string_view EndCommandName() const override { return "endforeach"_s; } + + bool ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const override; + + bool Replay(std::vector<cmListFileFunction> functions, + cmExecutionStatus& inStatus) override; + + std::vector<std::string> Args; + +private: + cmMakefile* Makefile; +}; + cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf) : Makefile(mf) - , Depth(0) { this->Makefile->PushLoopBlock(); } @@ -26,102 +55,71 @@ cmForEachFunctionBlocker::~cmForEachFunctionBlocker() this->Makefile->PopLoopBlock(); } -bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, - cmMakefile& mf, - cmExecutionStatus& inStatus) +bool cmForEachFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, + cmMakefile& mf) const { - if (lff.Name.Lower == "foreach") { - // record the number of nested foreach commands - this->Depth++; - } else if (lff.Name.Lower == "endforeach") { - // if this is the endofreach for this statement - if (!this->Depth) { - // Remove the function blocker for this scope or bail. - std::unique_ptr<cmFunctionBlocker> fb( - mf.RemoveFunctionBlocker(this, lff)); - if (!fb) { - return false; - } + std::vector<std::string> expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments); + return expandedArguments.empty() || expandedArguments[0] == this->Args[0]; +} - // at end of for each execute recorded commands - // store the old value - std::string oldDef; - if (mf.GetDefinition(this->Args[0])) { - oldDef = mf.GetDefinition(this->Args[0]); - } +bool cmForEachFunctionBlocker::Replay( + std::vector<cmListFileFunction> functions, cmExecutionStatus& inStatus) +{ + cmMakefile& mf = inStatus.GetMakefile(); + // at end of for each execute recorded commands + // store the old value + std::string oldDef; + if (mf.GetDefinition(this->Args[0])) { + oldDef = mf.GetDefinition(this->Args[0]); + } - for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { - // set the variable to the loop value - mf.AddDefinition(this->Args[0], arg.c_str()); - // Invoke all the functions that were collected in the block. - cmExecutionStatus status; - for (cmListFileFunction const& func : this->Functions) { - status.Clear(); - mf.ExecuteCommand(func, status); - if (status.GetReturnInvoked()) { - inStatus.SetReturnInvoked(); - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef.c_str()); - return true; - } - if (status.GetBreakInvoked()) { - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef.c_str()); - return true; - } - if (status.GetContinueInvoked()) { - break; - } - if (cmSystemTools::GetFatalErrorOccured()) { - return true; - } - } + for (std::string const& arg : cmMakeRange(this->Args).advance(1)) { + // set the variable to the loop value + mf.AddDefinition(this->Args[0], arg); + // Invoke all the functions that were collected in the block. + for (cmListFileFunction const& func : functions) { + cmExecutionStatus status(mf); + mf.ExecuteCommand(func, status); + if (status.GetReturnInvoked()) { + inStatus.SetReturnInvoked(); + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetBreakInvoked()) { + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); + return true; + } + if (status.GetContinueInvoked()) { + break; + } + if (cmSystemTools::GetFatalErrorOccured()) { + return true; } - - // restore the variable to its prior value - mf.AddDefinition(this->Args[0], oldDef.c_str()); - return true; } - // close out a nested foreach - this->Depth--; } - // record the command - this->Functions.push_back(lff); - - // always return true + // restore the variable to its prior value + mf.AddDefinition(this->Args[0], oldDef); return true; } - -bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, - cmMakefile& mf) -{ - if (lff.Name.Lower == "endforeach") { - std::vector<std::string> expandedArguments; - mf.ExpandArguments(lff.Arguments, expandedArguments); - // if the endforeach has arguments then make sure - // they match the begin foreach arguments - if ((expandedArguments.empty() || - (expandedArguments[0] == this->Args[0]))) { - return true; - } - } - return false; } -bool cmForEachCommand::InitialPass(std::vector<std::string> const& args, - cmExecutionStatus&) +bool cmForEachCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) { if (args.empty()) { - this->SetError("called with incorrect number of arguments"); + status.SetError("called with incorrect number of arguments"); return false; } if (args.size() > 1 && args[1] == "IN") { - return this->HandleInMode(args); + return HandleInMode(args, status.GetMakefile()); } // create a function blocker - auto f = cm::make_unique<cmForEachFunctionBlocker>(this->Makefile); + auto fb = cm::make_unique<cmForEachFunctionBlocker>(&status.GetMakefile()); if (args.size() > 1) { if (args[1] == "RANGE") { int start = 0; @@ -148,10 +146,9 @@ bool cmForEachCommand::InitialPass(std::vector<std::string> const& args, } if ((start > stop && step > 0) || (start < stop && step < 0) || step == 0) { - std::ostringstream str; - str << "called with incorrect range specification: start "; - str << start << ", stop " << stop << ", step " << step; - this->SetError(str.str()); + status.SetError( + cmStrCat("called with incorrect range specification: start ", start, + ", stop ", stop, ", step ", step)); return false; } std::vector<std::string> range; @@ -168,23 +165,23 @@ bool cmForEachCommand::InitialPass(std::vector<std::string> const& args, break; } } - f->Args = range; + fb->Args = range; } else { - f->Args = args; + fb->Args = args; } } else { - f->Args = args; + fb->Args = args; } - this->Makefile->AddFunctionBlocker(f.release()); + status.GetMakefile().AddFunctionBlocker(std::move(fb)); return true; } -bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args) +namespace { +bool HandleInMode(std::vector<std::string> const& args, cmMakefile& makefile) { - std::unique_ptr<cmForEachFunctionBlocker> f( - new cmForEachFunctionBlocker(this->Makefile)); - f->Args.push_back(args[0]); + auto fb = cm::make_unique<cmForEachFunctionBlocker>(&makefile); + fb->Args.push_back(args[0]); enum Doing { @@ -195,26 +192,26 @@ bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args) Doing doing = DoingNone; for (unsigned int i = 2; i < args.size(); ++i) { if (doing == DoingItems) { - f->Args.push_back(args[i]); + fb->Args.push_back(args[i]); } else if (args[i] == "LISTS") { doing = DoingLists; } else if (args[i] == "ITEMS") { doing = DoingItems; } else if (doing == DoingLists) { - const char* value = this->Makefile->GetDefinition(args[i]); + const char* value = makefile.GetDefinition(args[i]); if (value && *value) { - cmSystemTools::ExpandListArgument(value, f->Args, true); + cmExpandList(value, fb->Args, true); } } else { - std::ostringstream e; - e << "Unknown argument:\n" - << " " << args[i] << "\n"; - this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); + makefile.IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Unknown argument:\n", " ", args[i], "\n")); return true; } } - this->Makefile->AddFunctionBlocker(f.release()); // TODO: pass unique_ptr + makefile.AddFunctionBlocker(std::move(fb)); return true; } +} |