cmListCommand.cxx 15 KB

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