cmList.cxx 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmConfigure.h" // IWYU pragma: keep
  4. #include "cmList.h"
  5. #include <algorithm>
  6. #include <cstddef>
  7. #include <functional>
  8. #include <iterator>
  9. #include <set>
  10. #include <stdexcept>
  11. #include <utility>
  12. #include <cm/memory>
  13. #include "cmsys/RegularExpression.hxx"
  14. #include "cmAlgorithms.h"
  15. #include "cmGeneratorExpression.h"
  16. #include "cmRange.h"
  17. #include "cmStringAlgorithms.h"
  18. #include "cmStringReplaceHelper.h"
  19. #include "cmSystemTools.h"
  20. cm::string_view cmList::element_separator{ ";" };
  21. cmList cmList::sublist(size_type pos, size_type length) const
  22. {
  23. if (pos >= this->Values.size()) {
  24. throw std::out_of_range(cmStrCat(
  25. "begin index: ", pos, " is out of range 0 - ", this->Values.size() - 1));
  26. }
  27. size_type count = (length == npos || pos + length > this->size())
  28. ? this->size()
  29. : pos + length;
  30. return this->sublist(this->begin() + pos, this->begin() + count);
  31. }
  32. cmList::size_type cmList::find(cm::string_view value) const
  33. {
  34. auto res = std::find(this->Values.begin(), this->Values.end(), value);
  35. if (res == this->Values.end()) {
  36. return npos;
  37. }
  38. return std::distance(this->Values.begin(), res);
  39. }
  40. cmList& cmList::remove_duplicates()
  41. {
  42. auto newEnd = cmRemoveDuplicates(this->Values);
  43. this->Values.erase(newEnd, this->Values.end());
  44. return *this;
  45. }
  46. namespace {
  47. class MatchesRegex
  48. {
  49. public:
  50. MatchesRegex(cmsys::RegularExpression& regex, cmList::FilterMode mode)
  51. : Regex(regex)
  52. , IncludeMatches(mode == cmList::FilterMode::INCLUDE)
  53. {
  54. }
  55. bool operator()(const std::string& target)
  56. {
  57. return this->Regex.find(target) ^ this->IncludeMatches;
  58. }
  59. private:
  60. cmsys::RegularExpression& Regex;
  61. const bool IncludeMatches;
  62. };
  63. }
  64. cmList& cmList::filter(cm::string_view pattern, FilterMode mode)
  65. {
  66. cmsys::RegularExpression regex(std::string{ pattern });
  67. if (!regex.is_valid()) {
  68. throw std::invalid_argument(
  69. cmStrCat("sub-command FILTER, mode REGEX failed to compile regex \"",
  70. pattern, "\"."));
  71. }
  72. auto it = std::remove_if(this->Values.begin(), this->Values.end(),
  73. MatchesRegex{ regex, mode });
  74. this->Values.erase(it, this->Values.end());
  75. return *this;
  76. }
  77. namespace {
  78. class StringSorter
  79. {
  80. protected:
  81. using StringFilter = std::function<std::string(const std::string&)>;
  82. using OrderMode = cmList::SortConfiguration::OrderMode;
  83. using CompareMethod = cmList::SortConfiguration::CompareMethod;
  84. using CaseSensitivity = cmList::SortConfiguration::CaseSensitivity;
  85. StringFilter GetCompareFilter(CompareMethod compare)
  86. {
  87. return (compare == CompareMethod::FILE_BASENAME)
  88. ? cmSystemTools::GetFilenameName
  89. : nullptr;
  90. }
  91. StringFilter GetCaseFilter(CaseSensitivity sensitivity)
  92. {
  93. return (sensitivity == CaseSensitivity::INSENSITIVE)
  94. ? cmSystemTools::LowerCase
  95. : nullptr;
  96. }
  97. using ComparisonFunction =
  98. std::function<bool(const std::string&, const std::string&)>;
  99. ComparisonFunction GetComparisonFunction(CompareMethod compare)
  100. {
  101. if (compare == CompareMethod::NATURAL) {
  102. return std::function<bool(const std::string&, const std::string&)>(
  103. [](const std::string& x, const std::string& y) {
  104. return cmSystemTools::strverscmp(x, y) < 0;
  105. });
  106. }
  107. return std::function<bool(const std::string&, const std::string&)>(
  108. [](const std::string& x, const std::string& y) { return x < y; });
  109. }
  110. public:
  111. StringSorter(cmList::SortConfiguration const& config)
  112. : Filters{ this->GetCompareFilter(config.Compare),
  113. this->GetCaseFilter(config.Case) }
  114. , SortMethod(this->GetComparisonFunction(config.Compare))
  115. , Descending(config.Order == OrderMode::DESCENDING)
  116. {
  117. }
  118. std::string ApplyFilter(const std::string& argument)
  119. {
  120. std::string result = argument;
  121. for (auto const& filter : this->Filters) {
  122. if (filter != nullptr) {
  123. result = filter(result);
  124. }
  125. }
  126. return result;
  127. }
  128. bool operator()(const std::string& a, const std::string& b)
  129. {
  130. std::string af = this->ApplyFilter(a);
  131. std::string bf = this->ApplyFilter(b);
  132. bool result;
  133. if (this->Descending) {
  134. result = this->SortMethod(bf, af);
  135. } else {
  136. result = this->SortMethod(af, bf);
  137. }
  138. return result;
  139. }
  140. private:
  141. StringFilter Filters[2] = { nullptr, nullptr };
  142. ComparisonFunction SortMethod;
  143. bool Descending;
  144. };
  145. }
  146. cmList::SortConfiguration::SortConfiguration() = default;
  147. cmList& cmList::sort(const SortConfiguration& cfg)
  148. {
  149. SortConfiguration config{ cfg };
  150. if (config.Order == SortConfiguration::OrderMode::DEFAULT) {
  151. config.Order = SortConfiguration::OrderMode::ASCENDING;
  152. }
  153. if (config.Compare == SortConfiguration::CompareMethod::DEFAULT) {
  154. config.Compare = SortConfiguration::CompareMethod::STRING;
  155. }
  156. if (config.Case == SortConfiguration::CaseSensitivity::DEFAULT) {
  157. config.Case = SortConfiguration::CaseSensitivity::SENSITIVE;
  158. }
  159. if ((config.Compare == SortConfiguration::CompareMethod::STRING) &&
  160. (config.Case == SortConfiguration::CaseSensitivity::SENSITIVE) &&
  161. (config.Order == SortConfiguration::OrderMode::ASCENDING)) {
  162. std::sort(this->Values.begin(), this->Values.end());
  163. } else {
  164. StringSorter sorter(config);
  165. std::sort(this->Values.begin(), this->Values.end(), sorter);
  166. }
  167. return *this;
  168. }
  169. namespace {
  170. using transform_type = std::function<std::string(const std::string&)>;
  171. using transform_error = cmList::transform_error;
  172. class TransformSelector : public cmList::TransformSelector
  173. {
  174. public:
  175. ~TransformSelector() override = default;
  176. std::string Tag;
  177. const std::string& GetTag() override { return this->Tag; }
  178. virtual bool Validate(std::size_t count = 0) = 0;
  179. virtual bool InSelection(const std::string&) = 0;
  180. virtual void Transform(cmList::container_type& list,
  181. const transform_type& transform)
  182. {
  183. std::transform(list.begin(), list.end(), list.begin(), transform);
  184. }
  185. protected:
  186. TransformSelector(std::string&& tag)
  187. : Tag(std::move(tag))
  188. {
  189. }
  190. };
  191. class TransformNoSelector : public TransformSelector
  192. {
  193. public:
  194. TransformNoSelector()
  195. : TransformSelector("NO SELECTOR")
  196. {
  197. }
  198. bool Validate(std::size_t) override { return true; }
  199. bool InSelection(const std::string&) override { return true; }
  200. };
  201. class TransformSelectorRegex : public TransformSelector
  202. {
  203. public:
  204. TransformSelectorRegex(const std::string& regex)
  205. : TransformSelector("REGEX")
  206. , Regex(regex)
  207. {
  208. }
  209. TransformSelectorRegex(std::string&& regex)
  210. : TransformSelector("REGEX")
  211. , Regex(regex)
  212. {
  213. }
  214. bool Validate(std::size_t) override { return this->Regex.is_valid(); }
  215. bool InSelection(const std::string& value) override
  216. {
  217. return this->Regex.find(value);
  218. }
  219. cmsys::RegularExpression Regex;
  220. };
  221. class TransformSelectorIndexes : public TransformSelector
  222. {
  223. public:
  224. std::vector<index_type> Indexes;
  225. bool InSelection(const std::string&) override { return true; }
  226. void Transform(std::vector<std::string>& list,
  227. const transform_type& transform) override
  228. {
  229. this->Validate(list.size());
  230. for (auto index : this->Indexes) {
  231. list[index] = transform(list[index]);
  232. }
  233. }
  234. protected:
  235. TransformSelectorIndexes(std::string&& tag)
  236. : TransformSelector(std::move(tag))
  237. {
  238. }
  239. TransformSelectorIndexes(std::string&& tag, std::vector<int> const& indexes)
  240. : TransformSelector(std::move(tag))
  241. , Indexes(indexes)
  242. {
  243. }
  244. TransformSelectorIndexes(std::string&& tag, std::vector<int>&& indexes)
  245. : TransformSelector(std::move(tag))
  246. , Indexes(indexes)
  247. {
  248. }
  249. int NormalizeIndex(index_type index, std::size_t count)
  250. {
  251. if (index < 0) {
  252. index = static_cast<index_type>(count) + index;
  253. }
  254. if (index < 0 || count <= static_cast<std::size_t>(index)) {
  255. throw transform_error(cmStrCat(
  256. "sub-command TRANSFORM, selector ", this->Tag, ", index: ", index,
  257. " out of range (-", count, ", ", count - 1, ")."));
  258. }
  259. return index;
  260. }
  261. };
  262. class TransformSelectorAt : public TransformSelectorIndexes
  263. {
  264. public:
  265. TransformSelectorAt(std::vector<index_type> const& indexes)
  266. : TransformSelectorIndexes("AT", indexes)
  267. {
  268. }
  269. TransformSelectorAt(std::vector<index_type>&& indexes)
  270. : TransformSelectorIndexes("AT", std::move(indexes))
  271. {
  272. }
  273. bool Validate(std::size_t count) override
  274. {
  275. decltype(this->Indexes) indexes;
  276. for (auto index : this->Indexes) {
  277. indexes.push_back(this->NormalizeIndex(index, count));
  278. }
  279. this->Indexes = std::move(indexes);
  280. return true;
  281. }
  282. };
  283. class TransformSelectorFor : public TransformSelectorIndexes
  284. {
  285. public:
  286. TransformSelectorFor(int start, int stop, int step)
  287. : TransformSelectorIndexes("FOR")
  288. , Start(start)
  289. , Stop(stop)
  290. , Step(step)
  291. {
  292. }
  293. bool Validate(std::size_t count) override
  294. {
  295. this->Start = this->NormalizeIndex(this->Start, count);
  296. this->Stop = this->NormalizeIndex(this->Stop, count);
  297. // Does stepping move us further from the end?
  298. if (this->Start > this->Stop) {
  299. throw transform_error(
  300. cmStrCat("sub-command TRANSFORM, selector FOR "
  301. "expects <start> to be no greater than <stop> (",
  302. this->Start, " > ", this->Stop, ")"));
  303. }
  304. // compute indexes
  305. auto size = (this->Stop - this->Start + 1) / this->Step;
  306. if ((this->Stop - this->Start + 1) % this->Step != 0) {
  307. size += 1;
  308. }
  309. this->Indexes.resize(size);
  310. auto start = this->Start;
  311. auto step = this->Step;
  312. std::generate(this->Indexes.begin(), this->Indexes.end(),
  313. [&start, step]() -> int {
  314. auto r = start;
  315. start += step;
  316. return r;
  317. });
  318. return true;
  319. }
  320. private:
  321. index_type Start, Stop, Step;
  322. };
  323. class TransformAction
  324. {
  325. public:
  326. virtual ~TransformAction() = default;
  327. void Initialize(TransformSelector* selector) { this->Selector = selector; }
  328. virtual void Initialize(TransformSelector*, const std::string&) {}
  329. virtual void Initialize(TransformSelector*, const std::string&,
  330. const std::string&)
  331. {
  332. }
  333. virtual void Initialize(TransformSelector* selector,
  334. const std::vector<std::string>&)
  335. {
  336. this->Initialize(selector);
  337. }
  338. virtual std::string operator()(const std::string& s) = 0;
  339. protected:
  340. TransformSelector* Selector;
  341. };
  342. class TransformActionAppend : public TransformAction
  343. {
  344. public:
  345. using TransformAction::Initialize;
  346. void Initialize(TransformSelector* selector,
  347. const std::string& append) override
  348. {
  349. TransformAction::Initialize(selector);
  350. this->Append = append;
  351. }
  352. void Initialize(TransformSelector* selector,
  353. const std::vector<std::string>& append) override
  354. {
  355. this->Initialize(selector, append.front());
  356. }
  357. std::string operator()(const std::string& s) override
  358. {
  359. if (this->Selector->InSelection(s)) {
  360. return cmStrCat(s, this->Append);
  361. }
  362. return s;
  363. }
  364. private:
  365. std::string Append;
  366. };
  367. class TransformActionPrepend : public TransformAction
  368. {
  369. public:
  370. using TransformAction::Initialize;
  371. void Initialize(TransformSelector* selector,
  372. const std::string& prepend) override
  373. {
  374. TransformAction::Initialize(selector);
  375. this->Prepend = prepend;
  376. }
  377. void Initialize(TransformSelector* selector,
  378. const std::vector<std::string>& prepend) override
  379. {
  380. this->Initialize(selector, prepend.front());
  381. }
  382. std::string operator()(const std::string& s) override
  383. {
  384. if (this->Selector->InSelection(s)) {
  385. return cmStrCat(this->Prepend, s);
  386. }
  387. return s;
  388. }
  389. private:
  390. std::string Prepend;
  391. };
  392. class TransformActionToUpper : public TransformAction
  393. {
  394. public:
  395. std::string operator()(const std::string& s) override
  396. {
  397. if (this->Selector->InSelection(s)) {
  398. return cmSystemTools::UpperCase(s);
  399. }
  400. return s;
  401. }
  402. };
  403. class TransformActionToLower : public TransformAction
  404. {
  405. public:
  406. std::string operator()(const std::string& s) override
  407. {
  408. if (this->Selector->InSelection(s)) {
  409. return cmSystemTools::LowerCase(s);
  410. }
  411. return s;
  412. }
  413. };
  414. class TransformActionStrip : public TransformAction
  415. {
  416. public:
  417. std::string operator()(const std::string& s) override
  418. {
  419. if (this->Selector->InSelection(s)) {
  420. return cmTrimWhitespace(s);
  421. }
  422. return s;
  423. }
  424. };
  425. class TransformActionGenexStrip : public TransformAction
  426. {
  427. public:
  428. std::string operator()(const std::string& s) override
  429. {
  430. if (this->Selector->InSelection(s)) {
  431. return cmGeneratorExpression::Preprocess(
  432. s, cmGeneratorExpression::StripAllGeneratorExpressions);
  433. }
  434. return s;
  435. }
  436. };
  437. class TransformActionReplace : public TransformAction
  438. {
  439. public:
  440. using TransformAction::Initialize;
  441. void Initialize(TransformSelector* selector, const std::string& regex,
  442. const std::string& replace) override
  443. {
  444. TransformAction::Initialize(selector);
  445. this->ReplaceHelper =
  446. cm::make_unique<cmStringReplaceHelper>(regex, replace);
  447. if (!this->ReplaceHelper->IsRegularExpressionValid()) {
  448. throw transform_error(
  449. cmStrCat("sub-command TRANSFORM, action REPLACE: Failed to compile "
  450. "regex \"",
  451. regex, "\"."));
  452. }
  453. if (!this->ReplaceHelper->IsReplaceExpressionValid()) {
  454. throw transform_error(cmStrCat("sub-command TRANSFORM, action REPLACE: ",
  455. this->ReplaceHelper->GetError(), "."));
  456. }
  457. }
  458. void Initialize(TransformSelector* selector,
  459. const std::vector<std::string>& args) override
  460. {
  461. this->Initialize(selector, args[0], args[1]);
  462. }
  463. std::string operator()(const std::string& s) override
  464. {
  465. if (this->Selector->InSelection(s)) {
  466. // Scan through the input for all matches.
  467. std::string output;
  468. if (!this->ReplaceHelper->Replace(s, output)) {
  469. throw transform_error(
  470. cmStrCat("sub-command TRANSFORM, action REPLACE: ",
  471. this->ReplaceHelper->GetError(), "."));
  472. }
  473. return output;
  474. }
  475. return s;
  476. }
  477. private:
  478. std::unique_ptr<cmStringReplaceHelper> ReplaceHelper;
  479. };
  480. // Descriptor of action
  481. // Arity: number of arguments required for the action
  482. // Transform: Object implementing the action
  483. struct ActionDescriptor
  484. {
  485. ActionDescriptor(cmList::TransformAction action)
  486. : Action(action)
  487. {
  488. }
  489. ActionDescriptor(cmList::TransformAction action, std::string name,
  490. std::size_t arity,
  491. std::unique_ptr<TransformAction> transform)
  492. : Action(action)
  493. , Name(std::move(name))
  494. , Arity(arity)
  495. , Transform(std::move(transform))
  496. {
  497. }
  498. operator cmList::TransformAction() const { return this->Action; }
  499. cmList::TransformAction Action;
  500. std::string Name;
  501. std::size_t Arity = 0;
  502. std::unique_ptr<TransformAction> Transform;
  503. };
  504. // Build a set of supported actions.
  505. using ActionDescriptorSet = std::set<
  506. ActionDescriptor,
  507. std::function<bool(cmList::TransformAction, cmList::TransformAction)>>;
  508. ActionDescriptorSet Descriptors([](cmList::TransformAction x,
  509. cmList::TransformAction y) {
  510. return x < y;
  511. });
  512. ActionDescriptorSet::iterator TransformConfigure(
  513. cmList::TransformAction action,
  514. std::unique_ptr<cmList::TransformSelector>& selector, std::size_t arity)
  515. {
  516. if (Descriptors.empty()) {
  517. Descriptors.emplace(cmList::TransformAction::APPEND, "APPEND", 1,
  518. cm::make_unique<TransformActionAppend>());
  519. Descriptors.emplace(cmList::TransformAction::PREPEND, "PREPEND", 1,
  520. cm::make_unique<TransformActionPrepend>());
  521. Descriptors.emplace(cmList::TransformAction::TOUPPER, "TOUPPER", 0,
  522. cm::make_unique<TransformActionToUpper>());
  523. Descriptors.emplace(cmList::TransformAction::TOLOWER, "TOLOWER", 0,
  524. cm::make_unique<TransformActionToLower>());
  525. Descriptors.emplace(cmList::TransformAction::STRIP, "STRIP", 0,
  526. cm::make_unique<TransformActionStrip>());
  527. Descriptors.emplace(cmList::TransformAction::GENEX_STRIP, "GENEX_STRIP", 0,
  528. cm::make_unique<TransformActionGenexStrip>());
  529. Descriptors.emplace(cmList::TransformAction::REPLACE, "REPLACE", 2,
  530. cm::make_unique<TransformActionReplace>());
  531. }
  532. auto descriptor = Descriptors.find(action);
  533. if (descriptor == Descriptors.end()) {
  534. throw transform_error(cmStrCat(" sub-command TRANSFORM, ",
  535. std::to_string(static_cast<int>(action)),
  536. " invalid action."));
  537. }
  538. if (descriptor->Arity != arity) {
  539. throw transform_error(cmStrCat("sub-command TRANSFORM, action ",
  540. descriptor->Name, " expects ",
  541. descriptor->Arity, " argument(s)."));
  542. }
  543. if (!selector) {
  544. selector = cm::make_unique<TransformNoSelector>();
  545. }
  546. return descriptor;
  547. }
  548. }
  549. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
  550. std::initializer_list<index_type> indexes)
  551. {
  552. return cm::make_unique<TransformSelectorAt>(
  553. std::vector<index_type>{ indexes.begin(), indexes.end() });
  554. ;
  555. }
  556. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
  557. std::vector<index_type> const& indexes)
  558. {
  559. return cm::make_unique<TransformSelectorAt>(indexes);
  560. }
  561. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
  562. std::vector<index_type>&& indexes)
  563. {
  564. return cm::make_unique<TransformSelectorAt>(std::move(indexes));
  565. }
  566. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
  567. std::initializer_list<index_type> indexes)
  568. {
  569. if (indexes.size() < 2 || indexes.size() > 3) {
  570. throw transform_error("sub-command TRANSFORM, selector FOR "
  571. "expects 2 or 3 arguments");
  572. }
  573. if (indexes.size() == 3 && *(indexes.begin() + 2) < 0) {
  574. throw transform_error("sub-command TRANSFORM, selector FOR expects "
  575. "positive numeric value for <step>.");
  576. }
  577. return cm::make_unique<TransformSelectorFor>(
  578. *indexes.begin(), *(indexes.begin() + 1),
  579. indexes.size() == 3 ? *(indexes.begin() + 2) : 1);
  580. }
  581. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
  582. std::vector<index_type> const& indexes)
  583. {
  584. if (indexes.size() < 2 || indexes.size() > 3) {
  585. throw transform_error("sub-command TRANSFORM, selector FOR "
  586. "expects 2 or 3 arguments");
  587. }
  588. if (indexes.size() == 3 && indexes[2] < 0) {
  589. throw transform_error("sub-command TRANSFORM, selector FOR expects "
  590. "positive numeric value for <step>.");
  591. }
  592. return cm::make_unique<TransformSelectorFor>(
  593. indexes[0], indexes[1], indexes.size() == 3 ? indexes[2] : 1);
  594. }
  595. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
  596. std::vector<index_type>&& indexes)
  597. {
  598. if (indexes.size() < 2 || indexes.size() > 3) {
  599. throw transform_error("sub-command TRANSFORM, selector FOR "
  600. "expects 2 or 3 arguments");
  601. }
  602. if (indexes.size() == 3 && indexes[2] < 0) {
  603. throw transform_error("sub-command TRANSFORM, selector FOR expects "
  604. "positive numeric value for <step>.");
  605. }
  606. return cm::make_unique<TransformSelectorFor>(
  607. indexes[0], indexes[1], indexes.size() == 3 ? indexes[2] : 1);
  608. }
  609. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewREGEX(
  610. std::string const& regex)
  611. {
  612. std::unique_ptr<::TransformSelector> selector =
  613. cm::make_unique<TransformSelectorRegex>(regex);
  614. if (!selector->Validate()) {
  615. throw transform_error(
  616. cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
  617. "regex \"",
  618. regex, "\"."));
  619. }
  620. // weird construct to please all compilers
  621. return std::unique_ptr<cmList::TransformSelector>(selector.release());
  622. }
  623. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewREGEX(
  624. std::string&& regex)
  625. {
  626. std::unique_ptr<::TransformSelector> selector =
  627. cm::make_unique<TransformSelectorRegex>(std::move(regex));
  628. if (!selector->Validate()) {
  629. throw transform_error(
  630. cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
  631. "regex \"",
  632. regex, "\"."));
  633. }
  634. // weird construct to please all compilers
  635. return std::unique_ptr<cmList::TransformSelector>(selector.release());
  636. }
  637. cmList& cmList::transform(TransformAction action,
  638. std::unique_ptr<TransformSelector> selector)
  639. {
  640. auto descriptor = TransformConfigure(action, selector, 0);
  641. descriptor->Transform->Initialize(
  642. static_cast<::TransformSelector*>(selector.get()));
  643. static_cast<::TransformSelector&>(*selector).Transform(
  644. this->Values, [&descriptor](const std::string& s) -> std::string {
  645. return (*descriptor->Transform)(s);
  646. });
  647. return *this;
  648. }
  649. cmList& cmList::transform(TransformAction action, std::string const& arg,
  650. std::unique_ptr<TransformSelector> selector)
  651. {
  652. auto descriptor = TransformConfigure(action, selector, 1);
  653. descriptor->Transform->Initialize(
  654. static_cast<::TransformSelector*>(selector.get()), arg);
  655. static_cast<::TransformSelector&>(*selector).Transform(
  656. this->Values, [&descriptor](const std::string& s) -> std::string {
  657. return (*descriptor->Transform)(s);
  658. });
  659. return *this;
  660. }
  661. cmList& cmList::transform(TransformAction action, std::string const& arg1,
  662. std::string const& arg2,
  663. std::unique_ptr<TransformSelector> selector)
  664. {
  665. auto descriptor = TransformConfigure(action, selector, 2);
  666. descriptor->Transform->Initialize(
  667. static_cast<::TransformSelector*>(selector.get()), arg1, arg2);
  668. static_cast<::TransformSelector&>(*selector).Transform(
  669. this->Values, [&descriptor](const std::string& s) -> std::string {
  670. return (*descriptor->Transform)(s);
  671. });
  672. return *this;
  673. }
  674. cmList& cmList::transform(TransformAction action,
  675. std::vector<std::string> const& args,
  676. std::unique_ptr<TransformSelector> selector)
  677. {
  678. auto descriptor = TransformConfigure(action, selector, args.size());
  679. descriptor->Transform->Initialize(
  680. static_cast<::TransformSelector*>(selector.get()), args);
  681. static_cast<::TransformSelector&>(*selector).Transform(
  682. this->Values, [&descriptor](const std::string& s) -> std::string {
  683. return (*descriptor->Transform)(s);
  684. });
  685. return *this;
  686. }
  687. std::string cmList::join(cm::string_view glue) const
  688. {
  689. return cmJoin(this->Values, glue);
  690. }
  691. std::string& cmList::append(cm::string_view value, std::string& list)
  692. {
  693. if (list.empty()) {
  694. list = std::string(value);
  695. } else {
  696. list += cmStrCat(cmList::element_separator, value);
  697. }
  698. return list;
  699. }
  700. std::string& cmList::prepend(cm::string_view value, std::string& list)
  701. {
  702. if (list.empty()) {
  703. list = std::string(value);
  704. } else {
  705. list.insert(0, cmStrCat(value, cmList::element_separator));
  706. }
  707. return list;
  708. }
  709. cmList::size_type cmList::ComputeIndex(index_type pos, bool boundCheck) const
  710. {
  711. if (boundCheck) {
  712. if (this->Values.empty()) {
  713. throw std::out_of_range(
  714. cmStrCat("index: ", pos, " out of range (0, 0)"));
  715. }
  716. auto index = pos;
  717. if (!this->Values.empty()) {
  718. auto length = this->Values.size();
  719. if (index < 0) {
  720. index = static_cast<index_type>(length) + index;
  721. }
  722. if (index < 0 || length <= static_cast<size_type>(index)) {
  723. throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
  724. this->Values.size(), ", ",
  725. this->Values.size() - 1, ")"));
  726. }
  727. }
  728. return index;
  729. }
  730. return pos < 0 ? this->Values.size() + pos : pos;
  731. }
  732. cmList::size_type cmList::ComputeInsertIndex(index_type pos,
  733. bool boundCheck) const
  734. {
  735. if (boundCheck) {
  736. if (this->Values.empty() && pos != 0) {
  737. throw std::out_of_range(
  738. cmStrCat("index: ", pos, " out of range (0, 0)"));
  739. }
  740. auto index = pos;
  741. if (!this->Values.empty()) {
  742. auto length = this->Values.size();
  743. if (index < 0) {
  744. index = static_cast<index_type>(length) + index;
  745. }
  746. if (index < 0 || length < static_cast<size_type>(index)) {
  747. throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
  748. this->Values.size(), ", ",
  749. this->Values.size(), ")"));
  750. }
  751. }
  752. return index;
  753. }
  754. return pos < 0 ? this->Values.size() + pos : pos;
  755. }
  756. cmList cmList::GetItems(std::vector<index_type>&& indexes) const
  757. {
  758. cmList listItems;
  759. for (auto index : indexes) {
  760. listItems.emplace_back(this->at(index));
  761. }
  762. return listItems;
  763. }
  764. cmList& cmList::RemoveItems(std::vector<index_type>&& indexes)
  765. {
  766. if (indexes.empty()) {
  767. return *this;
  768. }
  769. // compute all indexes
  770. std::vector<size_type> idx(indexes.size());
  771. std::transform(
  772. indexes.cbegin(), indexes.cend(), idx.begin(),
  773. [this](const index_type& index) { return this->ComputeIndex(index); });
  774. std::sort(idx.begin(), idx.end(),
  775. [](size_type l, size_type r) { return l > r; });
  776. auto newEnd = std::unique(idx.begin(), idx.end());
  777. idx.erase(newEnd, idx.end());
  778. for (auto index : idx) {
  779. this->erase(this->begin() + index);
  780. }
  781. return *this;
  782. }
  783. cmList& cmList::RemoveItems(std::vector<std::string>&& items)
  784. {
  785. std::sort(items.begin(), items.end());
  786. auto last = std::unique(items.begin(), items.end());
  787. auto first = items.begin();
  788. auto newEnd = cmRemoveMatching(this->Values, cmMakeRange(first, last));
  789. this->Values.erase(newEnd, this->Values.end());
  790. return *this;
  791. }
  792. cmList::container_type::iterator cmList::Insert(
  793. container_type::const_iterator pos, std::string&& value,
  794. container_type& container, ExpandElements expandElements,
  795. EmptyElements emptyElements)
  796. {
  797. auto delta = std::distance(container.cbegin(), pos);
  798. auto insertPos = container.begin() + delta;
  799. if (expandElements == ExpandElements::Yes) {
  800. // If argument is empty, it is an empty list.
  801. if (emptyElements == EmptyElements::No && value.empty()) {
  802. return insertPos;
  803. }
  804. // if there are no ; in the name then just copy the current string
  805. if (value.find(';') == std::string::npos) {
  806. return container.insert(insertPos, std::move(value));
  807. }
  808. std::string newValue;
  809. // Break the string at non-escaped semicolons not nested in [].
  810. int squareNesting = 0;
  811. auto last = value.begin();
  812. auto const cend = value.end();
  813. for (auto c = last; c != cend; ++c) {
  814. switch (*c) {
  815. case '\\': {
  816. // We only want to allow escaping of semicolons. Other
  817. // escapes should not be processed here.
  818. auto cnext = c + 1;
  819. if ((cnext != cend) && *cnext == ';') {
  820. newValue.append(last, c);
  821. // Skip over the escape character
  822. last = cnext;
  823. c = cnext;
  824. }
  825. } break;
  826. case '[': {
  827. ++squareNesting;
  828. } break;
  829. case ']': {
  830. --squareNesting;
  831. } break;
  832. case ';': {
  833. // brackets.
  834. if (squareNesting == 0) {
  835. newValue.append(last, c);
  836. // Skip over the semicolon
  837. last = c + 1;
  838. if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
  839. // Add the last argument.
  840. insertPos = container.insert(insertPos, newValue);
  841. insertPos++;
  842. newValue.clear();
  843. }
  844. }
  845. } break;
  846. default: {
  847. // Just append this character.
  848. } break;
  849. }
  850. }
  851. newValue.append(last, cend);
  852. if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
  853. // Add the last argument.
  854. container.insert(insertPos, std::move(newValue));
  855. }
  856. } else if (!value.empty() || emptyElements == EmptyElements::Yes) {
  857. return container.insert(insertPos, std::move(value));
  858. }
  859. return container.begin() + delta;
  860. }