123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmConditionEvaluator.h"
- #include "cmsys/RegularExpression.hxx"
- #include <algorithm>
- #include <sstream>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "cmAlgorithms.h"
- #include "cmMakefile.h"
- #include "cmState.h"
- #include "cmSystemTools.h"
- class cmCommand;
- class cmTest;
- static std::string const keyAND = "AND";
- static std::string const keyCOMMAND = "COMMAND";
- static std::string const keyDEFINED = "DEFINED";
- static std::string const keyEQUAL = "EQUAL";
- static std::string const keyEXISTS = "EXISTS";
- static std::string const keyGREATER = "GREATER";
- static std::string const keyGREATER_EQUAL = "GREATER_EQUAL";
- static std::string const keyIN_LIST = "IN_LIST";
- static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE";
- static std::string const keyIS_DIRECTORY = "IS_DIRECTORY";
- static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN";
- static std::string const keyIS_SYMLINK = "IS_SYMLINK";
- static std::string const keyLESS = "LESS";
- static std::string const keyLESS_EQUAL = "LESS_EQUAL";
- static std::string const keyMATCHES = "MATCHES";
- static std::string const keyNOT = "NOT";
- static std::string const keyOR = "OR";
- static std::string const keyParenL = "(";
- static std::string const keyParenR = ")";
- static std::string const keyPOLICY = "POLICY";
- static std::string const keySTREQUAL = "STREQUAL";
- static std::string const keySTRGREATER = "STRGREATER";
- static std::string const keySTRGREATER_EQUAL = "STRGREATER_EQUAL";
- static std::string const keySTRLESS = "STRLESS";
- static std::string const keySTRLESS_EQUAL = "STRLESS_EQUAL";
- static std::string const keyTARGET = "TARGET";
- static std::string const keyTEST = "TEST";
- static std::string const keyVERSION_EQUAL = "VERSION_EQUAL";
- static std::string const keyVERSION_GREATER = "VERSION_GREATER";
- static std::string const keyVERSION_GREATER_EQUAL = "VERSION_GREATER_EQUAL";
- static std::string const keyVERSION_LESS = "VERSION_LESS";
- static std::string const keyVERSION_LESS_EQUAL = "VERSION_LESS_EQUAL";
- cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
- const cmListFileContext& context,
- const cmListFileBacktrace& bt)
- : Makefile(makefile)
- , ExecutionContext(context)
- , Backtrace(bt)
- , Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012))
- , Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054))
- , Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057))
- , Policy64Status(makefile.GetPolicyStatus(cmPolicies::CMP0064))
- {
- }
- //=========================================================================
- // order of operations,
- // 1. ( ) -- parenthetical groups
- // 2. IS_DIRECTORY EXISTS COMMAND DEFINED etc predicates
- // 3. MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL etc binary ops
- // 4. NOT
- // 5. AND OR
- //
- // There is an issue on whether the arguments should be values of references,
- // for example IF (FOO AND BAR) should that compare the strings FOO and BAR
- // or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
- // EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
- // take numeric values or variable names. STRLESS and STRGREATER take
- // variable names but if the variable name is not found it will use the name
- // directly. AND OR take variables or the values 0 or 1.
- bool cmConditionEvaluator::IsTrue(
- const std::vector<cmExpandedCommandArgument>& args, std::string& errorString,
- cmake::MessageType& status)
- {
- errorString.clear();
- // handle empty invocation
- if (args.empty()) {
- return false;
- }
- // store the reduced args in this vector
- cmArgumentList newArgs;
- // copy to the list structure
- newArgs.insert(newArgs.end(), args.begin(), args.end());
- // now loop through the arguments and see if we can reduce any of them
- // we do this multiple times. Once for each level of precedence
- // parens
- if (!this->HandleLevel0(newArgs, errorString, status)) {
- return false;
- }
- // predicates
- if (!this->HandleLevel1(newArgs, errorString, status)) {
- return false;
- }
- // binary ops
- if (!this->HandleLevel2(newArgs, errorString, status)) {
- return false;
- }
- // NOT
- if (!this->HandleLevel3(newArgs, errorString, status)) {
- return false;
- }
- // AND OR
- if (!this->HandleLevel4(newArgs, errorString, status)) {
- return false;
- }
- // now at the end there should only be one argument left
- if (newArgs.size() != 1) {
- errorString = "Unknown arguments specified";
- status = cmake::FATAL_ERROR;
- return false;
- }
- return this->GetBooleanValueWithAutoDereference(*(newArgs.begin()),
- errorString, status, true);
- }
- //=========================================================================
- const char* cmConditionEvaluator::GetDefinitionIfUnquoted(
- cmExpandedCommandArgument const& argument) const
- {
- if ((this->Policy54Status != cmPolicies::WARN &&
- this->Policy54Status != cmPolicies::OLD) &&
- argument.WasQuoted()) {
- return nullptr;
- }
- const char* def = this->Makefile.GetDefinition(argument.GetValue());
- if (def && argument.WasQuoted() &&
- this->Policy54Status == cmPolicies::WARN) {
- if (!this->Makefile.HasCMP0054AlreadyBeenReported(
- this->ExecutionContext)) {
- std::ostringstream e;
- e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n";
- e << "Quoted variables like \"" << argument.GetValue()
- << "\" will no longer be dereferenced "
- "when the policy is set to NEW. "
- "Since the policy is not set the OLD behavior will be used.";
- this->Makefile.GetCMakeInstance()->IssueMessage(
- cmake::AUTHOR_WARNING, e.str(), this->Backtrace);
- }
- }
- return def;
- }
- //=========================================================================
- const char* cmConditionEvaluator::GetVariableOrString(
- const cmExpandedCommandArgument& argument) const
- {
- const char* def = this->GetDefinitionIfUnquoted(argument);
- if (!def) {
- def = argument.c_str();
- }
- return def;
- }
- //=========================================================================
- bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
- cmExpandedCommandArgument& argument) const
- {
- if ((this->Policy54Status != cmPolicies::WARN &&
- this->Policy54Status != cmPolicies::OLD) &&
- argument.WasQuoted()) {
- return false;
- }
- bool isKeyword = argument.GetValue() == keyword;
- if (isKeyword && argument.WasQuoted() &&
- this->Policy54Status == cmPolicies::WARN) {
- if (!this->Makefile.HasCMP0054AlreadyBeenReported(
- this->ExecutionContext)) {
- std::ostringstream e;
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n";
- e << "Quoted keywords like \"" << argument.GetValue()
- << "\" will no longer be interpreted as keywords "
- "when the policy is set to NEW. "
- "Since the policy is not set the OLD behavior will be used.";
- this->Makefile.GetCMakeInstance()->IssueMessage(
- cmake::AUTHOR_WARNING, e.str(), this->Backtrace);
- }
- }
- return isKeyword;
- }
- //=========================================================================
- bool cmConditionEvaluator::GetBooleanValue(
- cmExpandedCommandArgument& arg) const
- {
- // Check basic constants.
- if (arg == "0") {
- return false;
- }
- if (arg == "1") {
- return true;
- }
- // Check named constants.
- if (cmSystemTools::IsOn(arg.c_str())) {
- return true;
- }
- if (cmSystemTools::IsOff(arg.c_str())) {
- return false;
- }
- // Check for numbers.
- if (!arg.empty()) {
- char* end;
- double d = strtod(arg.c_str(), &end);
- if (*end == '\0') {
- // The whole string is a number. Use C conversion to bool.
- return static_cast<bool>(d);
- }
- }
- // Check definition.
- const char* def = this->GetDefinitionIfUnquoted(arg);
- return !cmSystemTools::IsOff(def);
- }
- //=========================================================================
- // Boolean value behavior from CMake 2.6.4 and below.
- bool cmConditionEvaluator::GetBooleanValueOld(
- cmExpandedCommandArgument const& arg, bool one) const
- {
- if (one) {
- // Old IsTrue behavior for single argument.
- if (arg == "0") {
- return false;
- }
- if (arg == "1") {
- return true;
- }
- const char* def = this->GetDefinitionIfUnquoted(arg);
- return !cmSystemTools::IsOff(def);
- }
- // Old GetVariableOrNumber behavior.
- const char* def = this->GetDefinitionIfUnquoted(arg);
- if (!def && atoi(arg.c_str())) {
- def = arg.c_str();
- }
- return !cmSystemTools::IsOff(def);
- }
- //=========================================================================
- // returns the resulting boolean value
- bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
- cmExpandedCommandArgument& newArg, std::string& errorString,
- cmake::MessageType& status, bool oneArg) const
- {
- // Use the policy if it is set.
- if (this->Policy12Status == cmPolicies::NEW) {
- return GetBooleanValue(newArg);
- }
- if (this->Policy12Status == cmPolicies::OLD) {
- return GetBooleanValueOld(newArg, oneArg);
- }
- // Check policy only if old and new results differ.
- bool newResult = this->GetBooleanValue(newArg);
- bool oldResult = this->GetBooleanValueOld(newArg, oneArg);
- if (newResult != oldResult) {
- switch (this->Policy12Status) {
- case cmPolicies::WARN:
- errorString = "An argument named \"" + newArg.GetValue() +
- "\" appears in a conditional statement. " +
- cmPolicies::GetPolicyWarning(cmPolicies::CMP0012);
- status = cmake::AUTHOR_WARNING;
- CM_FALLTHROUGH;
- case cmPolicies::OLD:
- return oldResult;
- case cmPolicies::REQUIRED_IF_USED:
- case cmPolicies::REQUIRED_ALWAYS: {
- errorString = "An argument named \"" + newArg.GetValue() +
- "\" appears in a conditional statement. " +
- cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0012);
- status = cmake::FATAL_ERROR;
- }
- case cmPolicies::NEW:
- break;
- }
- }
- return newResult;
- }
- //=========================================================================
- void cmConditionEvaluator::IncrementArguments(
- cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
- cmArgumentList::iterator& argP2) const
- {
- if (argP1 != newArgs.end()) {
- argP1++;
- argP2 = argP1;
- if (argP1 != newArgs.end()) {
- argP2++;
- }
- }
- }
- //=========================================================================
- // helper function to reduce code duplication
- void cmConditionEvaluator::HandlePredicate(
- bool value, int& reducible, cmArgumentList::iterator& arg,
- cmArgumentList& newArgs, cmArgumentList::iterator& argP1,
- cmArgumentList::iterator& argP2) const
- {
- if (value) {
- *arg = cmExpandedCommandArgument("1", true);
- } else {
- *arg = cmExpandedCommandArgument("0", true);
- }
- newArgs.erase(argP1);
- argP1 = arg;
- this->IncrementArguments(newArgs, argP1, argP2);
- reducible = 1;
- }
- //=========================================================================
- // helper function to reduce code duplication
- void cmConditionEvaluator::HandleBinaryOp(bool value, int& reducible,
- cmArgumentList::iterator& arg,
- cmArgumentList& newArgs,
- cmArgumentList::iterator& argP1,
- cmArgumentList::iterator& argP2)
- {
- if (value) {
- *arg = cmExpandedCommandArgument("1", true);
- } else {
- *arg = cmExpandedCommandArgument("0", true);
- }
- newArgs.erase(argP2);
- newArgs.erase(argP1);
- argP1 = arg;
- this->IncrementArguments(newArgs, argP1, argP2);
- reducible = 1;
- }
- //=========================================================================
- // level 0 processes parenthetical expressions
- bool cmConditionEvaluator::HandleLevel0(cmArgumentList& newArgs,
- std::string& errorString,
- cmake::MessageType& status)
- {
- int reducible;
- do {
- reducible = 0;
- cmArgumentList::iterator arg = newArgs.begin();
- while (arg != newArgs.end()) {
- if (IsKeyword(keyParenL, *arg)) {
- // search for the closing paren for this opening one
- cmArgumentList::iterator argClose;
- argClose = arg;
- argClose++;
- unsigned int depth = 1;
- while (argClose != newArgs.end() && depth) {
- if (this->IsKeyword(keyParenL, *argClose)) {
- depth++;
- }
- if (this->IsKeyword(keyParenR, *argClose)) {
- depth--;
- }
- argClose++;
- }
- if (depth) {
- errorString = "mismatched parenthesis in condition";
- status = cmake::FATAL_ERROR;
- return false;
- }
- // store the reduced args in this vector
- std::vector<cmExpandedCommandArgument> newArgs2;
- // copy to the list structure
- cmArgumentList::iterator argP1 = arg;
- argP1++;
- newArgs2.insert(newArgs2.end(), argP1, argClose);
- newArgs2.pop_back();
- // now recursively invoke IsTrue to handle the values inside the
- // parenthetical expression
- bool value = this->IsTrue(newArgs2, errorString, status);
- if (value) {
- *arg = cmExpandedCommandArgument("1", true);
- } else {
- *arg = cmExpandedCommandArgument("0", true);
- }
- argP1 = arg;
- argP1++;
- // remove the now evaluated parenthetical expression
- newArgs.erase(argP1, argClose);
- }
- ++arg;
- }
- } while (reducible);
- return true;
- }
- //=========================================================================
- // level one handles most predicates except for NOT
- bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&,
- cmake::MessageType&)
- {
- int reducible;
- do {
- reducible = 0;
- cmArgumentList::iterator arg = newArgs.begin();
- cmArgumentList::iterator argP1;
- cmArgumentList::iterator argP2;
- while (arg != newArgs.end()) {
- argP1 = arg;
- this->IncrementArguments(newArgs, argP1, argP2);
- // does a file exist
- if (this->IsKeyword(keyEXISTS, *arg) && argP1 != newArgs.end()) {
- this->HandlePredicate(cmSystemTools::FileExists(argP1->c_str()),
- reducible, arg, newArgs, argP1, argP2);
- }
- // does a directory with this name exist
- if (this->IsKeyword(keyIS_DIRECTORY, *arg) && argP1 != newArgs.end()) {
- this->HandlePredicate(cmSystemTools::FileIsDirectory(argP1->c_str()),
- reducible, arg, newArgs, argP1, argP2);
- }
- // does a symlink with this name exist
- if (this->IsKeyword(keyIS_SYMLINK, *arg) && argP1 != newArgs.end()) {
- this->HandlePredicate(cmSystemTools::FileIsSymlink(argP1->c_str()),
- reducible, arg, newArgs, argP1, argP2);
- }
- // is the given path an absolute path ?
- if (this->IsKeyword(keyIS_ABSOLUTE, *arg) && argP1 != newArgs.end()) {
- this->HandlePredicate(cmSystemTools::FileIsFullPath(argP1->c_str()),
- reducible, arg, newArgs, argP1, argP2);
- }
- // does a command exist
- if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end()) {
- cmCommand* command =
- this->Makefile.GetState()->GetCommand(argP1->c_str());
- this->HandlePredicate(command != nullptr, reducible, arg, newArgs,
- argP1, argP2);
- }
- // does a policy exist
- if (this->IsKeyword(keyPOLICY, *arg) && argP1 != newArgs.end()) {
- cmPolicies::PolicyID pid;
- this->HandlePredicate(cmPolicies::GetPolicyID(argP1->c_str(), pid),
- reducible, arg, newArgs, argP1, argP2);
- }
- // does a target exist
- if (this->IsKeyword(keyTARGET, *arg) && argP1 != newArgs.end()) {
- this->HandlePredicate(
- this->Makefile.FindTargetToUse(argP1->GetValue()) != nullptr,
- reducible, arg, newArgs, argP1, argP2);
- }
- // does a test exist
- if (this->Policy64Status != cmPolicies::OLD &&
- this->Policy64Status != cmPolicies::WARN) {
- if (this->IsKeyword(keyTEST, *arg) && argP1 != newArgs.end()) {
- const cmTest* haveTest = this->Makefile.GetTest(argP1->c_str());
- this->HandlePredicate(haveTest != nullptr, reducible, arg, newArgs,
- argP1, argP2);
- }
- } else if (this->Policy64Status == cmPolicies::WARN &&
- this->IsKeyword(keyTEST, *arg)) {
- std::ostringstream e;
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n";
- e << "TEST will be interpreted as an operator "
- "when the policy is set to NEW. "
- "Since the policy is not set the OLD behavior will be used.";
- this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str());
- }
- // is a variable defined
- if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) {
- size_t argP1len = argP1->GetValue().size();
- bool bdef = false;
- if (argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" &&
- argP1->GetValue().operator[](argP1len - 1) == '}') {
- std::string env = argP1->GetValue().substr(4, argP1len - 5);
- bdef = cmSystemTools::HasEnv(env);
- } else {
- bdef = this->Makefile.IsDefinitionSet(argP1->GetValue());
- }
- this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
- }
- ++arg;
- }
- } while (reducible);
- return true;
- }
- //=========================================================================
- // level two handles most binary operations except for AND OR
- bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs,
- std::string& errorString,
- cmake::MessageType& status)
- {
- int reducible;
- std::string def_buf;
- const char* def;
- const char* def2;
- do {
- reducible = 0;
- cmArgumentList::iterator arg = newArgs.begin();
- cmArgumentList::iterator argP1;
- cmArgumentList::iterator argP2;
- while (arg != newArgs.end()) {
- argP1 = arg;
- this->IncrementArguments(newArgs, argP1, argP2);
- if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
- IsKeyword(keyMATCHES, *argP1)) {
- def = this->GetVariableOrString(*arg);
- if (def != arg->c_str() // yes, we compare the pointer value
- && cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) {
- // The string to match is owned by our match result variables.
- // Move it to our own buffer before clearing them.
- def_buf = def;
- def = def_buf.c_str();
- }
- const char* rex = argP2->c_str();
- this->Makefile.ClearMatches();
- cmsys::RegularExpression regEntry;
- if (!regEntry.compile(rex)) {
- std::ostringstream error;
- error << "Regular expression \"" << rex << "\" cannot compile";
- errorString = error.str();
- status = cmake::FATAL_ERROR;
- return false;
- }
- if (regEntry.find(def)) {
- this->Makefile.StoreMatches(regEntry);
- *arg = cmExpandedCommandArgument("1", true);
- } else {
- *arg = cmExpandedCommandArgument("0", true);
- }
- newArgs.erase(argP2);
- newArgs.erase(argP1);
- argP1 = arg;
- this->IncrementArguments(newArgs, argP1, argP2);
- reducible = 1;
- }
- if (argP1 != newArgs.end() && this->IsKeyword(keyMATCHES, *arg)) {
- *arg = cmExpandedCommandArgument("0", true);
- newArgs.erase(argP1);
- argP1 = arg;
- this->IncrementArguments(newArgs, argP1, argP2);
- reducible = 1;
- }
- if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
- (this->IsKeyword(keyLESS, *argP1) ||
- this->IsKeyword(keyLESS_EQUAL, *argP1) ||
- this->IsKeyword(keyGREATER, *argP1) ||
- this->IsKeyword(keyGREATER_EQUAL, *argP1) ||
- this->IsKeyword(keyEQUAL, *argP1))) {
- def = this->GetVariableOrString(*arg);
- def2 = this->GetVariableOrString(*argP2);
- double lhs;
- double rhs;
- bool result;
- if (sscanf(def, "%lg", &lhs) != 1 || sscanf(def2, "%lg", &rhs) != 1) {
- result = false;
- } else if (*(argP1) == keyLESS) {
- result = (lhs < rhs);
- } else if (*(argP1) == keyLESS_EQUAL) {
- result = (lhs <= rhs);
- } else if (*(argP1) == keyGREATER) {
- result = (lhs > rhs);
- } else if (*(argP1) == keyGREATER_EQUAL) {
- result = (lhs >= rhs);
- } else {
- result = (lhs == rhs);
- }
- this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
- }
- if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
- (this->IsKeyword(keySTRLESS, *argP1) ||
- this->IsKeyword(keySTRLESS_EQUAL, *argP1) ||
- this->IsKeyword(keySTRGREATER, *argP1) ||
- this->IsKeyword(keySTRGREATER_EQUAL, *argP1) ||
- this->IsKeyword(keySTREQUAL, *argP1))) {
- def = this->GetVariableOrString(*arg);
- def2 = this->GetVariableOrString(*argP2);
- int val = strcmp(def, def2);
- bool result;
- if (*(argP1) == keySTRLESS) {
- result = (val < 0);
- } else if (*(argP1) == keySTRLESS_EQUAL) {
- result = (val <= 0);
- } else if (*(argP1) == keySTRGREATER) {
- result = (val > 0);
- } else if (*(argP1) == keySTRGREATER_EQUAL) {
- result = (val >= 0);
- } else // strequal
- {
- result = (val == 0);
- }
- this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
- }
- if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
- (this->IsKeyword(keyVERSION_LESS, *argP1) ||
- this->IsKeyword(keyVERSION_LESS_EQUAL, *argP1) ||
- this->IsKeyword(keyVERSION_GREATER, *argP1) ||
- this->IsKeyword(keyVERSION_GREATER_EQUAL, *argP1) ||
- this->IsKeyword(keyVERSION_EQUAL, *argP1))) {
- def = this->GetVariableOrString(*arg);
- def2 = this->GetVariableOrString(*argP2);
- cmSystemTools::CompareOp op;
- if (*argP1 == keyVERSION_LESS) {
- op = cmSystemTools::OP_LESS;
- } else if (*argP1 == keyVERSION_LESS_EQUAL) {
- op = cmSystemTools::OP_LESS_EQUAL;
- } else if (*argP1 == keyVERSION_GREATER) {
- op = cmSystemTools::OP_GREATER;
- } else if (*argP1 == keyVERSION_GREATER_EQUAL) {
- op = cmSystemTools::OP_GREATER_EQUAL;
- } else { // version_equal
- op = cmSystemTools::OP_EQUAL;
- }
- bool result = cmSystemTools::VersionCompare(op, def, def2);
- this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
- }
- // is file A newer than file B
- if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
- this->IsKeyword(keyIS_NEWER_THAN, *argP1)) {
- int fileIsNewer = 0;
- bool success = cmSystemTools::FileTimeCompare(
- arg->GetValue(), (argP2)->GetValue(), &fileIsNewer);
- this->HandleBinaryOp(
- (!success || fileIsNewer == 1 || fileIsNewer == 0), reducible, arg,
- newArgs, argP1, argP2);
- }
- if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
- this->IsKeyword(keyIN_LIST, *argP1)) {
- if (this->Policy57Status != cmPolicies::OLD &&
- this->Policy57Status != cmPolicies::WARN) {
- bool result = false;
- def = this->GetVariableOrString(*arg);
- def2 = this->Makefile.GetDefinition(argP2->GetValue());
- if (def2) {
- std::vector<std::string> list;
- cmSystemTools::ExpandListArgument(def2, list, true);
- result = std::find(list.begin(), list.end(), def) != list.end();
- }
- this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2);
- } else if (this->Policy57Status == cmPolicies::WARN) {
- std::ostringstream e;
- e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057) << "\n";
- e << "IN_LIST will be interpreted as an operator "
- "when the policy is set to NEW. "
- "Since the policy is not set the OLD behavior will be used.";
- this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str());
- }
- }
- ++arg;
- }
- } while (reducible);
- return true;
- }
- //=========================================================================
- // level 3 handles NOT
- bool cmConditionEvaluator::HandleLevel3(cmArgumentList& newArgs,
- std::string& errorString,
- cmake::MessageType& status)
- {
- int reducible;
- do {
- reducible = 0;
- cmArgumentList::iterator arg = newArgs.begin();
- cmArgumentList::iterator argP1;
- cmArgumentList::iterator argP2;
- while (arg != newArgs.end()) {
- argP1 = arg;
- IncrementArguments(newArgs, argP1, argP2);
- if (argP1 != newArgs.end() && IsKeyword(keyNOT, *arg)) {
- bool rhs = this->GetBooleanValueWithAutoDereference(
- *argP1, errorString, status);
- this->HandlePredicate(!rhs, reducible, arg, newArgs, argP1, argP2);
- }
- ++arg;
- }
- } while (reducible);
- return true;
- }
- //=========================================================================
- // level 4 handles AND OR
- bool cmConditionEvaluator::HandleLevel4(cmArgumentList& newArgs,
- std::string& errorString,
- cmake::MessageType& status)
- {
- int reducible;
- bool lhs;
- bool rhs;
- do {
- reducible = 0;
- cmArgumentList::iterator arg = newArgs.begin();
- cmArgumentList::iterator argP1;
- cmArgumentList::iterator argP2;
- while (arg != newArgs.end()) {
- argP1 = arg;
- IncrementArguments(newArgs, argP1, argP2);
- if (argP1 != newArgs.end() && IsKeyword(keyAND, *argP1) &&
- argP2 != newArgs.end()) {
- lhs =
- this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
- rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
- status);
- this->HandleBinaryOp((lhs && rhs), reducible, arg, newArgs, argP1,
- argP2);
- }
- if (argP1 != newArgs.end() && this->IsKeyword(keyOR, *argP1) &&
- argP2 != newArgs.end()) {
- lhs =
- this->GetBooleanValueWithAutoDereference(*arg, errorString, status);
- rhs = this->GetBooleanValueWithAutoDereference(*argP2, errorString,
- status);
- this->HandleBinaryOp((lhs || rhs), reducible, arg, newArgs, argP1,
- argP2);
- }
- ++arg;
- }
- } while (reducible);
- return true;
- }
|