cmConditionEvaluator.cxx 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2014 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmConditionEvaluator.h"
  11. #include "cmOutputConverter.h"
  12. #include "cmAlgorithms.h"
  13. static std::string const keyAND = "AND";
  14. static std::string const keyCOMMAND = "COMMAND";
  15. static std::string const keyDEFINED = "DEFINED";
  16. static std::string const keyEQUAL = "EQUAL";
  17. static std::string const keyEXISTS = "EXISTS";
  18. static std::string const keyGREATER = "GREATER";
  19. static std::string const keyIN_LIST = "IN_LIST";
  20. static std::string const keyIS_ABSOLUTE = "IS_ABSOLUTE";
  21. static std::string const keyIS_DIRECTORY = "IS_DIRECTORY";
  22. static std::string const keyIS_NEWER_THAN = "IS_NEWER_THAN";
  23. static std::string const keyIS_SYMLINK = "IS_SYMLINK";
  24. static std::string const keyLESS = "LESS";
  25. static std::string const keyMATCHES = "MATCHES";
  26. static std::string const keyNOT = "NOT";
  27. static std::string const keyOR = "OR";
  28. static std::string const keyParenL = "(";
  29. static std::string const keyParenR = ")";
  30. static std::string const keyPOLICY = "POLICY";
  31. static std::string const keySTREQUAL = "STREQUAL";
  32. static std::string const keySTRGREATER = "STRGREATER";
  33. static std::string const keySTRLESS = "STRLESS";
  34. static std::string const keyTARGET = "TARGET";
  35. static std::string const keyTEST = "TEST";
  36. static std::string const keyVERSION_EQUAL = "VERSION_EQUAL";
  37. static std::string const keyVERSION_GREATER = "VERSION_GREATER";
  38. static std::string const keyVERSION_LESS = "VERSION_LESS";
  39. cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile,
  40. const cmListFileContext &context,
  41. const cmListFileBacktrace& bt):
  42. Makefile(makefile),
  43. ExecutionContext(context),
  44. Backtrace(bt),
  45. Policy12Status(makefile.GetPolicyStatus(cmPolicies::CMP0012)),
  46. Policy54Status(makefile.GetPolicyStatus(cmPolicies::CMP0054)),
  47. Policy57Status(makefile.GetPolicyStatus(cmPolicies::CMP0057)),
  48. Policy64Status(makefile.GetPolicyStatus(cmPolicies::CMP0064))
  49. {
  50. }
  51. //=========================================================================
  52. // order of operations,
  53. // 1. ( ) -- parenthetical groups
  54. // 2. IS_DIRECTORY EXISTS COMMAND DEFINED etc predicates
  55. // 3. MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL etc binary ops
  56. // 4. NOT
  57. // 5. AND OR
  58. //
  59. // There is an issue on whether the arguments should be values of references,
  60. // for example IF (FOO AND BAR) should that compare the strings FOO and BAR
  61. // or should it really do IF (${FOO} AND ${BAR}) Currently IS_DIRECTORY
  62. // EXISTS COMMAND and DEFINED all take values. EQUAL, LESS and GREATER can
  63. // take numeric values or variable names. STRLESS and STRGREATER take
  64. // variable names but if the variable name is not found it will use the name
  65. // directly. AND OR take variables or the values 0 or 1.
  66. bool cmConditionEvaluator::IsTrue(
  67. const std::vector<cmExpandedCommandArgument> &args,
  68. std::string &errorString,
  69. cmake::MessageType &status)
  70. {
  71. errorString = "";
  72. // handle empty invocation
  73. if (args.size() < 1)
  74. {
  75. return false;
  76. }
  77. // store the reduced args in this vector
  78. cmArgumentList newArgs;
  79. // copy to the list structure
  80. newArgs.insert(newArgs.end(), args.begin(), args.end());
  81. // now loop through the arguments and see if we can reduce any of them
  82. // we do this multiple times. Once for each level of precedence
  83. // parens
  84. if (!this->HandleLevel0(newArgs, errorString, status))
  85. {
  86. return false;
  87. }
  88. //predicates
  89. if (!this->HandleLevel1(newArgs, errorString, status))
  90. {
  91. return false;
  92. }
  93. // binary ops
  94. if (!this->HandleLevel2(newArgs, errorString, status))
  95. {
  96. return false;
  97. }
  98. // NOT
  99. if (!this->HandleLevel3(newArgs, errorString, status))
  100. {
  101. return false;
  102. }
  103. // AND OR
  104. if (!this->HandleLevel4(newArgs, errorString, status))
  105. {
  106. return false;
  107. }
  108. // now at the end there should only be one argument left
  109. if (newArgs.size() != 1)
  110. {
  111. errorString = "Unknown arguments specified";
  112. status = cmake::FATAL_ERROR;
  113. return false;
  114. }
  115. return this->GetBooleanValueWithAutoDereference(*(newArgs.begin()),
  116. errorString, status, true);
  117. }
  118. //=========================================================================
  119. const char* cmConditionEvaluator::GetDefinitionIfUnquoted(
  120. cmExpandedCommandArgument const& argument) const
  121. {
  122. if((this->Policy54Status != cmPolicies::WARN &&
  123. this->Policy54Status != cmPolicies::OLD) &&
  124. argument.WasQuoted())
  125. {
  126. return 0;
  127. }
  128. const char* def = this->Makefile.GetDefinition(argument.GetValue());
  129. if(def && argument.WasQuoted() && this->Policy54Status == cmPolicies::WARN)
  130. {
  131. if(!this->Makefile.HasCMP0054AlreadyBeenReported(
  132. this->ExecutionContext))
  133. {
  134. std::ostringstream e;
  135. e << (cmPolicies::GetPolicyWarning(cmPolicies::CMP0054)) << "\n";
  136. e << "Quoted variables like \"" << argument.GetValue() <<
  137. "\" will no longer be dereferenced "
  138. "when the policy is set to NEW. "
  139. "Since the policy is not set the OLD behavior will be used.";
  140. this->Makefile.GetCMakeInstance()
  141. ->IssueMessage(cmake::AUTHOR_WARNING, e.str(),
  142. this->Backtrace);
  143. }
  144. }
  145. return def;
  146. }
  147. //=========================================================================
  148. const char* cmConditionEvaluator::GetVariableOrString(
  149. const cmExpandedCommandArgument& argument) const
  150. {
  151. const char* def = this->GetDefinitionIfUnquoted(argument);
  152. if(!def)
  153. {
  154. def = argument.c_str();
  155. }
  156. return def;
  157. }
  158. //=========================================================================
  159. bool cmConditionEvaluator::IsKeyword(std::string const& keyword,
  160. cmExpandedCommandArgument& argument) const
  161. {
  162. if((this->Policy54Status != cmPolicies::WARN &&
  163. this->Policy54Status != cmPolicies::OLD) &&
  164. argument.WasQuoted())
  165. {
  166. return false;
  167. }
  168. bool isKeyword = argument.GetValue() == keyword;
  169. if(isKeyword && argument.WasQuoted() &&
  170. this->Policy54Status == cmPolicies::WARN)
  171. {
  172. if(!this->Makefile.HasCMP0054AlreadyBeenReported(
  173. this->ExecutionContext))
  174. {
  175. std::ostringstream e;
  176. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0054) << "\n";
  177. e << "Quoted keywords like \"" << argument.GetValue() <<
  178. "\" will no longer be interpreted as keywords "
  179. "when the policy is set to NEW. "
  180. "Since the policy is not set the OLD behavior will be used.";
  181. this->Makefile.GetCMakeInstance()
  182. ->IssueMessage(cmake::AUTHOR_WARNING, e.str(),
  183. this->Backtrace);
  184. }
  185. }
  186. return isKeyword;
  187. }
  188. //=========================================================================
  189. bool cmConditionEvaluator::GetBooleanValue(
  190. cmExpandedCommandArgument& arg) const
  191. {
  192. // Check basic constants.
  193. if (arg == "0")
  194. {
  195. return false;
  196. }
  197. if (arg == "1")
  198. {
  199. return true;
  200. }
  201. // Check named constants.
  202. if (cmSystemTools::IsOn(arg.c_str()))
  203. {
  204. return true;
  205. }
  206. if (cmSystemTools::IsOff(arg.c_str()))
  207. {
  208. return false;
  209. }
  210. // Check for numbers.
  211. if(!arg.empty())
  212. {
  213. char* end;
  214. double d = strtod(arg.c_str(), &end);
  215. if(*end == '\0')
  216. {
  217. // The whole string is a number. Use C conversion to bool.
  218. return d? true:false;
  219. }
  220. }
  221. // Check definition.
  222. const char* def = this->GetDefinitionIfUnquoted(arg);
  223. return !cmSystemTools::IsOff(def);
  224. }
  225. //=========================================================================
  226. // Boolean value behavior from CMake 2.6.4 and below.
  227. bool cmConditionEvaluator::GetBooleanValueOld(
  228. cmExpandedCommandArgument const& arg, bool one) const
  229. {
  230. if(one)
  231. {
  232. // Old IsTrue behavior for single argument.
  233. if(arg == "0")
  234. { return false; }
  235. else if(arg == "1")
  236. { return true; }
  237. else
  238. {
  239. const char* def = this->GetDefinitionIfUnquoted(arg);
  240. return !cmSystemTools::IsOff(def);
  241. }
  242. }
  243. else
  244. {
  245. // Old GetVariableOrNumber behavior.
  246. const char* def = this->GetDefinitionIfUnquoted(arg);
  247. if(!def && atoi(arg.c_str()))
  248. {
  249. def = arg.c_str();
  250. }
  251. return !cmSystemTools::IsOff(def);
  252. }
  253. }
  254. //=========================================================================
  255. // returns the resulting boolean value
  256. bool cmConditionEvaluator::GetBooleanValueWithAutoDereference(
  257. cmExpandedCommandArgument &newArg,
  258. std::string &errorString,
  259. cmake::MessageType &status,
  260. bool oneArg) const
  261. {
  262. // Use the policy if it is set.
  263. if (this->Policy12Status == cmPolicies::NEW)
  264. {
  265. return GetBooleanValue(newArg);
  266. }
  267. else if (this->Policy12Status == cmPolicies::OLD)
  268. {
  269. return GetBooleanValueOld(newArg, oneArg);
  270. }
  271. // Check policy only if old and new results differ.
  272. bool newResult = this->GetBooleanValue(newArg);
  273. bool oldResult = this->GetBooleanValueOld(newArg, oneArg);
  274. if(newResult != oldResult)
  275. {
  276. switch(this->Policy12Status)
  277. {
  278. case cmPolicies::WARN:
  279. {
  280. errorString = "An argument named \"" + newArg.GetValue()
  281. + "\" appears in a conditional statement. "
  282. + cmPolicies::GetPolicyWarning(cmPolicies::CMP0012);
  283. status = cmake::AUTHOR_WARNING;
  284. }
  285. case cmPolicies::OLD:
  286. return oldResult;
  287. case cmPolicies::REQUIRED_IF_USED:
  288. case cmPolicies::REQUIRED_ALWAYS:
  289. {
  290. errorString = "An argument named \"" + newArg.GetValue()
  291. + "\" appears in a conditional statement. "
  292. + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0012);
  293. status = cmake::FATAL_ERROR;
  294. }
  295. case cmPolicies::NEW:
  296. break;
  297. }
  298. }
  299. return newResult;
  300. }
  301. //=========================================================================
  302. void cmConditionEvaluator::IncrementArguments(cmArgumentList &newArgs,
  303. cmArgumentList::iterator &argP1,
  304. cmArgumentList::iterator &argP2) const
  305. {
  306. if (argP1 != newArgs.end())
  307. {
  308. argP1++;
  309. argP2 = argP1;
  310. if (argP1 != newArgs.end())
  311. {
  312. argP2++;
  313. }
  314. }
  315. }
  316. //=========================================================================
  317. // helper function to reduce code duplication
  318. void cmConditionEvaluator::HandlePredicate(bool value, int &reducible,
  319. cmArgumentList::iterator &arg,
  320. cmArgumentList &newArgs,
  321. cmArgumentList::iterator &argP1,
  322. cmArgumentList::iterator &argP2) const
  323. {
  324. if(value)
  325. {
  326. *arg = cmExpandedCommandArgument("1", true);
  327. }
  328. else
  329. {
  330. *arg = cmExpandedCommandArgument("0", true);
  331. }
  332. newArgs.erase(argP1);
  333. argP1 = arg;
  334. this->IncrementArguments(newArgs,argP1,argP2);
  335. reducible = 1;
  336. }
  337. //=========================================================================
  338. // helper function to reduce code duplication
  339. void cmConditionEvaluator::HandleBinaryOp(bool value, int &reducible,
  340. cmArgumentList::iterator &arg,
  341. cmArgumentList &newArgs,
  342. cmArgumentList::iterator &argP1,
  343. cmArgumentList::iterator &argP2)
  344. {
  345. if(value)
  346. {
  347. *arg = cmExpandedCommandArgument("1", true);
  348. }
  349. else
  350. {
  351. *arg = cmExpandedCommandArgument("0", true);
  352. }
  353. newArgs.erase(argP2);
  354. newArgs.erase(argP1);
  355. argP1 = arg;
  356. this->IncrementArguments(newArgs,argP1,argP2);
  357. reducible = 1;
  358. }
  359. //=========================================================================
  360. // level 0 processes parenthetical expressions
  361. bool cmConditionEvaluator::HandleLevel0(cmArgumentList &newArgs,
  362. std::string &errorString,
  363. cmake::MessageType &status)
  364. {
  365. int reducible;
  366. do
  367. {
  368. reducible = 0;
  369. cmArgumentList::iterator arg = newArgs.begin();
  370. while (arg != newArgs.end())
  371. {
  372. if (IsKeyword(keyParenL, *arg))
  373. {
  374. // search for the closing paren for this opening one
  375. cmArgumentList::iterator argClose;
  376. argClose = arg;
  377. argClose++;
  378. unsigned int depth = 1;
  379. while (argClose != newArgs.end() && depth)
  380. {
  381. if (this->IsKeyword(keyParenL, *argClose))
  382. {
  383. depth++;
  384. }
  385. if (this->IsKeyword(keyParenR, *argClose))
  386. {
  387. depth--;
  388. }
  389. argClose++;
  390. }
  391. if (depth)
  392. {
  393. errorString = "mismatched parenthesis in condition";
  394. status = cmake::FATAL_ERROR;
  395. return false;
  396. }
  397. // store the reduced args in this vector
  398. std::vector<cmExpandedCommandArgument> newArgs2;
  399. // copy to the list structure
  400. cmArgumentList::iterator argP1 = arg;
  401. argP1++;
  402. newArgs2.insert(newArgs2.end(), argP1, argClose);
  403. newArgs2.pop_back();
  404. // now recursively invoke IsTrue to handle the values inside the
  405. // parenthetical expression
  406. bool value =
  407. this->IsTrue(newArgs2, errorString, status);
  408. if(value)
  409. {
  410. *arg = cmExpandedCommandArgument("1", true);
  411. }
  412. else
  413. {
  414. *arg = cmExpandedCommandArgument("0", true);
  415. }
  416. argP1 = arg;
  417. argP1++;
  418. // remove the now evaluated parenthetical expression
  419. newArgs.erase(argP1,argClose);
  420. }
  421. ++arg;
  422. }
  423. }
  424. while (reducible);
  425. return true;
  426. }
  427. //=========================================================================
  428. // level one handles most predicates except for NOT
  429. bool cmConditionEvaluator::HandleLevel1(cmArgumentList &newArgs,
  430. std::string &, cmake::MessageType &)
  431. {
  432. int reducible;
  433. do
  434. {
  435. reducible = 0;
  436. cmArgumentList::iterator arg = newArgs.begin();
  437. cmArgumentList::iterator argP1;
  438. cmArgumentList::iterator argP2;
  439. while (arg != newArgs.end())
  440. {
  441. argP1 = arg;
  442. this->IncrementArguments(newArgs,argP1,argP2);
  443. // does a file exist
  444. if (this->IsKeyword(keyEXISTS, *arg) && argP1 != newArgs.end())
  445. {
  446. this->HandlePredicate(
  447. cmSystemTools::FileExists(argP1->c_str()),
  448. reducible, arg, newArgs, argP1, argP2);
  449. }
  450. // does a directory with this name exist
  451. if (this->IsKeyword(keyIS_DIRECTORY, *arg) && argP1 != newArgs.end())
  452. {
  453. this->HandlePredicate(
  454. cmSystemTools::FileIsDirectory(argP1->c_str()),
  455. reducible, arg, newArgs, argP1, argP2);
  456. }
  457. // does a symlink with this name exist
  458. if (this->IsKeyword(keyIS_SYMLINK, *arg) && argP1 != newArgs.end())
  459. {
  460. this->HandlePredicate(
  461. cmSystemTools::FileIsSymlink(argP1->c_str()),
  462. reducible, arg, newArgs, argP1, argP2);
  463. }
  464. // is the given path an absolute path ?
  465. if (this->IsKeyword(keyIS_ABSOLUTE, *arg) && argP1 != newArgs.end())
  466. {
  467. this->HandlePredicate(
  468. cmSystemTools::FileIsFullPath(argP1->c_str()),
  469. reducible, arg, newArgs, argP1, argP2);
  470. }
  471. // does a command exist
  472. if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end())
  473. {
  474. cmCommand* command =
  475. this->Makefile.GetState()->GetCommand(argP1->c_str());
  476. this->HandlePredicate(
  477. command ? true : false,
  478. reducible, arg, newArgs, argP1, argP2);
  479. }
  480. // does a policy exist
  481. if (this->IsKeyword(keyPOLICY, *arg) && argP1 != newArgs.end())
  482. {
  483. cmPolicies::PolicyID pid;
  484. this->HandlePredicate(
  485. cmPolicies::GetPolicyID(argP1->c_str(), pid),
  486. reducible, arg, newArgs, argP1, argP2);
  487. }
  488. // does a target exist
  489. if (this->IsKeyword(keyTARGET, *arg) && argP1 != newArgs.end())
  490. {
  491. this->HandlePredicate(
  492. this->Makefile.FindTargetToUse(argP1->GetValue())?true:false,
  493. reducible, arg, newArgs, argP1, argP2);
  494. }
  495. // does a test exist
  496. if(this->Policy64Status != cmPolicies::OLD &&
  497. this->Policy64Status != cmPolicies::WARN)
  498. {
  499. if (this->IsKeyword(keyTEST, *arg) && argP1 != newArgs.end())
  500. {
  501. const cmTest* haveTest = this->Makefile.GetTest(argP1->c_str());
  502. this->HandlePredicate(
  503. haveTest?true:false,
  504. reducible, arg, newArgs, argP1, argP2);
  505. }
  506. }
  507. else if(this->Policy64Status == cmPolicies::WARN &&
  508. this->IsKeyword(keyTEST, *arg))
  509. {
  510. std::ostringstream e;
  511. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0064) << "\n";
  512. e << "TEST will be interpreted as an operator "
  513. "when the policy is set to NEW. "
  514. "Since the policy is not set the OLD behavior will be used.";
  515. this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str());
  516. }
  517. // is a variable defined
  518. if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end())
  519. {
  520. size_t argP1len = argP1->GetValue().size();
  521. bool bdef = false;
  522. if(argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" &&
  523. argP1->GetValue().operator[](argP1len-1) == '}')
  524. {
  525. std::string env = argP1->GetValue().substr(4, argP1len-5);
  526. bdef = cmSystemTools::GetEnv(env.c_str())?true:false;
  527. }
  528. else
  529. {
  530. bdef = this->Makefile.IsDefinitionSet(argP1->GetValue());
  531. }
  532. this->HandlePredicate(bdef, reducible, arg, newArgs, argP1, argP2);
  533. }
  534. ++arg;
  535. }
  536. }
  537. while (reducible);
  538. return true;
  539. }
  540. //=========================================================================
  541. // level two handles most binary operations except for AND OR
  542. bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs,
  543. std::string &errorString,
  544. cmake::MessageType &status)
  545. {
  546. int reducible;
  547. std::string def_buf;
  548. const char *def;
  549. const char *def2;
  550. do
  551. {
  552. reducible = 0;
  553. cmArgumentList::iterator arg = newArgs.begin();
  554. cmArgumentList::iterator argP1;
  555. cmArgumentList::iterator argP2;
  556. while (arg != newArgs.end())
  557. {
  558. argP1 = arg;
  559. this->IncrementArguments(newArgs,argP1,argP2);
  560. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  561. IsKeyword(keyMATCHES, *argP1))
  562. {
  563. def = this->GetVariableOrString(*arg);
  564. if (def != arg->c_str() // yes, we compare the pointer value
  565. && cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_"))
  566. {
  567. // The string to match is owned by our match result variables.
  568. // Move it to our own buffer before clearing them.
  569. def_buf = def;
  570. def = def_buf.c_str();
  571. }
  572. const char* rex = argP2->c_str();
  573. this->Makefile.ClearMatches();
  574. cmsys::RegularExpression regEntry;
  575. if ( !regEntry.compile(rex) )
  576. {
  577. std::ostringstream error;
  578. error << "Regular expression \"" << rex << "\" cannot compile";
  579. errorString = error.str();
  580. status = cmake::FATAL_ERROR;
  581. return false;
  582. }
  583. if (regEntry.find(def))
  584. {
  585. this->Makefile.StoreMatches(regEntry);
  586. *arg = cmExpandedCommandArgument("1", true);
  587. }
  588. else
  589. {
  590. *arg = cmExpandedCommandArgument("0", true);
  591. }
  592. newArgs.erase(argP2);
  593. newArgs.erase(argP1);
  594. argP1 = arg;
  595. this->IncrementArguments(newArgs,argP1,argP2);
  596. reducible = 1;
  597. }
  598. if (argP1 != newArgs.end() && this->IsKeyword(keyMATCHES, *arg))
  599. {
  600. *arg = cmExpandedCommandArgument("0", true);
  601. newArgs.erase(argP1);
  602. argP1 = arg;
  603. this->IncrementArguments(newArgs,argP1,argP2);
  604. reducible = 1;
  605. }
  606. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  607. (this->IsKeyword(keyLESS, *argP1) ||
  608. this->IsKeyword(keyGREATER, *argP1) ||
  609. this->IsKeyword(keyEQUAL, *argP1)))
  610. {
  611. def = this->GetVariableOrString(*arg);
  612. def2 = this->GetVariableOrString(*argP2);
  613. double lhs;
  614. double rhs;
  615. bool result;
  616. if(sscanf(def, "%lg", &lhs) != 1 ||
  617. sscanf(def2, "%lg", &rhs) != 1)
  618. {
  619. result = false;
  620. }
  621. else if (*(argP1) == keyLESS)
  622. {
  623. result = (lhs < rhs);
  624. }
  625. else if (*(argP1) == keyGREATER)
  626. {
  627. result = (lhs > rhs);
  628. }
  629. else
  630. {
  631. result = (lhs == rhs);
  632. }
  633. this->HandleBinaryOp(result,
  634. reducible, arg, newArgs, argP1, argP2);
  635. }
  636. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  637. (this->IsKeyword(keySTRLESS, *argP1) ||
  638. this->IsKeyword(keySTREQUAL, *argP1) ||
  639. this->IsKeyword(keySTRGREATER, *argP1)))
  640. {
  641. def = this->GetVariableOrString(*arg);
  642. def2 = this->GetVariableOrString(*argP2);
  643. int val = strcmp(def,def2);
  644. bool result;
  645. if (*(argP1) == keySTRLESS)
  646. {
  647. result = (val < 0);
  648. }
  649. else if (*(argP1) == keySTRGREATER)
  650. {
  651. result = (val > 0);
  652. }
  653. else // strequal
  654. {
  655. result = (val == 0);
  656. }
  657. this->HandleBinaryOp(result,
  658. reducible, arg, newArgs, argP1, argP2);
  659. }
  660. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  661. (this->IsKeyword(keyVERSION_LESS, *argP1) ||
  662. this->IsKeyword(keyVERSION_GREATER, *argP1) ||
  663. this->IsKeyword(keyVERSION_EQUAL, *argP1)))
  664. {
  665. def = this->GetVariableOrString(*arg);
  666. def2 = this->GetVariableOrString(*argP2);
  667. cmSystemTools::CompareOp op = cmSystemTools::OP_EQUAL;
  668. if(*argP1 == keyVERSION_LESS)
  669. {
  670. op = cmSystemTools::OP_LESS;
  671. }
  672. else if(*argP1 == keyVERSION_GREATER)
  673. {
  674. op = cmSystemTools::OP_GREATER;
  675. }
  676. bool result = cmSystemTools::VersionCompare(op, def, def2);
  677. this->HandleBinaryOp(result,
  678. reducible, arg, newArgs, argP1, argP2);
  679. }
  680. // is file A newer than file B
  681. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  682. this->IsKeyword(keyIS_NEWER_THAN, *argP1))
  683. {
  684. int fileIsNewer=0;
  685. bool success=cmSystemTools::FileTimeCompare(arg->GetValue(),
  686. (argP2)->GetValue(),
  687. &fileIsNewer);
  688. this->HandleBinaryOp(
  689. (success==false || fileIsNewer==1 || fileIsNewer==0),
  690. reducible, arg, newArgs, argP1, argP2);
  691. }
  692. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  693. this->IsKeyword(keyIN_LIST, *argP1))
  694. {
  695. if(this->Policy57Status != cmPolicies::OLD &&
  696. this->Policy57Status != cmPolicies::WARN)
  697. {
  698. bool result = false;
  699. def = this->GetVariableOrString(*arg);
  700. def2 = this->Makefile.GetDefinition(argP2->GetValue());
  701. if(def2)
  702. {
  703. std::vector<std::string> list;
  704. cmSystemTools::ExpandListArgument(def2, list, true);
  705. result = std::find(list.begin(), list.end(), def) != list.end();
  706. }
  707. this->HandleBinaryOp(result,
  708. reducible, arg, newArgs, argP1, argP2);
  709. }
  710. else if(this->Policy57Status == cmPolicies::WARN)
  711. {
  712. std::ostringstream e;
  713. e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0057) << "\n";
  714. e << "IN_LIST will be interpreted as an operator "
  715. "when the policy is set to NEW. "
  716. "Since the policy is not set the OLD behavior will be used.";
  717. this->Makefile.IssueMessage(cmake::AUTHOR_WARNING, e.str());
  718. }
  719. }
  720. ++arg;
  721. }
  722. }
  723. while (reducible);
  724. return true;
  725. }
  726. //=========================================================================
  727. // level 3 handles NOT
  728. bool cmConditionEvaluator::HandleLevel3(cmArgumentList &newArgs,
  729. std::string &errorString,
  730. cmake::MessageType &status)
  731. {
  732. int reducible;
  733. do
  734. {
  735. reducible = 0;
  736. cmArgumentList::iterator arg = newArgs.begin();
  737. cmArgumentList::iterator argP1;
  738. cmArgumentList::iterator argP2;
  739. while (arg != newArgs.end())
  740. {
  741. argP1 = arg;
  742. IncrementArguments(newArgs,argP1,argP2);
  743. if (argP1 != newArgs.end() && IsKeyword(keyNOT, *arg))
  744. {
  745. bool rhs = this->GetBooleanValueWithAutoDereference(*argP1,
  746. errorString,
  747. status);
  748. this->HandlePredicate(!rhs, reducible, arg, newArgs, argP1, argP2);
  749. }
  750. ++arg;
  751. }
  752. }
  753. while (reducible);
  754. return true;
  755. }
  756. //=========================================================================
  757. // level 4 handles AND OR
  758. bool cmConditionEvaluator::HandleLevel4(cmArgumentList &newArgs,
  759. std::string &errorString,
  760. cmake::MessageType &status)
  761. {
  762. int reducible;
  763. bool lhs;
  764. bool rhs;
  765. do
  766. {
  767. reducible = 0;
  768. cmArgumentList::iterator arg = newArgs.begin();
  769. cmArgumentList::iterator argP1;
  770. cmArgumentList::iterator argP2;
  771. while (arg != newArgs.end())
  772. {
  773. argP1 = arg;
  774. IncrementArguments(newArgs,argP1,argP2);
  775. if (argP1 != newArgs.end() && IsKeyword(keyAND, *argP1) &&
  776. argP2 != newArgs.end())
  777. {
  778. lhs = this->GetBooleanValueWithAutoDereference(*arg,
  779. errorString,
  780. status);
  781. rhs = this->GetBooleanValueWithAutoDereference(*argP2,
  782. errorString,
  783. status);
  784. this->HandleBinaryOp((lhs && rhs),
  785. reducible, arg, newArgs, argP1, argP2);
  786. }
  787. if (argP1 != newArgs.end() && this->IsKeyword(keyOR, *argP1) &&
  788. argP2 != newArgs.end())
  789. {
  790. lhs = this->GetBooleanValueWithAutoDereference(*arg,
  791. errorString,
  792. status);
  793. rhs = this->GetBooleanValueWithAutoDereference(*argP2,
  794. errorString,
  795. status);
  796. this->HandleBinaryOp((lhs || rhs),
  797. reducible, arg, newArgs, argP1, argP2);
  798. }
  799. ++arg;
  800. }
  801. }
  802. while (reducible);
  803. return true;
  804. }