cmIfCommand.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmIfCommand.h"
  14. #include <stdlib.h> // required for atof
  15. #include <list>
  16. #include <cmsys/RegularExpression.hxx>
  17. bool cmIfFunctionBlocker::
  18. IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf)
  19. {
  20. const char* name = lff.m_Name.c_str();
  21. const std::vector<cmListFileArgument>& args = lff.m_Arguments;
  22. // always let if statements through
  23. if (!strcmp(name,"IF"))
  24. {
  25. return false;
  26. }
  27. // watch for our ELSE or ENDIF
  28. if (!strcmp(name,"ELSE") || !strcmp(name,"ENDIF"))
  29. {
  30. if (args == m_Args)
  31. {
  32. // if it was an else statement then we should change state
  33. // and block this Else Command
  34. if (!strcmp(name,"ELSE"))
  35. {
  36. m_IsBlocking = !m_IsBlocking;
  37. return true;
  38. }
  39. // otherwise it must be an ENDIF statement, in that case remove the
  40. // function blocker
  41. mf.RemoveFunctionBlocker(lff);
  42. return true;
  43. }
  44. else if(args.empty())
  45. {
  46. std::string err = "Empty arguments for ";
  47. err += name;
  48. err += ". Did you mean ";
  49. err += name;
  50. err += "( ";
  51. for(std::vector<cmListFileArgument>::const_iterator a = m_Args.begin();
  52. a != m_Args.end();++a)
  53. {
  54. err += (a->Quoted?"\"":"");
  55. err += a->Value;
  56. err += (a->Quoted?"\"":"");
  57. err += " ";
  58. }
  59. err += ")?";
  60. cmSystemTools::Error(err.c_str());
  61. }
  62. }
  63. return m_IsBlocking;
  64. }
  65. bool cmIfFunctionBlocker::ShouldRemove(const cmListFileFunction& lff,
  66. cmMakefile&)
  67. {
  68. if (lff.m_Name == "ENDIF")
  69. {
  70. if (lff.m_Arguments == m_Args)
  71. {
  72. return true;
  73. }
  74. }
  75. return false;
  76. }
  77. void cmIfFunctionBlocker::
  78. ScopeEnded(cmMakefile &mf)
  79. {
  80. std::string errmsg = "The end of a CMakeLists file was reached with an IF statement that was not closed properly.\nWithin the directory: ";
  81. errmsg += mf.GetCurrentDirectory();
  82. errmsg += "\nThe arguments are: ";
  83. for(std::vector<cmListFileArgument>::const_iterator j = m_Args.begin();
  84. j != m_Args.end(); ++j)
  85. {
  86. errmsg += (j->Quoted?"\"":"");
  87. errmsg += j->Value;
  88. errmsg += (j->Quoted?"\"":"");
  89. errmsg += " ";
  90. }
  91. cmSystemTools::Message(errmsg.c_str(), "Warning");
  92. }
  93. bool cmIfCommand::InvokeInitialPass(const std::vector<cmListFileArgument>& args)
  94. {
  95. bool isValid;
  96. std::vector<std::string> expandedArguments;
  97. m_Makefile->ExpandArguments(args, expandedArguments);
  98. bool isTrue = cmIfCommand::IsTrue(expandedArguments,isValid,m_Makefile);
  99. if (!isValid)
  100. {
  101. std::string err = "An IF command had incorrect arguments: ";
  102. unsigned int i;
  103. for(i =0; i < args.size(); ++i)
  104. {
  105. err += (args[i].Quoted?"\"":"");
  106. err += args[i].Value;
  107. err += (args[i].Quoted?"\"":"");
  108. err += " ";
  109. }
  110. this->SetError(err.c_str());
  111. return false;
  112. }
  113. cmIfFunctionBlocker *f = new cmIfFunctionBlocker();
  114. // if is isn't true block the commands
  115. f->m_IsBlocking = !isTrue;
  116. f->m_Args = args;
  117. m_Makefile->AddFunctionBlocker(f);
  118. return true;
  119. }
  120. // order of operations,
  121. // EXISTS COMMAND DEFINED
  122. // MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL
  123. // AND OR
  124. //
  125. // There is an issue on whether the arguments should be values of references,
  126. // for example IF (FOO AND BAR) should that compare the strings FOO and BAR
  127. // or should it really do IF (${FOO} AND ${BAR}) Currently EXISTS COMMAND and
  128. // DEFINED all take values. EQUAL, LESS and GREATER can take numeric values or
  129. // variable names. STRLESS and STRGREATER take variable names but if the
  130. // variable name is not found it will use the name directly. AND OR take
  131. // variables or the values 0 or 1.
  132. bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
  133. bool &isValid, const cmMakefile *makefile)
  134. {
  135. // check for the different signatures
  136. isValid = false;
  137. const char *def;
  138. const char *def2;
  139. // handle empty invocation
  140. if (args.size() < 1)
  141. {
  142. isValid = true;
  143. return false;
  144. }
  145. // this is a super ugly hack. Basically old versiosn of VTK and ITK have a
  146. // bad test to check for more recent versions of CMake in the
  147. // CMakeLists.txt file for libtiff. So when we reved CMake up to 2.0 the
  148. // test started failing because the minor version went to zero this causes
  149. // the test to pass
  150. if (args.size() == 3 &&
  151. (makefile->GetDefinition("VTKTIFF_SOURCE_DIR") ||
  152. makefile->GetDefinition("ITKTIFF_SOURCE_DIR")) &&
  153. args[0] == "CMAKE_MINOR_VERSION" &&
  154. args[1] == "MATCHES")
  155. {
  156. isValid = true;
  157. return true;
  158. }
  159. // store the reduced args in this vector
  160. std::list<std::string> newArgs;
  161. int reducible;
  162. unsigned int i;
  163. // copy to the list structure
  164. for(i = 0; i < args.size(); ++i)
  165. {
  166. newArgs.push_back(args[i]);
  167. }
  168. std::list<std::string>::iterator argP1;
  169. std::list<std::string>::iterator argP2;
  170. // now loop through the arguments and see if we can reduce any of them
  171. // we do this multiple times. Once for each level of precedence
  172. do
  173. {
  174. reducible = 0;
  175. std::list<std::string>::iterator arg = newArgs.begin();
  176. while (arg != newArgs.end())
  177. {
  178. argP1 = arg;
  179. argP1++;
  180. argP2 = argP1;
  181. argP2++;
  182. // does a file exist
  183. if (*arg == "EXISTS" && argP1 != newArgs.end())
  184. {
  185. if(cmSystemTools::FileExists((argP1)->c_str()))
  186. {
  187. *arg = "1";
  188. }
  189. else
  190. {
  191. *arg = "0";
  192. }
  193. newArgs.erase(argP1);
  194. argP1 = arg;
  195. argP1++;
  196. argP2 = argP1;
  197. argP2++;
  198. reducible = 1;
  199. }
  200. // does a command exist
  201. if (*arg == "COMMAND" && argP1 != newArgs.end())
  202. {
  203. if(makefile->CommandExists((argP1)->c_str()))
  204. {
  205. *arg = "1";
  206. }
  207. else
  208. {
  209. *arg = "0";
  210. }
  211. newArgs.erase(argP1);
  212. argP1 = arg;
  213. argP1++;
  214. argP2 = argP1;
  215. argP2++;
  216. reducible = 1;
  217. }
  218. // is a variable defined
  219. if (*arg == "DEFINED" && argP1 != newArgs.end())
  220. {
  221. def = makefile->GetDefinition((argP1)->c_str());
  222. if(def)
  223. {
  224. *arg = "1";
  225. }
  226. else
  227. {
  228. *arg = "0";
  229. }
  230. newArgs.erase(argP1);
  231. argP1 = arg;
  232. argP1++;
  233. argP2 = argP1;
  234. argP2++;
  235. reducible = 1;
  236. }
  237. ++arg;
  238. }
  239. }
  240. while (reducible);
  241. // now loop through the arguments and see if we can reduce any of them
  242. // we do this multiple times. Once for each level of precedence
  243. do
  244. {
  245. reducible = 0;
  246. std::list<std::string>::iterator arg = newArgs.begin();
  247. while (arg != newArgs.end())
  248. {
  249. argP1 = arg;
  250. argP1++;
  251. argP2 = argP1;
  252. argP2++;
  253. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  254. *(argP1) == "MATCHES")
  255. {
  256. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  257. cmsys::RegularExpression regEntry((argP2)->c_str());
  258. if (regEntry.find(def))
  259. {
  260. *arg = "1";
  261. }
  262. else
  263. {
  264. *arg = "0";
  265. }
  266. newArgs.erase(argP2);
  267. newArgs.erase(argP1);
  268. argP1 = arg;
  269. argP1++;
  270. argP2 = argP1;
  271. argP2++;
  272. reducible = 1;
  273. }
  274. if (argP1 != newArgs.end() && *arg == "MATCHES")
  275. {
  276. *arg = "0";
  277. newArgs.erase(argP1);
  278. argP1 = arg;
  279. argP1++;
  280. argP2 = argP1;
  281. argP2++;
  282. reducible = 1;
  283. }
  284. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  285. (*(argP1) == "LESS" || *(argP1) == "GREATER" ||
  286. *(argP1) == "EQUAL"))
  287. {
  288. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  289. def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
  290. if (*(argP1) == "LESS")
  291. {
  292. if(atof(def) < atof(def2))
  293. {
  294. *arg = "1";
  295. }
  296. else
  297. {
  298. *arg = "0";
  299. }
  300. }
  301. else if (*(argP1) == "GREATER")
  302. {
  303. if(atof(def) > atof(def2))
  304. {
  305. *arg = "1";
  306. }
  307. else
  308. {
  309. *arg = "0";
  310. }
  311. }
  312. else
  313. {
  314. if(atof(def) == atof(def2))
  315. {
  316. *arg = "1";
  317. }
  318. else
  319. {
  320. *arg = "0";
  321. }
  322. }
  323. newArgs.erase(argP2);
  324. newArgs.erase(argP1);
  325. argP1 = arg;
  326. argP1++;
  327. argP2 = argP1;
  328. argP2++;
  329. reducible = 1;
  330. }
  331. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  332. (*(argP1) == "STRLESS" ||
  333. *(argP1) == "STREQUAL" ||
  334. *(argP1) == "STRGREATER"))
  335. {
  336. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  337. def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
  338. int val = strcmp(def,def2);
  339. int result;
  340. if (*(argP1) == "STRLESS")
  341. {
  342. result = (val < 0);
  343. }
  344. else if (*(argP1) == "STRGREATER")
  345. {
  346. result = (val > 0);
  347. }
  348. else // strequal
  349. {
  350. result = (val == 0);
  351. }
  352. if(result)
  353. {
  354. *arg = "1";
  355. }
  356. else
  357. {
  358. *arg = "0";
  359. }
  360. newArgs.erase(argP2);
  361. newArgs.erase(argP1);
  362. argP1 = arg;
  363. argP1++;
  364. argP2 = argP1;
  365. argP2++;
  366. reducible = 1;
  367. }
  368. ++arg;
  369. }
  370. }
  371. while (reducible);
  372. // now loop through the arguments and see if we can reduce any of them
  373. // we do this multiple times. Once for each level of precedence
  374. do
  375. {
  376. reducible = 0;
  377. std::list<std::string>::iterator arg = newArgs.begin();
  378. while (arg != newArgs.end())
  379. {
  380. argP1 = arg;
  381. argP1++;
  382. argP2 = argP1;
  383. argP2++;
  384. if (argP1 != newArgs.end() && *arg == "NOT")
  385. {
  386. def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
  387. if(!cmSystemTools::IsOff(def))
  388. {
  389. *arg = "0";
  390. }
  391. else
  392. {
  393. *arg = "1";
  394. }
  395. newArgs.erase(argP1);
  396. argP1 = arg;
  397. argP1++;
  398. argP2 = argP1;
  399. argP2++;
  400. reducible = 1;
  401. }
  402. ++arg;
  403. }
  404. }
  405. while (reducible);
  406. // now loop through the arguments and see if we can reduce any of them
  407. // we do this multiple times. Once for each level of precedence
  408. do
  409. {
  410. reducible = 0;
  411. std::list<std::string>::iterator arg = newArgs.begin();
  412. while (arg != newArgs.end())
  413. {
  414. argP1 = arg;
  415. argP1++;
  416. argP2 = argP1;
  417. argP2++;
  418. if (argP1 != newArgs.end() && *(argP1) == "AND" &&
  419. argP2 != newArgs.end())
  420. {
  421. def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
  422. def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
  423. if(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2))
  424. {
  425. *arg = "0";
  426. }
  427. else
  428. {
  429. *arg = "1";
  430. }
  431. newArgs.erase(argP2);
  432. newArgs.erase(argP1);
  433. argP1 = arg;
  434. argP1++;
  435. argP2 = argP1;
  436. argP2++;
  437. reducible = 1;
  438. }
  439. if (argP1 != newArgs.end() && *(argP1) == "OR" &&
  440. argP2 != newArgs.end())
  441. {
  442. def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
  443. def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
  444. if(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2))
  445. {
  446. *arg = "0";
  447. }
  448. else
  449. {
  450. *arg = "1";
  451. }
  452. newArgs.erase(argP2);
  453. newArgs.erase(argP1);
  454. argP1 = arg;
  455. argP1++;
  456. argP2 = argP1;
  457. argP2++;
  458. reducible = 1;
  459. }
  460. ++arg;
  461. }
  462. }
  463. while (reducible);
  464. // now at the end there should only be one argument left
  465. if (newArgs.size() == 1)
  466. {
  467. isValid = true;
  468. if (*newArgs.begin() == "0")
  469. {
  470. return false;
  471. }
  472. if (*newArgs.begin() == "1")
  473. {
  474. return true;
  475. }
  476. def = makefile->GetDefinition(args[0].c_str());
  477. if(cmSystemTools::IsOff(def))
  478. {
  479. return false;
  480. }
  481. }
  482. return true;
  483. }
  484. const char* cmIfCommand::GetVariableOrString(const char* str,
  485. const cmMakefile* mf)
  486. {
  487. const char* def = mf->GetDefinition(str);
  488. if(!def)
  489. {
  490. def = str;
  491. }
  492. return def;
  493. }
  494. const char* cmIfCommand::GetVariableOrNumber(const char* str,
  495. const cmMakefile* mf)
  496. {
  497. const char* def = mf->GetDefinition(str);
  498. if(!def)
  499. {
  500. if (atoi(str))
  501. {
  502. def = str;
  503. }
  504. }
  505. return def;
  506. }