cmListCommand.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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 "cmListCommand.h"
  14. #include <cmsys/RegularExpression.hxx>
  15. #include <cmsys/SystemTools.hxx>
  16. #include <stdlib.h> // required for atoi
  17. #include <ctype.h>
  18. //----------------------------------------------------------------------------
  19. bool cmListCommand
  20. ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  21. {
  22. if(args.size() < 1)
  23. {
  24. this->SetError("must be called with at least one argument.");
  25. return false;
  26. }
  27. const std::string &subCommand = args[0];
  28. if(subCommand == "LENGTH")
  29. {
  30. return this->HandleLengthCommand(args);
  31. }
  32. if(subCommand == "GET")
  33. {
  34. return this->HandleGetCommand(args);
  35. }
  36. if(subCommand == "APPEND")
  37. {
  38. return this->HandleAppendCommand(args);
  39. }
  40. if(subCommand == "FIND")
  41. {
  42. return this->HandleFindCommand(args);
  43. }
  44. if(subCommand == "INSERT")
  45. {
  46. return this->HandleInsertCommand(args);
  47. }
  48. if(subCommand == "REMOVE_AT")
  49. {
  50. return this->HandleRemoveAtCommand(args);
  51. }
  52. if(subCommand == "REMOVE_ITEM")
  53. {
  54. return this->HandleRemoveItemCommand(args);
  55. }
  56. if(subCommand == "REMOVE_DUPLICATES")
  57. {
  58. return this->HandleRemoveDuplicatesCommand(args);
  59. }
  60. if(subCommand == "SORT")
  61. {
  62. return this->HandleSortCommand(args);
  63. }
  64. if(subCommand == "REVERSE")
  65. {
  66. return this->HandleReverseCommand(args);
  67. }
  68. std::string e = "does not recognize sub-command "+subCommand;
  69. this->SetError(e.c_str());
  70. return false;
  71. }
  72. //----------------------------------------------------------------------------
  73. bool cmListCommand::GetListString(std::string& listString, const char* var)
  74. {
  75. if ( !var )
  76. {
  77. return false;
  78. }
  79. // get the old value
  80. const char* cacheValue
  81. = this->Makefile->GetDefinition(var);
  82. if(!cacheValue)
  83. {
  84. return false;
  85. }
  86. listString = cacheValue;
  87. return true;
  88. }
  89. //----------------------------------------------------------------------------
  90. bool cmListCommand::GetList(std::vector<std::string>& list, const char* var)
  91. {
  92. std::string listString;
  93. if ( !this->GetListString(listString, var) )
  94. {
  95. return false;
  96. }
  97. // if the size of the list
  98. if(listString.size() == 0)
  99. {
  100. return true;
  101. }
  102. // expand the variable into a list
  103. cmSystemTools::ExpandListArgument(listString, list, true);
  104. // check the list for empty values
  105. bool hasEmpty = false;
  106. for(std::vector<std::string>::iterator i = list.begin();
  107. i != list.end(); ++i)
  108. {
  109. if(i->size() == 0)
  110. {
  111. hasEmpty = true;
  112. break;
  113. }
  114. }
  115. // if no empty elements then just return
  116. if(!hasEmpty)
  117. {
  118. return true;
  119. }
  120. // if we have empty elements we need to check policy CMP0007
  121. switch(this->Makefile->GetPolicyStatus(cmPolicies::CMP0007))
  122. {
  123. case cmPolicies::WARN:
  124. {
  125. // Default is to warn and use old behavior
  126. // OLD behavior is to allow compatibility, so recall
  127. // ExpandListArgument without the true which will remove
  128. // empty values
  129. list.clear();
  130. cmSystemTools::ExpandListArgument(listString, list);
  131. std::string warn = this->Makefile->GetPolicies()->
  132. GetPolicyWarning(cmPolicies::CMP0007);
  133. warn += " List has value = [";
  134. warn += listString;
  135. warn += "].";
  136. this->Makefile->IssueMessage(cmake::AUTHOR_WARNING,
  137. warn);
  138. return true;
  139. }
  140. case cmPolicies::OLD:
  141. // OLD behavior is to allow compatibility, so recall
  142. // ExpandListArgument without the true which will remove
  143. // empty values
  144. list.clear();
  145. cmSystemTools::ExpandListArgument(listString, list);
  146. return true;
  147. case cmPolicies::NEW:
  148. return true;
  149. case cmPolicies::REQUIRED_IF_USED:
  150. case cmPolicies::REQUIRED_ALWAYS:
  151. this->Makefile->IssueMessage(
  152. cmake::FATAL_ERROR,
  153. this->Makefile->GetPolicies()
  154. ->GetRequiredPolicyError(cmPolicies::CMP0007)
  155. );
  156. return false;
  157. }
  158. return true;
  159. }
  160. //----------------------------------------------------------------------------
  161. bool cmListCommand::HandleLengthCommand(std::vector<std::string> const& args)
  162. {
  163. if(args.size() != 3)
  164. {
  165. this->SetError("sub-command LENGTH requires two arguments.");
  166. return false;
  167. }
  168. const std::string& listName = args[1];
  169. const std::string& variableName = args[args.size() - 1];
  170. std::vector<std::string> varArgsExpanded;
  171. // do not check the return value here
  172. // if the list var is not found varArgsExpanded will have size 0
  173. // and we will return 0
  174. this->GetList(varArgsExpanded, listName.c_str());
  175. size_t length = varArgsExpanded.size();
  176. char buffer[1024];
  177. sprintf(buffer, "%d", static_cast<int>(length));
  178. this->Makefile->AddDefinition(variableName.c_str(), buffer);
  179. return true;
  180. }
  181. //----------------------------------------------------------------------------
  182. bool cmListCommand::HandleGetCommand(std::vector<std::string> const& args)
  183. {
  184. if(args.size() < 4)
  185. {
  186. this->SetError("sub-command GET requires at least three arguments.");
  187. return false;
  188. }
  189. const std::string& listName = args[1];
  190. const std::string& variableName = args[args.size() - 1];
  191. // expand the variable
  192. std::vector<std::string> varArgsExpanded;
  193. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  194. {
  195. this->Makefile->AddDefinition(variableName.c_str(), "NOTFOUND");
  196. return true;
  197. }
  198. std::string value;
  199. size_t cc;
  200. const char* sep = "";
  201. for ( cc = 2; cc < args.size()-1; cc ++ )
  202. {
  203. int item = atoi(args[cc].c_str());
  204. value += sep;
  205. sep = ";";
  206. size_t nitem = varArgsExpanded.size();
  207. if ( item < 0 )
  208. {
  209. item = (int)nitem + item;
  210. }
  211. if ( item < 0 || nitem <= (size_t)item )
  212. {
  213. cmOStringStream str;
  214. str << "index: " << item << " out of range (-"
  215. << varArgsExpanded.size() << ", "
  216. << varArgsExpanded.size()-1 << ")";
  217. this->SetError(str.str().c_str());
  218. return false;
  219. }
  220. value += varArgsExpanded[item];
  221. }
  222. this->Makefile->AddDefinition(variableName.c_str(), value.c_str());
  223. return true;
  224. }
  225. //----------------------------------------------------------------------------
  226. bool cmListCommand::HandleAppendCommand(std::vector<std::string> const& args)
  227. {
  228. if(args.size() < 2)
  229. {
  230. this->SetError("sub-command APPEND requires at least one argument.");
  231. return false;
  232. }
  233. // Skip if nothing to append.
  234. if(args.size() < 3)
  235. {
  236. return true;
  237. }
  238. const std::string& listName = args[1];
  239. // expand the variable
  240. std::string listString;
  241. this->GetListString(listString, listName.c_str());
  242. size_t cc;
  243. const char* sep = "";
  244. for ( cc = 2; cc < args.size(); ++ cc )
  245. {
  246. listString += sep;
  247. sep = ";";
  248. listString += args[cc];
  249. }
  250. this->Makefile->AddDefinition(listName.c_str(), listString.c_str());
  251. return true;
  252. }
  253. //----------------------------------------------------------------------------
  254. bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
  255. {
  256. if(args.size() != 4)
  257. {
  258. this->SetError("sub-command FIND requires three arguments.");
  259. return false;
  260. }
  261. const std::string& listName = args[1];
  262. const std::string& variableName = args[args.size() - 1];
  263. // expand the variable
  264. std::vector<std::string> varArgsExpanded;
  265. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  266. {
  267. this->Makefile->AddDefinition(variableName.c_str(), "-1");
  268. return true;
  269. }
  270. std::vector<std::string>::iterator it;
  271. unsigned int index = 0;
  272. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  273. {
  274. if ( *it == args[2] )
  275. {
  276. char indexString[32];
  277. sprintf(indexString, "%d", index);
  278. this->Makefile->AddDefinition(variableName.c_str(), indexString);
  279. return true;
  280. }
  281. index++;
  282. }
  283. this->Makefile->AddDefinition(variableName.c_str(), "-1");
  284. return true;
  285. }
  286. //----------------------------------------------------------------------------
  287. bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args)
  288. {
  289. if(args.size() < 4)
  290. {
  291. this->SetError("sub-command INSERT requires at least three arguments.");
  292. return false;
  293. }
  294. const std::string& listName = args[1];
  295. // expand the variable
  296. int item = atoi(args[2].c_str());
  297. std::vector<std::string> varArgsExpanded;
  298. if ( !this->GetList(varArgsExpanded, listName.c_str()) && item != 0)
  299. {
  300. cmOStringStream str;
  301. str << "index: " << item << " out of range (0, 0)";
  302. this->SetError(str.str().c_str());
  303. return false;
  304. }
  305. if ( varArgsExpanded.size() != 0 )
  306. {
  307. size_t nitem = varArgsExpanded.size();
  308. if ( item < 0 )
  309. {
  310. item = (int)nitem + item;
  311. }
  312. if ( item < 0 || nitem <= (size_t)item )
  313. {
  314. cmOStringStream str;
  315. str << "index: " << item << " out of range (-"
  316. << varArgsExpanded.size() << ", "
  317. << (varArgsExpanded.size() == 0?0:(varArgsExpanded.size()-1)) << ")";
  318. this->SetError(str.str().c_str());
  319. return false;
  320. }
  321. }
  322. size_t cc;
  323. size_t cnt = 0;
  324. for ( cc = 3; cc < args.size(); ++ cc )
  325. {
  326. varArgsExpanded.insert(varArgsExpanded.begin()+item+cnt, args[cc]);
  327. cnt ++;
  328. }
  329. std::string value;
  330. const char* sep = "";
  331. for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
  332. {
  333. value += sep;
  334. value += varArgsExpanded[cc];
  335. sep = ";";
  336. }
  337. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  338. return true;
  339. }
  340. //----------------------------------------------------------------------------
  341. bool cmListCommand
  342. ::HandleRemoveItemCommand(std::vector<std::string> const& args)
  343. {
  344. if(args.size() < 3)
  345. {
  346. this->SetError("sub-command REMOVE_ITEM requires two or more arguments.");
  347. return false;
  348. }
  349. const std::string& listName = args[1];
  350. // expand the variable
  351. std::vector<std::string> varArgsExpanded;
  352. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  353. {
  354. this->SetError("sub-command REMOVE_ITEM requires list to be present.");
  355. return false;
  356. }
  357. size_t cc;
  358. for ( cc = 2; cc < args.size(); ++ cc )
  359. {
  360. size_t kk = 0;
  361. while ( kk < varArgsExpanded.size() )
  362. {
  363. if ( varArgsExpanded[kk] == args[cc] )
  364. {
  365. varArgsExpanded.erase(varArgsExpanded.begin()+kk);
  366. }
  367. else
  368. {
  369. kk ++;
  370. }
  371. }
  372. }
  373. std::string value;
  374. const char* sep = "";
  375. for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
  376. {
  377. value += sep;
  378. value += varArgsExpanded[cc];
  379. sep = ";";
  380. }
  381. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  382. return true;
  383. }
  384. //----------------------------------------------------------------------------
  385. bool cmListCommand
  386. ::HandleReverseCommand(std::vector<std::string> const& args)
  387. {
  388. if(args.size() < 2)
  389. {
  390. this->SetError("sub-command REVERSE requires a list as an argument.");
  391. return false;
  392. }
  393. const std::string& listName = args[1];
  394. // expand the variable
  395. std::vector<std::string> varArgsExpanded;
  396. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  397. {
  398. this->SetError("sub-command REVERSE requires list to be present.");
  399. return false;
  400. }
  401. std::string value;
  402. std::vector<std::string>::reverse_iterator it;
  403. const char* sep = "";
  404. for ( it = varArgsExpanded.rbegin(); it != varArgsExpanded.rend(); ++ it )
  405. {
  406. value += sep;
  407. value += it->c_str();
  408. sep = ";";
  409. }
  410. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  411. return true;
  412. }
  413. //----------------------------------------------------------------------------
  414. bool cmListCommand
  415. ::HandleRemoveDuplicatesCommand(std::vector<std::string> const& args)
  416. {
  417. if(args.size() < 2)
  418. {
  419. this->SetError(
  420. "sub-command REMOVE_DUPLICATES requires a list as an argument.");
  421. return false;
  422. }
  423. const std::string& listName = args[1];
  424. // expand the variable
  425. std::vector<std::string> varArgsExpanded;
  426. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  427. {
  428. this->SetError(
  429. "sub-command REMOVE_DUPLICATES requires list to be present.");
  430. return false;
  431. }
  432. std::string value;
  433. std::set<std::string> unique;
  434. std::vector<std::string>::iterator it;
  435. const char* sep = "";
  436. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  437. {
  438. if (unique.find(*it) != unique.end())
  439. {
  440. continue;
  441. }
  442. unique.insert(*it);
  443. value += sep;
  444. value += it->c_str();
  445. sep = ";";
  446. }
  447. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  448. return true;
  449. }
  450. //----------------------------------------------------------------------------
  451. bool cmListCommand
  452. ::HandleSortCommand(std::vector<std::string> const& args)
  453. {
  454. if(args.size() < 2)
  455. {
  456. this->SetError("sub-command SORT requires a list as an argument.");
  457. return false;
  458. }
  459. const std::string& listName = args[1];
  460. // expand the variable
  461. std::vector<std::string> varArgsExpanded;
  462. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  463. {
  464. this->SetError("sub-command SORT requires list to be present.");
  465. return false;
  466. }
  467. std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
  468. std::string value;
  469. std::vector<std::string>::iterator it;
  470. const char* sep = "";
  471. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  472. {
  473. value += sep;
  474. value += it->c_str();
  475. sep = ";";
  476. }
  477. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  478. return true;
  479. }
  480. //----------------------------------------------------------------------------
  481. bool cmListCommand::HandleRemoveAtCommand(
  482. std::vector<std::string> const& args)
  483. {
  484. if(args.size() < 3)
  485. {
  486. this->SetError("sub-command REMOVE_AT requires at least "
  487. "two arguments.");
  488. return false;
  489. }
  490. const std::string& listName = args[1];
  491. // expand the variable
  492. std::vector<std::string> varArgsExpanded;
  493. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  494. {
  495. this->SetError("sub-command REMOVE_AT requires list to be present.");
  496. return false;
  497. }
  498. size_t cc;
  499. std::vector<size_t> removed;
  500. for ( cc = 2; cc < args.size(); ++ cc )
  501. {
  502. int item = atoi(args[cc].c_str());
  503. size_t nitem = varArgsExpanded.size();
  504. if ( item < 0 )
  505. {
  506. item = (int)nitem + item;
  507. }
  508. if ( item < 0 || nitem <= (size_t)item )
  509. {
  510. cmOStringStream str;
  511. str << "index: " << item << " out of range (-"
  512. << varArgsExpanded.size() << ", "
  513. << varArgsExpanded.size()-1 << ")";
  514. this->SetError(str.str().c_str());
  515. return false;
  516. }
  517. removed.push_back(static_cast<size_t>(item));
  518. }
  519. std::string value;
  520. const char* sep = "";
  521. for ( cc = 0; cc < varArgsExpanded.size(); ++ cc )
  522. {
  523. size_t kk;
  524. bool found = false;
  525. for ( kk = 0; kk < removed.size(); ++ kk )
  526. {
  527. if ( cc == removed[kk] )
  528. {
  529. found = true;
  530. }
  531. }
  532. if ( !found )
  533. {
  534. value += sep;
  535. value += varArgsExpanded[cc];
  536. sep = ";";
  537. }
  538. }
  539. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  540. return true;
  541. }