summaryrefslogtreecommitdiff
path: root/Source/cmForEachCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmForEachCommand.cxx')
-rw-r--r--Source/cmForEachCommand.cxx203
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;
}
+}