cmPlaceholderExpander.cxx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  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 "cmPlaceholderExpander.h"
  4. #include <cctype>
  5. std::string& cmPlaceholderExpander::ExpandVariables(std::string& s)
  6. {
  7. std::string::size_type start = s.find('<');
  8. // no variables to expand
  9. if (start == std::string::npos) {
  10. return s;
  11. }
  12. std::string::size_type pos = 0;
  13. std::string expandedInput;
  14. while (start != std::string::npos && start < s.size() - 2) {
  15. std::string::size_type end = s.find('>', start);
  16. // if we find a < with no > we are done
  17. if (end == std::string::npos) {
  18. s = expandedInput;
  19. return s;
  20. }
  21. char c = s[start + 1];
  22. // if the next char after the < is not A-Za-z then
  23. // skip it and try to find the next < in the string
  24. if (!isalpha(c)) {
  25. start = s.find('<', start + 1);
  26. } else {
  27. // extract the var
  28. std::string var = s.substr(start + 1, end - start - 1);
  29. std::string replace = this->ExpandVariable(var);
  30. expandedInput += s.substr(pos, start - pos);
  31. // Prevent consecutive whitespace in the output if the rule variable
  32. // expands to an empty string.
  33. bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' &&
  34. end + 1 < s.size() && s[end + 1] == ' ';
  35. if (consecutive) {
  36. expandedInput.pop_back();
  37. }
  38. expandedInput += replace;
  39. // move to next one
  40. start = s.find('<', start + var.size() + 2);
  41. pos = end + 1;
  42. }
  43. }
  44. // add the rest of the input
  45. expandedInput += s.substr(pos, s.size() - pos);
  46. s = expandedInput;
  47. return s;
  48. }