cmIfCommand.cxx 6.76 KB
Newer Older
1 2 3
/*============================================================================
  CMake - Cross Platform Makefile Generator
  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4

5 6
  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.
7

8 9 10 11
  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
12
#include "cmIfCommand.h"
Alexander Neundorf's avatar
 
Alexander Neundorf committed
13 14
#include "cmStringCommand.h"

15 16
#include "cmConditionEvaluator.h"

17
#include <stdlib.h> // required for atof
18
#include <list>
19 20
#include <cmsys/RegularExpression.hxx>

21 22

static std::string cmIfCommandError(
23
  cmMakefile* mf, std::vector<cmExpandedCommandArgument> const& args)
24 25 26
{
  cmLocalGenerator* lg = mf->GetLocalGenerator();
  std::string err = "given arguments:\n ";
27
  for(std::vector<cmExpandedCommandArgument>::const_iterator i = args.begin();
28 29 30
      i != args.end(); ++i)
    {
    err += " ";
31
    err += lg->EscapeForCMake(i->GetValue());
32 33 34 35 36
    }
  err += "\n";
  return err;
}

37
//=========================================================================
38
bool cmIfFunctionBlocker::
39
IsFunctionBlocked(const cmListFileFunction& lff,
40
                  cmMakefile &mf,
41
                  cmExecutionStatus &inStatus)
42
{
43 44
  // we start by recording all the functions
  if (!cmSystemTools::Strucmp(lff.Name.c_str(),"if"))
45
    {
46
    this->ScopeDepth++;
47
    }
48
  if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
49
    {
50 51
    this->ScopeDepth--;
    // if this is the endif for this if statement, then start executing
52
    if (!this->ScopeDepth)
Ken Martin's avatar
Ken Martin committed
53
      {
54
      // Remove the function blocker for this scope or bail.
55 56
      cmsys::auto_ptr<cmFunctionBlocker>
        fb(mf.RemoveFunctionBlocker(this, lff));
57 58
      if(!fb.get()) { return false; }

59 60 61 62
      // 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)
Ken Martin's avatar
Ken Martin committed
63
        {
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
        // 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;
79 80 81 82 83 84 85

          // if trace is enabled, print a (trivially) evaluated "else"
          // statement
          if(!this->IsBlocking && mf.GetCMakeInstance()->GetTrace())
            {
            mf.PrintCommandTrace(this->Functions[c]);
            }
86 87 88
          }
        else if (scopeDepth == 0 && !cmSystemTools::Strucmp
                 (this->Functions[c].Name.c_str(),"elseif"))
Ken Martin's avatar
Ken Martin committed
89
          {
90
          if (this->HasRun)
Ken Martin's avatar
Ken Martin committed
91
            {
92
            this->IsBlocking = true;
Ken Martin's avatar
Ken Martin committed
93
            }
94 95
          else
            {
96 97 98 99
            // Place this call on the call stack.
            cmMakefileCall stack_manager(&mf, this->Functions[c], status);
            static_cast<void>(stack_manager);

100 101 102 103 104 105
            // if trace is enabled, print the evaluated "elseif" statement
            if(mf.GetCMakeInstance()->GetTrace())
              {
              mf.PrintCommandTrace(this->Functions[c]);
              }

106
            std::string errorString;
107

108
            std::vector<cmExpandedCommandArgument> expandedArguments;
109
            mf.ExpandArguments(this->Functions[c].Arguments,
110
                               expandedArguments);
111

Ken Martin's avatar
Ken Martin committed
112
            cmake::MessageType messType;
113 114 115 116 117

            cmConditionEvaluator conditionEvaluator(mf);

            bool isTrue = conditionEvaluator.IsTrue(
              expandedArguments, errorString, messType);
118

119
            if (errorString.size())
120
              {
121
              std::string err = cmIfCommandError(&mf, expandedArguments);
122
              err += errorString;
Ken Martin's avatar
Ken Martin committed
123 124
              mf.IssueMessage(messType, err);
              if (messType == cmake::FATAL_ERROR)
125 126 127 128
                {
                cmSystemTools::SetFatalErrorOccured();
                return true;
                }
129
              }
130

131 132 133 134 135 136 137
            if (isTrue)
              {
              this->IsBlocking = false;
              this->HasRun = true;
              }
            }
          }
138

139 140
        // should we execute?
        else if (!this->IsBlocking)
Ken Martin's avatar
Ken Martin committed
141
          {
142 143 144 145 146 147 148 149 150 151 152 153
          status.Clear();
          mf.ExecuteCommand(this->Functions[c],status);
          if (status.GetReturnInvoked())
            {
            inStatus.SetReturnInvoked(true);
            return true;
            }
          if (status.GetBreakInvoked())
            {
            inStatus.SetBreakInvoked(true);
            return true;
            }
154 155 156 157 158
          if (status.GetContinueInvoked())
            {
            inStatus.SetContinueInvoked(true);
            return true;
            }
Ken Martin's avatar
Ken Martin committed
159
          }
Ken Martin's avatar
Ken Martin committed
160
        }
Ken Martin's avatar
Ken Martin committed
161 162 163
      return true;
      }
    }
164

165 166
  // record the command
  this->Functions.push_back(lff);
167

168 169
  // always return true
  return true;
170 171
}

172
//=========================================================================
173
bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
Bill Hoffman's avatar
Bill Hoffman committed
174
                                       cmMakefile&)
175
{
176
  if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endif"))
177
    {
178 179 180 181
    // if the endif has arguments, then make sure
    // they match the arguments of the matching if
    if (lff.Arguments.size() == 0 ||
        lff.Arguments == this->Args)
182 183 184 185
      {
      return true;
      }
    }
Ken Martin's avatar
Ken Martin committed
186

187
  return false;
188 189
}

190
//=========================================================================
Ken Martin's avatar
Ken Martin committed
191
bool cmIfCommand
192
::InvokeInitialPass(const std::vector<cmListFileArgument>& args,
193
                    cmExecutionStatus &)
194
{
195
  std::string errorString;
196

197
  std::vector<cmExpandedCommandArgument> expandedArguments;
Ken Martin's avatar
Ken Martin committed
198
  this->Makefile->ExpandArguments(args, expandedArguments);
199 200

  cmake::MessageType status;
201 202 203 204 205

  cmConditionEvaluator conditionEvaluator(*(this->Makefile));

  bool isTrue = conditionEvaluator.IsTrue(
    expandedArguments, errorString, status);
206

207
  if (errorString.size())
208
    {
209
    std::string err = cmIfCommandError(this->Makefile, expandedArguments);
210
    err += errorString;
211 212
    if (status == cmake::FATAL_ERROR)
      {
Stephen Kelly's avatar
Stephen Kelly committed
213
      this->SetError(err);
214 215 216 217 218 219 220
      cmSystemTools::SetFatalErrorOccured();
      return false;
      }
    else
      {
      this->Makefile->IssueMessage(status, err);
      }
221
    }
222

223 224
  cmIfFunctionBlocker *f = new cmIfFunctionBlocker();
  // if is isn't true block the commands
225
  f->ScopeDepth = 1;
Ken Martin's avatar
Ken Martin committed
226
  f->IsBlocking = !isTrue;
Ken Martin's avatar
Ken Martin committed
227 228 229 230
  if (isTrue)
    {
    f->HasRun = true;
    }
Ken Martin's avatar
Ken Martin committed
231 232
  f->Args = args;
  this->Makefile->AddFunctionBlocker(f);
233

234 235
  return true;
}