cmList.cxx 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  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. if (!this->Values.empty()) {
  717. auto length = this->Values.size();
  718. if (pos < 0) {
  719. pos = static_cast<index_type>(length) + pos;
  720. }
  721. if (pos < 0 || length <= static_cast<size_type>(pos)) {
  722. throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
  723. this->Values.size(), ", ",
  724. this->Values.size() - 1, ")"));
  725. }
  726. }
  727. return pos;
  728. }
  729. return pos < 0 ? this->Values.size() + pos : pos;
  730. }
  731. cmList::size_type cmList::ComputeInsertIndex(index_type pos,
  732. bool boundCheck) const
  733. {
  734. if (boundCheck) {
  735. if (this->Values.empty() && pos != 0) {
  736. throw std::out_of_range(
  737. cmStrCat("index: ", pos, " out of range (0, 0)"));
  738. }
  739. if (!this->Values.empty()) {
  740. auto length = this->Values.size();
  741. if (pos < 0) {
  742. pos = static_cast<index_type>(length) + pos;
  743. }
  744. if (pos < 0 || length < static_cast<size_type>(pos)) {
  745. throw std::out_of_range(cmStrCat("index: ", pos, " out of range (-",
  746. this->Values.size(), ", ",
  747. this->Values.size(), ")"));
  748. }
  749. }
  750. return pos;
  751. }
  752. return pos < 0 ? this->Values.size() + pos : pos;
  753. }
  754. cmList cmList::GetItems(std::vector<index_type>&& indexes) const
  755. {
  756. cmList listItems;
  757. for (auto index : indexes) {
  758. listItems.emplace_back(this->at(index));
  759. }
  760. return listItems;
  761. }
  762. cmList& cmList::RemoveItems(std::vector<index_type>&& indexes)
  763. {
  764. if (indexes.empty()) {
  765. return *this;
  766. }
  767. // compute all indexes
  768. std::vector<size_type> idx(indexes.size());
  769. std::transform(
  770. indexes.cbegin(), indexes.cend(), idx.begin(),
  771. [this](const index_type& index) { return this->ComputeIndex(index); });
  772. std::sort(idx.begin(), idx.end(),
  773. [](size_type l, size_type r) { return l > r; });
  774. auto newEnd = std::unique(idx.begin(), idx.end());
  775. idx.erase(newEnd, idx.end());
  776. for (auto index : idx) {
  777. this->erase(this->begin() + index);
  778. }
  779. return *this;
  780. }
  781. cmList& cmList::RemoveItems(std::vector<std::string>&& items)
  782. {
  783. std::sort(items.begin(), items.end());
  784. auto last = std::unique(items.begin(), items.end());
  785. auto first = items.begin();
  786. auto newEnd = cmRemoveMatching(this->Values, cmMakeRange(first, last));
  787. this->Values.erase(newEnd, this->Values.end());
  788. return *this;
  789. }
  790. cmList::container_type::iterator cmList::Insert(
  791. container_type::const_iterator pos, std::string&& value,
  792. container_type& container, ExpandElements expandElements,
  793. EmptyElements emptyElements)
  794. {
  795. auto delta = std::distance(container.cbegin(), pos);
  796. auto insertPos = container.begin() + delta;
  797. if (expandElements == ExpandElements::Yes) {
  798. // If argument is empty, it is an empty list.
  799. if (emptyElements == EmptyElements::No && value.empty()) {
  800. return insertPos;
  801. }
  802. // if there are no ; in the name then just copy the current string
  803. if (value.find(';') == std::string::npos) {
  804. return container.insert(insertPos, std::move(value));
  805. }
  806. std::string newValue;
  807. // Break the string at non-escaped semicolons not nested in [].
  808. int squareNesting = 0;
  809. auto last = value.begin();
  810. auto const cend = value.end();
  811. for (auto c = last; c != cend; ++c) {
  812. switch (*c) {
  813. case '\\': {
  814. // We only want to allow escaping of semicolons. Other
  815. // escapes should not be processed here.
  816. auto cnext = c + 1;
  817. if ((cnext != cend) && *cnext == ';') {
  818. newValue.append(last, c);
  819. // Skip over the escape character
  820. last = cnext;
  821. c = cnext;
  822. }
  823. } break;
  824. case '[': {
  825. ++squareNesting;
  826. } break;
  827. case ']': {
  828. --squareNesting;
  829. } break;
  830. case ';': {
  831. // brackets.
  832. if (squareNesting == 0) {
  833. newValue.append(last, c);
  834. // Skip over the semicolon
  835. last = c + 1;
  836. if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
  837. // Add the last argument.
  838. insertPos = container.insert(insertPos, newValue);
  839. insertPos++;
  840. newValue.clear();
  841. }
  842. }
  843. } break;
  844. default: {
  845. // Just append this character.
  846. } break;
  847. }
  848. }
  849. newValue.append(last, cend);
  850. if (!newValue.empty() || emptyElements == EmptyElements::Yes) {
  851. // Add the last argument.
  852. container.insert(insertPos, std::move(newValue));
  853. }
  854. } else if (!value.empty() || emptyElements == EmptyElements::Yes) {
  855. return container.insert(insertPos, std::move(value));
  856. }
  857. return container.begin() + delta;
  858. }