cmIfCommand.cxx 14 KB

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