cmIfCommand.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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. char* errorString = 0;
  96. std::vector<std::string> expandedArguments;
  97. m_Makefile->ExpandArguments(args, expandedArguments);
  98. bool isTrue = cmIfCommand::IsTrue(expandedArguments,&errorString,m_Makefile);
  99. if (errorString)
  100. {
  101. std::string err = "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. err += "(";
  111. err += errorString;
  112. err += ").";
  113. this->SetError(err.c_str());
  114. return false;
  115. }
  116. cmIfFunctionBlocker *f = new cmIfFunctionBlocker();
  117. // if is isn't true block the commands
  118. f->m_IsBlocking = !isTrue;
  119. f->m_Args = args;
  120. m_Makefile->AddFunctionBlocker(f);
  121. return true;
  122. }
  123. // order of operations,
  124. // EXISTS COMMAND DEFINED
  125. // MATCHES LESS GREATER EQUAL STRLESS STRGREATER STREQUAL
  126. // AND OR
  127. //
  128. // There is an issue on whether the arguments should be values of references,
  129. // for example IF (FOO AND BAR) should that compare the strings FOO and BAR
  130. // or should it really do IF (${FOO} AND ${BAR}) Currently EXISTS COMMAND and
  131. // DEFINED all take values. EQUAL, LESS and GREATER can take numeric values or
  132. // variable names. STRLESS and STRGREATER take variable names but if the
  133. // variable name is not found it will use the name directly. AND OR take
  134. // variables or the values 0 or 1.
  135. bool cmIfCommand::IsTrue(const std::vector<std::string> &args,
  136. char **errorString, const cmMakefile *makefile)
  137. {
  138. // check for the different signatures
  139. *errorString = "Unknown arguments specified";
  140. const char *def;
  141. const char *def2;
  142. // handle empty invocation
  143. if (args.size() < 1)
  144. {
  145. *errorString = 0;
  146. return false;
  147. }
  148. // this is a super ugly hack. Basically old versiosn of VTK and ITK have a
  149. // bad test to check for more recent versions of CMake in the
  150. // CMakeLists.txt file for libtiff. So when we reved CMake up to 2.0 the
  151. // test started failing because the minor version went to zero this causes
  152. // the test to pass
  153. if (args.size() == 3 &&
  154. (makefile->GetDefinition("VTKTIFF_SOURCE_DIR") ||
  155. makefile->GetDefinition("ITKTIFF_SOURCE_DIR")) &&
  156. args[0] == "CMAKE_MINOR_VERSION" &&
  157. args[1] == "MATCHES")
  158. {
  159. *errorString = 0;
  160. return true;
  161. }
  162. // store the reduced args in this vector
  163. std::list<std::string> newArgs;
  164. int reducible;
  165. unsigned int i;
  166. // copy to the list structure
  167. for(i = 0; i < args.size(); ++i)
  168. {
  169. newArgs.push_back(args[i]);
  170. }
  171. std::list<std::string>::iterator argP1;
  172. std::list<std::string>::iterator argP2;
  173. // now loop through the arguments and see if we can reduce any of them
  174. // we do this multiple times. Once for each level of precedence
  175. do
  176. {
  177. reducible = 0;
  178. std::list<std::string>::iterator arg = newArgs.begin();
  179. while (arg != newArgs.end())
  180. {
  181. argP1 = arg;
  182. argP1++;
  183. argP2 = argP1;
  184. argP2++;
  185. // does a file exist
  186. if (*arg == "EXISTS" && argP1 != newArgs.end())
  187. {
  188. if(cmSystemTools::FileExists((argP1)->c_str()))
  189. {
  190. *arg = "1";
  191. }
  192. else
  193. {
  194. *arg = "0";
  195. }
  196. newArgs.erase(argP1);
  197. argP1 = arg;
  198. argP1++;
  199. argP2 = argP1;
  200. argP2++;
  201. reducible = 1;
  202. }
  203. // does a command exist
  204. if (*arg == "COMMAND" && argP1 != newArgs.end())
  205. {
  206. if(makefile->CommandExists((argP1)->c_str()))
  207. {
  208. *arg = "1";
  209. }
  210. else
  211. {
  212. *arg = "0";
  213. }
  214. newArgs.erase(argP1);
  215. argP1 = arg;
  216. argP1++;
  217. argP2 = argP1;
  218. argP2++;
  219. reducible = 1;
  220. }
  221. // is a variable defined
  222. if (*arg == "DEFINED" && argP1 != newArgs.end())
  223. {
  224. def = makefile->GetDefinition((argP1)->c_str());
  225. if(def)
  226. {
  227. *arg = "1";
  228. }
  229. else
  230. {
  231. *arg = "0";
  232. }
  233. newArgs.erase(argP1);
  234. argP1 = arg;
  235. argP1++;
  236. argP2 = argP1;
  237. argP2++;
  238. reducible = 1;
  239. }
  240. ++arg;
  241. }
  242. }
  243. while (reducible);
  244. // now loop through the arguments and see if we can reduce any of them
  245. // we do this multiple times. Once for each level of precedence
  246. do
  247. {
  248. reducible = 0;
  249. std::list<std::string>::iterator arg = newArgs.begin();
  250. while (arg != newArgs.end())
  251. {
  252. argP1 = arg;
  253. argP1++;
  254. argP2 = argP1;
  255. argP2++;
  256. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  257. *(argP1) == "MATCHES")
  258. {
  259. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  260. const char* rex = (argP2)->c_str();
  261. cmsys::RegularExpression regEntry;
  262. if ( !regEntry.compile(rex) )
  263. {
  264. cmOStringStream error;
  265. error << "Regular expression \"" << rex << "\" cannot compile";
  266. *errorString = new char[error.str().size() + 1];
  267. strcpy(*errorString, error.str().c_str());
  268. return false;
  269. }
  270. if (regEntry.find(def))
  271. {
  272. *arg = "1";
  273. }
  274. else
  275. {
  276. *arg = "0";
  277. }
  278. newArgs.erase(argP2);
  279. newArgs.erase(argP1);
  280. argP1 = arg;
  281. argP1++;
  282. argP2 = argP1;
  283. argP2++;
  284. reducible = 1;
  285. }
  286. if (argP1 != newArgs.end() && *arg == "MATCHES")
  287. {
  288. *arg = "0";
  289. newArgs.erase(argP1);
  290. argP1 = arg;
  291. argP1++;
  292. argP2 = argP1;
  293. argP2++;
  294. reducible = 1;
  295. }
  296. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  297. (*(argP1) == "LESS" || *(argP1) == "GREATER" ||
  298. *(argP1) == "EQUAL"))
  299. {
  300. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  301. def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
  302. if (*(argP1) == "LESS")
  303. {
  304. if(atof(def) < atof(def2))
  305. {
  306. *arg = "1";
  307. }
  308. else
  309. {
  310. *arg = "0";
  311. }
  312. }
  313. else if (*(argP1) == "GREATER")
  314. {
  315. if(atof(def) > atof(def2))
  316. {
  317. *arg = "1";
  318. }
  319. else
  320. {
  321. *arg = "0";
  322. }
  323. }
  324. else
  325. {
  326. if(atof(def) == atof(def2))
  327. {
  328. *arg = "1";
  329. }
  330. else
  331. {
  332. *arg = "0";
  333. }
  334. }
  335. newArgs.erase(argP2);
  336. newArgs.erase(argP1);
  337. argP1 = arg;
  338. argP1++;
  339. argP2 = argP1;
  340. argP2++;
  341. reducible = 1;
  342. }
  343. if (argP1 != newArgs.end() && argP2 != newArgs.end() &&
  344. (*(argP1) == "STRLESS" ||
  345. *(argP1) == "STREQUAL" ||
  346. *(argP1) == "STRGREATER"))
  347. {
  348. def = cmIfCommand::GetVariableOrString(arg->c_str(), makefile);
  349. def2 = cmIfCommand::GetVariableOrString((argP2)->c_str(), makefile);
  350. int val = strcmp(def,def2);
  351. int result;
  352. if (*(argP1) == "STRLESS")
  353. {
  354. result = (val < 0);
  355. }
  356. else if (*(argP1) == "STRGREATER")
  357. {
  358. result = (val > 0);
  359. }
  360. else // strequal
  361. {
  362. result = (val == 0);
  363. }
  364. if(result)
  365. {
  366. *arg = "1";
  367. }
  368. else
  369. {
  370. *arg = "0";
  371. }
  372. newArgs.erase(argP2);
  373. newArgs.erase(argP1);
  374. argP1 = arg;
  375. argP1++;
  376. argP2 = argP1;
  377. argP2++;
  378. reducible = 1;
  379. }
  380. ++arg;
  381. }
  382. }
  383. while (reducible);
  384. // now loop through the arguments and see if we can reduce any of them
  385. // we do this multiple times. Once for each level of precedence
  386. do
  387. {
  388. reducible = 0;
  389. std::list<std::string>::iterator arg = newArgs.begin();
  390. while (arg != newArgs.end())
  391. {
  392. argP1 = arg;
  393. argP1++;
  394. argP2 = argP1;
  395. argP2++;
  396. if (argP1 != newArgs.end() && *arg == "NOT")
  397. {
  398. def = cmIfCommand::GetVariableOrNumber((argP1)->c_str(), makefile);
  399. if(!cmSystemTools::IsOff(def))
  400. {
  401. *arg = "0";
  402. }
  403. else
  404. {
  405. *arg = "1";
  406. }
  407. newArgs.erase(argP1);
  408. argP1 = arg;
  409. argP1++;
  410. argP2 = argP1;
  411. argP2++;
  412. reducible = 1;
  413. }
  414. ++arg;
  415. }
  416. }
  417. while (reducible);
  418. // now loop through the arguments and see if we can reduce any of them
  419. // we do this multiple times. Once for each level of precedence
  420. do
  421. {
  422. reducible = 0;
  423. std::list<std::string>::iterator arg = newArgs.begin();
  424. while (arg != newArgs.end())
  425. {
  426. argP1 = arg;
  427. argP1++;
  428. argP2 = argP1;
  429. argP2++;
  430. if (argP1 != newArgs.end() && *(argP1) == "AND" &&
  431. argP2 != newArgs.end())
  432. {
  433. def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
  434. def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
  435. if(cmSystemTools::IsOff(def) || cmSystemTools::IsOff(def2))
  436. {
  437. *arg = "0";
  438. }
  439. else
  440. {
  441. *arg = "1";
  442. }
  443. newArgs.erase(argP2);
  444. newArgs.erase(argP1);
  445. argP1 = arg;
  446. argP1++;
  447. argP2 = argP1;
  448. argP2++;
  449. reducible = 1;
  450. }
  451. if (argP1 != newArgs.end() && *(argP1) == "OR" &&
  452. argP2 != newArgs.end())
  453. {
  454. def = cmIfCommand::GetVariableOrNumber(arg->c_str(), makefile);
  455. def2 = cmIfCommand::GetVariableOrNumber((argP2)->c_str(), makefile);
  456. if(cmSystemTools::IsOff(def) && cmSystemTools::IsOff(def2))
  457. {
  458. *arg = "0";
  459. }
  460. else
  461. {
  462. *arg = "1";
  463. }
  464. newArgs.erase(argP2);
  465. newArgs.erase(argP1);
  466. argP1 = arg;
  467. argP1++;
  468. argP2 = argP1;
  469. argP2++;
  470. reducible = 1;
  471. }
  472. ++arg;
  473. }
  474. }
  475. while (reducible);
  476. // now at the end there should only be one argument left
  477. if (newArgs.size() == 1)
  478. {
  479. *errorString = 0;
  480. if (*newArgs.begin() == "0")
  481. {
  482. return false;
  483. }
  484. if (*newArgs.begin() == "1")
  485. {
  486. return true;
  487. }
  488. def = makefile->GetDefinition(args[0].c_str());
  489. if(cmSystemTools::IsOff(def))
  490. {
  491. return false;
  492. }
  493. }
  494. return true;
  495. }
  496. const char* cmIfCommand::GetVariableOrString(const char* str,
  497. const cmMakefile* mf)
  498. {
  499. const char* def = mf->GetDefinition(str);
  500. if(!def)
  501. {
  502. def = str;
  503. }
  504. return def;
  505. }
  506. const char* cmIfCommand::GetVariableOrNumber(const char* str,
  507. const cmMakefile* mf)
  508. {
  509. const char* def = mf->GetDefinition(str);
  510. if(!def)
  511. {
  512. if (atoi(str))
  513. {
  514. def = str;
  515. }
  516. }
  517. return def;
  518. }