summaryrefslogtreecommitdiffstats
path: root/Source/cmIfCommand.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmIfCommand.cxx')
-rw-r--r--Source/cmIfCommand.cxx199
1 files changed, 199 insertions, 0 deletions
diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx
new file mode 100644
index 0000000..a8fa4f9
--- /dev/null
+++ b/Source/cmIfCommand.cxx
@@ -0,0 +1,199 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmIfCommand.h"
+
+#include "cmConditionEvaluator.h"
+#include "cmExecutionStatus.h"
+#include "cmExpandedCommandArgument.h"
+#include "cmMakefile.h"
+#include "cmOutputConverter.h"
+#include "cmSystemTools.h"
+#include "cm_auto_ptr.hxx"
+#include "cmake.h"
+
+static std::string cmIfCommandError(
+ std::vector<cmExpandedCommandArgument> const& args)
+{
+ std::string err = "given arguments:\n ";
+ for (std::vector<cmExpandedCommandArgument>::const_iterator i = args.begin();
+ i != args.end(); ++i) {
+ err += " ";
+ err += cmOutputConverter::EscapeForCMake(i->GetValue());
+ }
+ err += "\n";
+ return err;
+}
+
+//=========================================================================
+bool cmIfFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff,
+ cmMakefile& mf,
+ cmExecutionStatus& inStatus)
+{
+ // we start by recording all the functions
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "if")) {
+ this->ScopeDepth++;
+ } else if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endif")) {
+ this->ScopeDepth--;
+ // if this is the endif for this if statement, then start executing
+ if (!this->ScopeDepth) {
+ // Remove the function blocker for this scope or bail.
+ CM_AUTO_PTR<cmFunctionBlocker> fb(mf.RemoveFunctionBlocker(this, lff));
+ if (!fb.get()) {
+ return false;
+ }
+
+ // execute the functions for the true parts of the if statement
+ cmExecutionStatus status;
+ int scopeDepth = 0;
+ for (unsigned int c = 0; c < this->Functions.size(); ++c) {
+ // keep track of scope depth
+ if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(), "if")) {
+ scopeDepth++;
+ }
+ if (!cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),
+ "endif")) {
+ scopeDepth--;
+ }
+ // watch for our state change
+ if (scopeDepth == 0 &&
+ !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(), "else")) {
+ this->IsBlocking = this->HasRun;
+ this->HasRun = true;
+
+ // if trace is enabled, print a (trivially) evaluated "else"
+ // statement
+ if (!this->IsBlocking && mf.GetCMakeInstance()->GetTrace()) {
+ mf.PrintCommandTrace(this->Functions[c]);
+ }
+ } else if (scopeDepth == 0 &&
+ !cmSystemTools::Strucmp(this->Functions[c].Name.c_str(),
+ "elseif")) {
+ if (this->HasRun) {
+ this->IsBlocking = true;
+ } else {
+ // if trace is enabled, print the evaluated "elseif" statement
+ if (mf.GetCMakeInstance()->GetTrace()) {
+ mf.PrintCommandTrace(this->Functions[c]);
+ }
+
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ mf.ExpandArguments(this->Functions[c].Arguments,
+ expandedArguments);
+
+ cmake::MessageType messType;
+
+ cmListFileContext conditionContext =
+ cmListFileContext::FromCommandContext(
+ this->Functions[c], this->GetStartingContext().FilePath);
+
+ cmConditionEvaluator conditionEvaluator(
+ mf, conditionContext, mf.GetBacktrace(this->Functions[c]));
+
+ bool isTrue = conditionEvaluator.IsTrue(expandedArguments,
+ errorString, messType);
+
+ if (!errorString.empty()) {
+ std::string err = cmIfCommandError(expandedArguments);
+ err += errorString;
+ cmListFileBacktrace bt = mf.GetBacktrace(this->Functions[c]);
+ mf.GetCMakeInstance()->IssueMessage(messType, err, bt);
+ if (messType == cmake::FATAL_ERROR) {
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ }
+
+ if (isTrue) {
+ this->IsBlocking = false;
+ this->HasRun = true;
+ }
+ }
+ }
+
+ // should we execute?
+ else if (!this->IsBlocking) {
+ status.Clear();
+ mf.ExecuteCommand(this->Functions[c], status);
+ if (status.GetReturnInvoked()) {
+ inStatus.SetReturnInvoked(true);
+ return true;
+ }
+ if (status.GetBreakInvoked()) {
+ inStatus.SetBreakInvoked(true);
+ return true;
+ }
+ if (status.GetContinueInvoked()) {
+ inStatus.SetContinueInvoked(true);
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ // record the command
+ this->Functions.push_back(lff);
+
+ // always return true
+ return true;
+}
+
+//=========================================================================
+bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
+ cmMakefile&)
+{
+ if (!cmSystemTools::Strucmp(lff.Name.c_str(), "endif")) {
+ // if the endif has arguments, then make sure
+ // they match the arguments of the matching if
+ if (lff.Arguments.empty() || lff.Arguments == this->Args) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//=========================================================================
+bool cmIfCommand::InvokeInitialPass(
+ const std::vector<cmListFileArgument>& args, cmExecutionStatus&)
+{
+ std::string errorString;
+
+ std::vector<cmExpandedCommandArgument> expandedArguments;
+ this->Makefile->ExpandArguments(args, expandedArguments);
+
+ cmake::MessageType status;
+
+ cmConditionEvaluator conditionEvaluator(
+ *(this->Makefile), this->Makefile->GetExecutionContext(),
+ this->Makefile->GetBacktrace());
+
+ bool isTrue =
+ conditionEvaluator.IsTrue(expandedArguments, errorString, status);
+
+ if (!errorString.empty()) {
+ std::string err = "if " + cmIfCommandError(expandedArguments);
+ err += errorString;
+ if (status == cmake::FATAL_ERROR) {
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, err);
+ cmSystemTools::SetFatalErrorOccured();
+ return true;
+ }
+ this->Makefile->IssueMessage(status, err);
+ }
+
+ cmIfFunctionBlocker* f = new cmIfFunctionBlocker();
+ // if is isn't true block the commands
+ f->ScopeDepth = 1;
+ f->IsBlocking = !isTrue;
+ if (isTrue) {
+ f->HasRun = true;
+ }
+ f->Args = args;
+ this->Makefile->AddFunctionBlocker(f);
+
+ return true;
+}