cmList.cxx 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  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,
  240. std::vector<index_type> const& indexes)
  241. : TransformSelector(std::move(tag))
  242. , Indexes(indexes)
  243. {
  244. }
  245. TransformSelectorIndexes(std::string&& tag,
  246. std::vector<index_type>&& indexes)
  247. : TransformSelector(std::move(tag))
  248. , Indexes(indexes)
  249. {
  250. }
  251. index_type NormalizeIndex(index_type index, std::size_t count)
  252. {
  253. if (index < 0) {
  254. index = static_cast<index_type>(count) + index;
  255. }
  256. if (index < 0 || count <= static_cast<std::size_t>(index)) {
  257. throw transform_error(cmStrCat(
  258. "sub-command TRANSFORM, selector ", this->Tag, ", index: ", index,
  259. " out of range (-", count, ", ", count - 1, ")."));
  260. }
  261. return index;
  262. }
  263. };
  264. class TransformSelectorAt : public TransformSelectorIndexes
  265. {
  266. public:
  267. TransformSelectorAt(std::vector<index_type> const& indexes)
  268. : TransformSelectorIndexes("AT", indexes)
  269. {
  270. }
  271. TransformSelectorAt(std::vector<index_type>&& indexes)
  272. : TransformSelectorIndexes("AT", std::move(indexes))
  273. {
  274. }
  275. bool Validate(std::size_t count) override
  276. {
  277. decltype(this->Indexes) indexes;
  278. for (auto index : this->Indexes) {
  279. indexes.push_back(this->NormalizeIndex(index, count));
  280. }
  281. this->Indexes = std::move(indexes);
  282. return true;
  283. }
  284. };
  285. class TransformSelectorFor : public TransformSelectorIndexes
  286. {
  287. public:
  288. TransformSelectorFor(index_type start, index_type stop, index_type step)
  289. : TransformSelectorIndexes("FOR")
  290. , Start(start)
  291. , Stop(stop)
  292. , Step(step)
  293. {
  294. }
  295. bool Validate(std::size_t count) override
  296. {
  297. this->Start = this->NormalizeIndex(this->Start, count);
  298. this->Stop = this->NormalizeIndex(this->Stop, count);
  299. // Does stepping move us further from the end?
  300. if (this->Start > this->Stop) {
  301. throw transform_error(
  302. cmStrCat("sub-command TRANSFORM, selector FOR "
  303. "expects <start> to be no greater than <stop> (",
  304. this->Start, " > ", this->Stop, ")"));
  305. }
  306. // compute indexes
  307. auto size = (this->Stop - this->Start + 1) / this->Step;
  308. if ((this->Stop - this->Start + 1) % this->Step != 0) {
  309. size += 1;
  310. }
  311. this->Indexes.resize(size);
  312. auto start = this->Start;
  313. auto step = this->Step;
  314. std::generate(this->Indexes.begin(), this->Indexes.end(),
  315. [&start, step]() -> index_type {
  316. auto r = start;
  317. start += step;
  318. return r;
  319. });
  320. return true;
  321. }
  322. private:
  323. index_type Start, Stop, Step;
  324. };
  325. class TransformAction
  326. {
  327. public:
  328. virtual ~TransformAction() = default;
  329. void Initialize(TransformSelector* selector) { this->Selector = selector; }
  330. virtual void Initialize(TransformSelector*, const std::string&) {}
  331. virtual void Initialize(TransformSelector*, const std::string&,
  332. const std::string&)
  333. {
  334. }
  335. virtual void Initialize(TransformSelector* selector,
  336. const std::vector<std::string>&)
  337. {
  338. this->Initialize(selector);
  339. }
  340. virtual std::string operator()(const std::string& s) = 0;
  341. protected:
  342. TransformSelector* Selector;
  343. };
  344. class TransformActionAppend : public TransformAction
  345. {
  346. public:
  347. using TransformAction::Initialize;
  348. void Initialize(TransformSelector* selector,
  349. const std::string& append) override
  350. {
  351. TransformAction::Initialize(selector);
  352. this->Append = append;
  353. }
  354. void Initialize(TransformSelector* selector,
  355. const std::vector<std::string>& append) override
  356. {
  357. this->Initialize(selector, append.front());
  358. }
  359. std::string operator()(const std::string& s) override
  360. {
  361. if (this->Selector->InSelection(s)) {
  362. return cmStrCat(s, this->Append);
  363. }
  364. return s;
  365. }
  366. private:
  367. std::string Append;
  368. };
  369. class TransformActionPrepend : public TransformAction
  370. {
  371. public:
  372. using TransformAction::Initialize;
  373. void Initialize(TransformSelector* selector,
  374. const std::string& prepend) override
  375. {
  376. TransformAction::Initialize(selector);
  377. this->Prepend = prepend;
  378. }
  379. void Initialize(TransformSelector* selector,
  380. const std::vector<std::string>& prepend) override
  381. {
  382. this->Initialize(selector, prepend.front());
  383. }
  384. std::string operator()(const std::string& s) override
  385. {
  386. if (this->Selector->InSelection(s)) {
  387. return cmStrCat(this->Prepend, s);
  388. }
  389. return s;
  390. }
  391. private:
  392. std::string Prepend;
  393. };
  394. class TransformActionToUpper : public TransformAction
  395. {
  396. public:
  397. std::string operator()(const std::string& s) override
  398. {
  399. if (this->Selector->InSelection(s)) {
  400. return cmSystemTools::UpperCase(s);
  401. }
  402. return s;
  403. }
  404. };
  405. class TransformActionToLower : public TransformAction
  406. {
  407. public:
  408. std::string operator()(const std::string& s) override
  409. {
  410. if (this->Selector->InSelection(s)) {
  411. return cmSystemTools::LowerCase(s);
  412. }
  413. return s;
  414. }
  415. };
  416. class TransformActionStrip : public TransformAction
  417. {
  418. public:
  419. std::string operator()(const std::string& s) override
  420. {
  421. if (this->Selector->InSelection(s)) {
  422. return cmTrimWhitespace(s);
  423. }
  424. return s;
  425. }
  426. };
  427. class TransformActionGenexStrip : public TransformAction
  428. {
  429. public:
  430. std::string operator()(const std::string& s) override
  431. {
  432. if (this->Selector->InSelection(s)) {
  433. return cmGeneratorExpression::Preprocess(
  434. s, cmGeneratorExpression::StripAllGeneratorExpressions);
  435. }
  436. return s;
  437. }
  438. };
  439. class TransformActionReplace : public TransformAction
  440. {
  441. public:
  442. using TransformAction::Initialize;
  443. void Initialize(TransformSelector* selector, const std::string& regex,
  444. const std::string& replace) override
  445. {
  446. TransformAction::Initialize(selector);
  447. this->ReplaceHelper =
  448. cm::make_unique<cmStringReplaceHelper>(regex, replace);
  449. if (!this->ReplaceHelper->IsRegularExpressionValid()) {
  450. throw transform_error(
  451. cmStrCat("sub-command TRANSFORM, action REPLACE: Failed to compile "
  452. "regex \"",
  453. regex, "\"."));
  454. }
  455. if (!this->ReplaceHelper->IsReplaceExpressionValid()) {
  456. throw transform_error(cmStrCat("sub-command TRANSFORM, action REPLACE: ",
  457. this->ReplaceHelper->GetError(), "."));
  458. }
  459. }
  460. void Initialize(TransformSelector* selector,
  461. const std::vector<std::string>& args) override
  462. {
  463. this->Initialize(selector, args[0], args[1]);
  464. }
  465. std::string operator()(const std::string& s) override
  466. {
  467. if (this->Selector->InSelection(s)) {
  468. // Scan through the input for all matches.
  469. std::string output;
  470. if (!this->ReplaceHelper->Replace(s, output)) {
  471. throw transform_error(
  472. cmStrCat("sub-command TRANSFORM, action REPLACE: ",
  473. this->ReplaceHelper->GetError(), "."));
  474. }
  475. return output;
  476. }
  477. return s;
  478. }
  479. private:
  480. std::unique_ptr<cmStringReplaceHelper> ReplaceHelper;
  481. };
  482. // Descriptor of action
  483. // Arity: number of arguments required for the action
  484. // Transform: Object implementing the action
  485. struct ActionDescriptor
  486. {
  487. ActionDescriptor(cmList::TransformAction action)
  488. : Action(action)
  489. {
  490. }
  491. ActionDescriptor(cmList::TransformAction action, std::string name,
  492. std::size_t arity,
  493. std::unique_ptr<TransformAction> transform)
  494. : Action(action)
  495. , Name(std::move(name))
  496. , Arity(arity)
  497. , Transform(std::move(transform))
  498. {
  499. }
  500. operator cmList::TransformAction() const { return this->Action; }
  501. cmList::TransformAction Action;
  502. std::string Name;
  503. std::size_t Arity = 0;
  504. std::unique_ptr<TransformAction> Transform;
  505. };
  506. // Build a set of supported actions.
  507. using ActionDescriptorSet = std::set<
  508. ActionDescriptor,
  509. std::function<bool(cmList::TransformAction, cmList::TransformAction)>>;
  510. ActionDescriptorSet Descriptors([](cmList::TransformAction x,
  511. cmList::TransformAction y) {
  512. return x < y;
  513. });
  514. ActionDescriptorSet::iterator TransformConfigure(
  515. cmList::TransformAction action,
  516. std::unique_ptr<cmList::TransformSelector>& selector, std::size_t arity)
  517. {
  518. if (Descriptors.empty()) {
  519. Descriptors.emplace(cmList::TransformAction::APPEND, "APPEND", 1,
  520. cm::make_unique<TransformActionAppend>());
  521. Descriptors.emplace(cmList::TransformAction::PREPEND, "PREPEND", 1,
  522. cm::make_unique<TransformActionPrepend>());
  523. Descriptors.emplace(cmList::TransformAction::TOUPPER, "TOUPPER", 0,
  524. cm::make_unique<TransformActionToUpper>());
  525. Descriptors.emplace(cmList::TransformAction::TOLOWER, "TOLOWER", 0,
  526. cm::make_unique<TransformActionToLower>());
  527. Descriptors.emplace(cmList::TransformAction::STRIP, "STRIP", 0,
  528. cm::make_unique<TransformActionStrip>());
  529. Descriptors.emplace(cmList::TransformAction::GENEX_STRIP, "GENEX_STRIP", 0,
  530. cm::make_unique<TransformActionGenexStrip>());
  531. Descriptors.emplace(cmList::TransformAction::REPLACE, "REPLACE", 2,
  532. cm::make_unique<TransformActionReplace>());
  533. }
  534. auto descriptor = Descriptors.find(action);
  535. if (descriptor == Descriptors.end()) {
  536. throw transform_error(cmStrCat(" sub-command TRANSFORM, ",
  537. std::to_string(static_cast<int>(action)),
  538. " invalid action."));
  539. }
  540. if (descriptor->Arity != arity) {
  541. throw transform_error(cmStrCat("sub-command TRANSFORM, action ",
  542. descriptor->Name, " expects ",
  543. descriptor->Arity, " argument(s)."));
  544. }
  545. if (!selector) {
  546. selector = cm::make_unique<TransformNoSelector>();
  547. }
  548. return descriptor;
  549. }
  550. }
  551. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
  552. std::initializer_list<index_type> indexes)
  553. {
  554. return cm::make_unique<TransformSelectorAt>(
  555. std::vector<index_type>{ indexes.begin(), indexes.end() });
  556. ;
  557. }
  558. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
  559. std::vector<index_type> const& indexes)
  560. {
  561. return cm::make_unique<TransformSelectorAt>(indexes);
  562. }
  563. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewAT(
  564. std::vector<index_type>&& indexes)
  565. {
  566. return cm::make_unique<TransformSelectorAt>(std::move(indexes));
  567. }
  568. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
  569. std::initializer_list<index_type> indexes)
  570. {
  571. if (indexes.size() < 2 || indexes.size() > 3) {
  572. throw transform_error("sub-command TRANSFORM, selector FOR "
  573. "expects 2 or 3 arguments");
  574. }
  575. if (indexes.size() == 3 && *(indexes.begin() + 2) < 0) {
  576. throw transform_error("sub-command TRANSFORM, selector FOR expects "
  577. "positive numeric value for <step>.");
  578. }
  579. return cm::make_unique<TransformSelectorFor>(
  580. *indexes.begin(), *(indexes.begin() + 1),
  581. indexes.size() == 3 ? *(indexes.begin() + 2) : 1);
  582. }
  583. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
  584. std::vector<index_type> const& indexes)
  585. {
  586. if (indexes.size() < 2 || indexes.size() > 3) {
  587. throw transform_error("sub-command TRANSFORM, selector FOR "
  588. "expects 2 or 3 arguments");
  589. }
  590. if (indexes.size() == 3 && indexes[2] < 0) {
  591. throw transform_error("sub-command TRANSFORM, selector FOR expects "
  592. "positive numeric value for <step>.");
  593. }
  594. return cm::make_unique<TransformSelectorFor>(
  595. indexes[0], indexes[1], indexes.size() == 3 ? indexes[2] : 1);
  596. }
  597. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewFOR(
  598. std::vector<index_type>&& indexes)
  599. {
  600. if (indexes.size() < 2 || indexes.size() > 3) {
  601. throw transform_error("sub-command TRANSFORM, selector FOR "
  602. "expects 2 or 3 arguments");
  603. }
  604. if (indexes.size() == 3 && indexes[2] < 0) {
  605. throw transform_error("sub-command TRANSFORM, selector FOR expects "
  606. "positive numeric value for <step>.");
  607. }
  608. return cm::make_unique<TransformSelectorFor>(
  609. indexes[0], indexes[1], indexes.size() == 3 ? indexes[2] : 1);
  610. }
  611. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewREGEX(
  612. std::string const& regex)
  613. {
  614. std::unique_ptr<::TransformSelector> selector =
  615. cm::make_unique<TransformSelectorRegex>(regex);
  616. if (!selector->Validate()) {
  617. throw transform_error(
  618. cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
  619. "regex \"",
  620. regex, "\"."));
  621. }
  622. // weird construct to please all compilers
  623. return std::unique_ptr<cmList::TransformSelector>(selector.release());
  624. }
  625. std::unique_ptr<cmList::TransformSelector> cmList::TransformSelector::NewREGEX(
  626. std::string&& regex)
  627. {
  628. std::unique_ptr<::TransformSelector> selector =
  629. cm::make_unique<TransformSelectorRegex>(std::move(regex));
  630. if (!selector->Validate()) {
  631. throw transform_error(
  632. cmStrCat("sub-command TRANSFORM, selector REGEX failed to compile "
  633. "regex \"",
  634. regex, "\"."));
  635. }
  636. // weird construct to please all compilers
  637. return std::unique_ptr<cmList::TransformSelector>(selector.release());
  638. }
  639. cmList& cmList::transform(TransformAction action,
  640. std::unique_ptr<TransformSelector> selector)
  641. {
  642. auto descriptor = TransformConfigure(action, selector, 0);
  643. descriptor->Transform->Initialize(
  644. static_cast<::TransformSelector*>(selector.get()));
  645. static_cast<::TransformSelector&>(*selector).Transform(
  646. this->Values, [&descriptor](const std::string& s) -> std::string {
  647. return (*descriptor->Transform)(s);
  648. });
  649. return *this;
  650. }
  651. cmList& cmList::transform(TransformAction action, std::string const& arg,
  652. std::unique_ptr<TransformSelector> selector)
  653. {
  654. auto descriptor = TransformConfigure(action, selector, 1);
  655. descriptor->Transform->Initialize(
  656. static_cast<::TransformSelector*>(selector.get()), arg);
  657. static_cast<::TransformSelector&>(*selector).Transform(
  658. this->Values, [&descriptor](const std::string& s) -> std::string {
  659. return (*descriptor->Transform)(s);
  660. });
  661. return *this;
  662. }
  663. cmList& cmList::transform(TransformAction action, std::string const& arg1,
  664. std::string const& arg2,
  665. std::unique_ptr<TransformSelector> selector)
  666. {
  667. auto descriptor = TransformConfigure(action, selector, 2);
  668. descriptor->Transform->Initialize(
  669. static_cast<::TransformSelector*>(selector.get()), arg1, arg2);
  670. static_cast<::TransformSelector&>(*selector).Transform(
  671. this->Values, [&descriptor](const std::string& s) -> std::string {
  672. return (*descriptor->Transform)(s);
  673. });
  674. return *this;
  675. }
  676. cmList& cmList::transform(TransformAction action,
  677. std::vector<std::string> const& args,
  678. std::unique_ptr<TransformSelector> selector)
  679. {
  680. auto descriptor = TransformConfigure(action, selector, args.size());
  681. descriptor->Transform->Initialize(
  682. static_cast<::TransformSelector*>(selector.get()), args);
  683. static_cast<::TransformSelector&>(*selector).Transform(
  684. this->Values, [&descriptor](const std::string& s) -> std::string {
  685. return (*descriptor->Transform)(s);
  686. });
  687. return *this;
  688. }
  689. std::string& cmList::append(std::string& list, std::string&& value)
  690. {
  691. if (list.empty()) {
  692. list = std::move(value);
  693. } else {
  694. list += cmStrCat(cmList::element_separator, value);
  695. }
  696. return list;
  697. }
  698. std::string& cmList::append(std::string& list, cm::string_view value)
  699. {
  700. return cmList::append(list, std::string{ value });
  701. }
  702. std::string& cmList::prepend(std::string& list, std::string&& value)
  703. {
  704. if (list.empty()) {
  705. list = std::move(value);
  706. } else {
  707. list.insert(0, cmStrCat(value, cmList::element_separator));
  708. }
  709. return list;
  710. }
  711. std::string& cmList::prepend(std::string& list, cm::string_view value)
  712. {
  713. return cmList::prepend(list, std::string{ value });
  714. }
  715. cmList::size_type cmList::ComputeIndex(index_type pos, bool boundCheck) const
  716. {
  717. if (boundCheck) {
  718. if (this->Values.empty()) {
  719. throw std::out_of_range(
  720. cmStrCat("index: ", pos, " out of range (0, 0)"));
  721. }
  722. auto index = pos;
  723. if (!this->Values.empty()) {
  724. auto length = this->Values.size();
  725. if (index < 0) {
  726. index = static_cast<index_type>(length) + index;
  727. }
  728. if (index < 0 || length <= static_cast<size_type>(index)) {
  729. throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
  730. this->Values.size(), ", ",
  731. this->Values.size() - 1, ")"));
  732. }
  733. }
  734. return index;
  735. }
  736. return pos < 0 ? this->Values.size() + pos : pos;
  737. }
  738. cmList::size_type cmList::ComputeInsertIndex(index_type pos,
  739. bool boundCheck) const
  740. {
  741. if (boundCheck) {
  742. if (this->Values.empty() && pos != 0) {
  743. throw std::out_of_range(
  744. cmStrCat("index: ", pos, " out of range (0, 0)"));
  745. }
  746. auto index = pos;
  747. if (!this->Values.empty()) {
  748. auto length = this->Values.size();
  749. if (index < 0) {
  750. index = static_cast<index_type>(length) + index;
  751. }
  752. if (index < 0 || length < static_cast<size_type>(index)) {
  753. throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
  754. this->Values.size(), ", ",
  755. this->Values.size(), ")"));
  756. }
  757. }
  758. return index;
  759. }
  760. return pos < 0 ? this->Values.size() + pos : pos;
  761. }
  762. cmList cmList::GetItems(std::vector<index_type>&& indexes) const
  763. {
  764. cmList listItems;
  765. for (auto index : indexes) {
  766. listItems.emplace_back(this->get_item(index));
  767. }
  768. return listItems;
  769. }
  770. cmList& cmList::RemoveItems(std::vector<index_type>&& indexes)
  771. {
  772. if (indexes.empty()) {
  773. return *this;
  774. }
  775. // compute all indexes
  776. std::vector<size_type> idx(indexes.size());
  777. std::transform(indexes.cbegin(), indexes.cend(), idx.begin(),
  778. [this](const index_type& index) -> size_type {
  779. return this->ComputeIndex(index);
  780. });
  781. std::sort(idx.begin(), idx.end(),
  782. [](size_type l, size_type r) { return l > r; });
  783. auto newEnd = std::unique(idx.begin(), idx.end());
  784. idx.erase(newEnd, idx.end());
  785. for (auto index : idx) {
  786. this->erase(this->begin() + index);
  787. }
  788. return *this;
  789. }
  790. cmList& cmList::RemoveItems(std::vector<std::string>&& items)
  791. {
  792. std::sort(items.begin(), items.end());
  793. auto last = std::unique(items.begin(), items.end());
  794. auto first = items.begin();
  795. auto newEnd = cmRemoveMatching(this->Values, cmMakeRange(first, last));
  796. this->Values.erase(newEnd, this->Values.end());
  797. return *this;
  798. }
  799. cmList::container_type::iterator cmList::Insert(
  800. container_type& container, container_type::const_iterator pos,
  801. std::string&& value, ExpandElements expandElements,
  802. EmptyElements emptyElements)
  803. {
  804. auto delta = std::distance(container.cbegin(), pos);
  805. auto insertPos = container.begin() + delta;
  806. if (expandElements == ExpandElements::Yes) {
  807. // If argument is empty, it is an empty list.
  808. if (emptyElements == EmptyElements::No && value.empty()) {
  809. return insertPos;
  810. }
  811. // if there are no ; in the name then just copy the current string
  812. if (value.find(';') == std::string::npos) {
  813. return container.insert(insertPos, std::move(value));
  814. }
  815. std::string newValue;
  816. // Break the string at non-escaped semicolons not nested in [].
  817. int squareNesting = 0;
  818. auto last = value.begin();
  819. auto const cend = value.end();
  820. for (auto c = last; c != cend; ++c) {
  821. switch (*c) {
  822. case '\\': {
  823. // We only want to allow escaping of semicolons. Other
  824. // escapes should not be processed here.
  825. auto cnext = c + 1;
  826. if ((cnext != cend) && *cnext == ';') {
  827. newValue.append(last, c);
  828. // Skip over the escape character
  829. last = cnext;
  830. c = cnext;
  831. }
  832. } break;
  833. case '[': {
  834. ++squareNesting;
  835. } break;
  836. case ']': {
  837. --squareNesting;
  838. } break;
  839. case ';': {
  840. // brackets.
  841. if (squareNesting == 0) {
  842. newValue.append(last, c);
  843. // Skip over the semicolon
  844. last = c + 1;
  845. if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
  846. // Add the last argument.
  847. insertPos = container.insert(insertPos, newValue);
  848. insertPos++;
  849. newValue.clear();
  850. }
  851. }
  852. } break;
  853. default: {
  854. // Just append this character.
  855. } break;
  856. }
  857. }
  858. newValue.append(last, cend);
  859. if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
  860. // Add the last argument.
  861. container.insert(insertPos, std::move(newValue));
  862. }
  863. } else if (!value.empty() || emptyElements == EmptyElements::Yes) {
  864. return container.insert(insertPos, std::move(value));
  865. }
  866. return container.begin() + delta;
  867. }