cmListCommand.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  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. for ( cc = 2; cc < args.size(); ++ cc )
  244. {
  245. if(listString.size())
  246. {
  247. listString += ";";
  248. }
  249. listString += args[cc];
  250. }
  251. this->Makefile->AddDefinition(listName.c_str(), listString.c_str());
  252. return true;
  253. }
  254. //----------------------------------------------------------------------------
  255. bool cmListCommand::HandleFindCommand(std::vector<std::string> const& args)
  256. {
  257. if(args.size() != 4)
  258. {
  259. this->SetError("sub-command FIND requires three arguments.");
  260. return false;
  261. }
  262. const std::string& listName = args[1];
  263. const std::string& variableName = args[args.size() - 1];
  264. // expand the variable
  265. std::vector<std::string> varArgsExpanded;
  266. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  267. {
  268. this->Makefile->AddDefinition(variableName.c_str(), "-1");
  269. return true;
  270. }
  271. std::vector<std::string>::iterator it;
  272. unsigned int index = 0;
  273. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  274. {
  275. if ( *it == args[2] )
  276. {
  277. char indexString[32];
  278. sprintf(indexString, "%d", index);
  279. this->Makefile->AddDefinition(variableName.c_str(), indexString);
  280. return true;
  281. }
  282. index++;
  283. }
  284. this->Makefile->AddDefinition(variableName.c_str(), "-1");
  285. return true;
  286. }
  287. //----------------------------------------------------------------------------
  288. bool cmListCommand::HandleInsertCommand(std::vector<std::string> const& args)
  289. {
  290. if(args.size() < 4)
  291. {
  292. this->SetError("sub-command INSERT requires at least three arguments.");
  293. return false;
  294. }
  295. const std::string& listName = args[1];
  296. // expand the variable
  297. int item = atoi(args[2].c_str());
  298. std::vector<std::string> varArgsExpanded;
  299. if ( !this->GetList(varArgsExpanded, listName.c_str()) && item != 0)
  300. {
  301. cmOStringStream str;
  302. str << "index: " << item << " out of range (0, 0)";
  303. this->SetError(str.str().c_str());
  304. return false;
  305. }
  306. if ( varArgsExpanded.size() != 0 )
  307. {
  308. size_t nitem = varArgsExpanded.size();
  309. if ( item < 0 )
  310. {
  311. item = (int)nitem + item;
  312. }
  313. if ( item < 0 || nitem <= (size_t)item )
  314. {
  315. cmOStringStream str;
  316. str << "index: " << item << " out of range (-"
  317. << varArgsExpanded.size() << ", "
  318. << (varArgsExpanded.size() == 0?0:(varArgsExpanded.size()-1)) << ")";
  319. this->SetError(str.str().c_str());
  320. return false;
  321. }
  322. }
  323. size_t cc;
  324. size_t cnt = 0;
  325. for ( cc = 3; cc < args.size(); ++ cc )
  326. {
  327. varArgsExpanded.insert(varArgsExpanded.begin()+item+cnt, args[cc]);
  328. cnt ++;
  329. }
  330. std::string value;
  331. const char* sep = "";
  332. for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
  333. {
  334. value += sep;
  335. value += varArgsExpanded[cc];
  336. sep = ";";
  337. }
  338. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  339. return true;
  340. }
  341. //----------------------------------------------------------------------------
  342. bool cmListCommand
  343. ::HandleRemoveItemCommand(std::vector<std::string> const& args)
  344. {
  345. if(args.size() < 3)
  346. {
  347. this->SetError("sub-command REMOVE_ITEM requires two or more arguments.");
  348. return false;
  349. }
  350. const std::string& listName = args[1];
  351. // expand the variable
  352. std::vector<std::string> varArgsExpanded;
  353. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  354. {
  355. this->SetError("sub-command REMOVE_ITEM requires list to be present.");
  356. return false;
  357. }
  358. size_t cc;
  359. for ( cc = 2; cc < args.size(); ++ cc )
  360. {
  361. size_t kk = 0;
  362. while ( kk < varArgsExpanded.size() )
  363. {
  364. if ( varArgsExpanded[kk] == args[cc] )
  365. {
  366. varArgsExpanded.erase(varArgsExpanded.begin()+kk);
  367. }
  368. else
  369. {
  370. kk ++;
  371. }
  372. }
  373. }
  374. std::string value;
  375. const char* sep = "";
  376. for ( cc = 0; cc < varArgsExpanded.size(); cc ++ )
  377. {
  378. value += sep;
  379. value += varArgsExpanded[cc];
  380. sep = ";";
  381. }
  382. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  383. return true;
  384. }
  385. //----------------------------------------------------------------------------
  386. bool cmListCommand
  387. ::HandleReverseCommand(std::vector<std::string> const& args)
  388. {
  389. if(args.size() < 2)
  390. {
  391. this->SetError("sub-command REVERSE requires a list as an argument.");
  392. return false;
  393. }
  394. const std::string& listName = args[1];
  395. // expand the variable
  396. std::vector<std::string> varArgsExpanded;
  397. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  398. {
  399. this->SetError("sub-command REVERSE requires list to be present.");
  400. return false;
  401. }
  402. std::string value;
  403. std::vector<std::string>::reverse_iterator it;
  404. const char* sep = "";
  405. for ( it = varArgsExpanded.rbegin(); it != varArgsExpanded.rend(); ++ it )
  406. {
  407. value += sep;
  408. value += it->c_str();
  409. sep = ";";
  410. }
  411. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  412. return true;
  413. }
  414. //----------------------------------------------------------------------------
  415. bool cmListCommand
  416. ::HandleRemoveDuplicatesCommand(std::vector<std::string> const& args)
  417. {
  418. if(args.size() < 2)
  419. {
  420. this->SetError(
  421. "sub-command REMOVE_DUPLICATES requires a list as an argument.");
  422. return false;
  423. }
  424. const std::string& listName = args[1];
  425. // expand the variable
  426. std::vector<std::string> varArgsExpanded;
  427. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  428. {
  429. this->SetError(
  430. "sub-command REMOVE_DUPLICATES requires list to be present.");
  431. return false;
  432. }
  433. std::string value;
  434. std::set<std::string> unique;
  435. std::vector<std::string>::iterator it;
  436. const char* sep = "";
  437. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  438. {
  439. if (unique.find(*it) != unique.end())
  440. {
  441. continue;
  442. }
  443. unique.insert(*it);
  444. value += sep;
  445. value += it->c_str();
  446. sep = ";";
  447. }
  448. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  449. return true;
  450. }
  451. //----------------------------------------------------------------------------
  452. bool cmListCommand
  453. ::HandleSortCommand(std::vector<std::string> const& args)
  454. {
  455. if(args.size() < 2)
  456. {
  457. this->SetError("sub-command SORT requires a list as an argument.");
  458. return false;
  459. }
  460. const std::string& listName = args[1];
  461. // expand the variable
  462. std::vector<std::string> varArgsExpanded;
  463. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  464. {
  465. this->SetError("sub-command SORT requires list to be present.");
  466. return false;
  467. }
  468. std::sort(varArgsExpanded.begin(), varArgsExpanded.end());
  469. std::string value;
  470. std::vector<std::string>::iterator it;
  471. const char* sep = "";
  472. for ( it = varArgsExpanded.begin(); it != varArgsExpanded.end(); ++ it )
  473. {
  474. value += sep;
  475. value += it->c_str();
  476. sep = ";";
  477. }
  478. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  479. return true;
  480. }
  481. //----------------------------------------------------------------------------
  482. bool cmListCommand::HandleRemoveAtCommand(
  483. std::vector<std::string> const& args)
  484. {
  485. if(args.size() < 3)
  486. {
  487. this->SetError("sub-command REMOVE_AT requires at least "
  488. "two arguments.");
  489. return false;
  490. }
  491. const std::string& listName = args[1];
  492. // expand the variable
  493. std::vector<std::string> varArgsExpanded;
  494. if ( !this->GetList(varArgsExpanded, listName.c_str()) )
  495. {
  496. this->SetError("sub-command REMOVE_AT requires list to be present.");
  497. return false;
  498. }
  499. size_t cc;
  500. std::vector<size_t> removed;
  501. for ( cc = 2; cc < args.size(); ++ cc )
  502. {
  503. int item = atoi(args[cc].c_str());
  504. size_t nitem = varArgsExpanded.size();
  505. if ( item < 0 )
  506. {
  507. item = (int)nitem + item;
  508. }
  509. if ( item < 0 || nitem <= (size_t)item )
  510. {
  511. cmOStringStream str;
  512. str << "index: " << item << " out of range (-"
  513. << varArgsExpanded.size() << ", "
  514. << varArgsExpanded.size()-1 << ")";
  515. this->SetError(str.str().c_str());
  516. return false;
  517. }
  518. removed.push_back(static_cast<size_t>(item));
  519. }
  520. std::string value;
  521. const char* sep = "";
  522. for ( cc = 0; cc < varArgsExpanded.size(); ++ cc )
  523. {
  524. size_t kk;
  525. bool found = false;
  526. for ( kk = 0; kk < removed.size(); ++ kk )
  527. {
  528. if ( cc == removed[kk] )
  529. {
  530. found = true;
  531. }
  532. }
  533. if ( !found )
  534. {
  535. value += sep;
  536. value += varArgsExpanded[cc];
  537. sep = ";";
  538. }
  539. }
  540. this->Makefile->AddDefinition(listName.c_str(), value.c_str());
  541. return true;
  542. }