cmConditionEvaluator.cxx 23 KB

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