cmCommandLineArgument.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #pragma once
  4. #include "cmStringAlgorithms.h"
  5. #include "cmSystemTools.h"
  6. template <typename FunctionSignature>
  7. struct cmCommandLineArgument
  8. {
  9. enum class Values
  10. {
  11. Zero,
  12. One,
  13. Two,
  14. ZeroOrOne,
  15. OneOrMore
  16. };
  17. std::string InvalidSyntaxMessage;
  18. std::string InvalidValueMessage;
  19. std::string Name;
  20. Values Type;
  21. std::function<FunctionSignature> StoreCall;
  22. template <typename FunctionType>
  23. cmCommandLineArgument(std::string n, Values t, FunctionType&& func)
  24. : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
  25. , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
  26. , Name(std::move(n))
  27. , Type(t)
  28. , StoreCall(std::forward<FunctionType>(func))
  29. {
  30. }
  31. template <typename FunctionType>
  32. cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
  33. FunctionType&& func)
  34. : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
  35. , InvalidValueMessage(std::move(failedMsg))
  36. , Name(std::move(n))
  37. , Type(t)
  38. , StoreCall(std::forward<FunctionType>(func))
  39. {
  40. }
  41. bool matches(std::string const& input) const
  42. {
  43. return (this->Type == Values::Zero) ? (input == this->Name)
  44. : cmHasPrefix(input, this->Name);
  45. }
  46. template <typename T, typename... CallState>
  47. bool parse(std::string const& input, T& index,
  48. std::vector<std::string> const& allArgs,
  49. CallState&&... state) const
  50. {
  51. enum class ParseMode
  52. {
  53. Valid,
  54. Invalid,
  55. SyntaxError,
  56. ValueError
  57. };
  58. ParseMode parseState = ParseMode::Valid;
  59. if (this->Type == Values::Zero) {
  60. if (input.size() == this->Name.size()) {
  61. parseState =
  62. this->StoreCall(std::string{}, std::forward<CallState>(state)...)
  63. ? ParseMode::Valid
  64. : ParseMode::Invalid;
  65. } else {
  66. parseState = ParseMode::SyntaxError;
  67. }
  68. } else if (this->Type == Values::One || this->Type == Values::ZeroOrOne) {
  69. if (input.size() == this->Name.size()) {
  70. ++index;
  71. if (index >= allArgs.size() || allArgs[index][0] == '-') {
  72. if (this->Type == Values::ZeroOrOne) {
  73. parseState =
  74. this->StoreCall(std::string{}, std::forward<CallState>(state)...)
  75. ? ParseMode::Valid
  76. : ParseMode::Invalid;
  77. } else {
  78. parseState = ParseMode::ValueError;
  79. }
  80. } else {
  81. parseState =
  82. this->StoreCall(allArgs[index], std::forward<CallState>(state)...)
  83. ? ParseMode::Valid
  84. : ParseMode::Invalid;
  85. }
  86. } else {
  87. // parse the string to get the value
  88. auto possible_value = cm::string_view(input).substr(this->Name.size());
  89. if (possible_value.empty()) {
  90. parseState = ParseMode::SyntaxError;
  91. parseState = ParseMode::ValueError;
  92. } else if (possible_value[0] == '=') {
  93. possible_value.remove_prefix(1);
  94. if (possible_value.empty()) {
  95. parseState = ParseMode::ValueError;
  96. } else {
  97. parseState = this->StoreCall(std::string(possible_value),
  98. std::forward<CallState>(state)...)
  99. ? ParseMode::Valid
  100. : ParseMode::Invalid;
  101. }
  102. }
  103. if (parseState == ParseMode::Valid) {
  104. if (possible_value[0] == ' ') {
  105. possible_value.remove_prefix(1);
  106. }
  107. parseState = this->StoreCall(std::string(possible_value),
  108. std::forward<CallState>(state)...)
  109. ? ParseMode::Valid
  110. : ParseMode::Invalid;
  111. }
  112. }
  113. } else if (this->Type == Values::Two) {
  114. if (input.size() == this->Name.size()) {
  115. if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
  116. allArgs[index + 2][0] == '-') {
  117. parseState = ParseMode::ValueError;
  118. } else {
  119. index += 2;
  120. parseState =
  121. this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
  122. std::forward<CallState>(state)...)
  123. ? ParseMode::Valid
  124. : ParseMode::Invalid;
  125. }
  126. }
  127. } else if (this->Type == Values::OneOrMore) {
  128. if (input.size() == this->Name.size()) {
  129. auto nextValueIndex = index + 1;
  130. if (nextValueIndex >= allArgs.size() || allArgs[index + 1][0] == '-') {
  131. parseState = ParseMode::ValueError;
  132. } else {
  133. std::string buffer = allArgs[nextValueIndex++];
  134. while (nextValueIndex < allArgs.size() &&
  135. allArgs[nextValueIndex][0] != '-') {
  136. buffer = cmStrCat(buffer, ";", allArgs[nextValueIndex++]);
  137. }
  138. parseState =
  139. this->StoreCall(buffer, std::forward<CallState>(state)...)
  140. ? ParseMode::Valid
  141. : ParseMode::Invalid;
  142. }
  143. }
  144. }
  145. if (parseState == ParseMode::SyntaxError) {
  146. cmSystemTools::Error(this->InvalidSyntaxMessage);
  147. } else if (parseState == ParseMode::ValueError) {
  148. cmSystemTools::Error(this->InvalidValueMessage);
  149. }
  150. return (parseState == ParseMode::Valid);
  151. }
  152. };