cmCommandLineArgument.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 <cm/optional>
  5. #include "cmStringAlgorithms.h"
  6. #include "cmSystemTools.h"
  7. template <typename FunctionSignature>
  8. struct cmCommandLineArgument
  9. {
  10. enum class Values
  11. {
  12. Zero,
  13. One,
  14. Two,
  15. ZeroOrOne,
  16. OneOrMore
  17. };
  18. enum class RequiresSeparator
  19. {
  20. Yes,
  21. No
  22. };
  23. enum class ParseMode
  24. {
  25. Valid,
  26. Invalid,
  27. SyntaxError,
  28. ValueError
  29. };
  30. std::string InvalidSyntaxMessage;
  31. std::string InvalidValueMessage;
  32. std::string Name;
  33. Values Type;
  34. RequiresSeparator SeparatorNeeded;
  35. std::function<FunctionSignature> StoreCall;
  36. template <typename FunctionType>
  37. cmCommandLineArgument(std::string n, Values t, FunctionType&& func)
  38. : InvalidSyntaxMessage(cmStrCat(" is invalid syntax for ", n))
  39. , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
  40. , Name(std::move(n))
  41. , Type(t)
  42. , SeparatorNeeded(RequiresSeparator::Yes)
  43. , StoreCall(std::forward<FunctionType>(func))
  44. {
  45. }
  46. template <typename FunctionType>
  47. cmCommandLineArgument(std::string n, Values t, RequiresSeparator s,
  48. FunctionType&& func)
  49. : InvalidSyntaxMessage(cmStrCat(" is invalid syntax for ", n))
  50. , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
  51. , Name(std::move(n))
  52. , Type(t)
  53. , SeparatorNeeded(s)
  54. , StoreCall(std::forward<FunctionType>(func))
  55. {
  56. }
  57. template <typename FunctionType>
  58. cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
  59. FunctionType&& func)
  60. : InvalidSyntaxMessage(cmStrCat(" is invalid syntax for ", n))
  61. , InvalidValueMessage(std::move(failedMsg))
  62. , Name(std::move(n))
  63. , Type(t)
  64. , SeparatorNeeded(RequiresSeparator::Yes)
  65. , StoreCall(std::forward<FunctionType>(func))
  66. {
  67. }
  68. template <typename FunctionType>
  69. cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
  70. RequiresSeparator s, FunctionType&& func)
  71. : InvalidSyntaxMessage(cmStrCat(" is invalid syntax for ", n))
  72. , InvalidValueMessage(std::move(failedMsg))
  73. , Name(std::move(n))
  74. , Type(t)
  75. , SeparatorNeeded(s)
  76. , StoreCall(std::forward<FunctionType>(func))
  77. {
  78. }
  79. bool matches(std::string const& input) const
  80. {
  81. bool matched = false;
  82. if (this->Type == Values::Zero) {
  83. matched = (input == this->Name);
  84. } else if (this->SeparatorNeeded == RequiresSeparator::No) {
  85. matched = cmHasPrefix(input, this->Name);
  86. } else if (cmHasPrefix(input, this->Name)) {
  87. if (input.size() == this->Name.size()) {
  88. matched = true;
  89. } else {
  90. matched =
  91. (input[this->Name.size()] == '=' || input[this->Name.size()] == ' ');
  92. }
  93. }
  94. return matched;
  95. }
  96. template <typename T, typename... CallState>
  97. bool parse(std::string const& input, T& index,
  98. std::vector<std::string> const& allArgs,
  99. CallState&&... state) const
  100. {
  101. ParseMode parseState = ParseMode::Valid;
  102. if (this->Type == Values::Zero) {
  103. if (input.size() == this->Name.size()) {
  104. parseState =
  105. this->StoreCall(std::string{}, std::forward<CallState>(state)...)
  106. ? ParseMode::Valid
  107. : ParseMode::Invalid;
  108. } else {
  109. parseState = ParseMode::SyntaxError;
  110. }
  111. } else if (this->Type == Values::One || this->Type == Values::ZeroOrOne) {
  112. if (input.size() == this->Name.size()) {
  113. auto nextValueIndex = index + 1;
  114. if (nextValueIndex >= allArgs.size() ||
  115. allArgs[nextValueIndex][0] == '-') {
  116. if (this->Type == Values::ZeroOrOne) {
  117. parseState =
  118. this->StoreCall(std::string{}, std::forward<CallState>(state)...)
  119. ? ParseMode::Valid
  120. : ParseMode::Invalid;
  121. } else {
  122. parseState = ParseMode::ValueError;
  123. }
  124. } else {
  125. parseState = this->StoreCall(allArgs[nextValueIndex],
  126. std::forward<CallState>(state)...)
  127. ? ParseMode::Valid
  128. : ParseMode::Invalid;
  129. index = nextValueIndex;
  130. }
  131. } else {
  132. auto value = this->extract_single_value(input, parseState);
  133. if (parseState == ParseMode::Valid) {
  134. parseState =
  135. this->StoreCall(value, std::forward<CallState>(state)...)
  136. ? ParseMode::Valid
  137. : ParseMode::Invalid;
  138. }
  139. }
  140. } else if (this->Type == Values::Two) {
  141. if (input.size() == this->Name.size()) {
  142. if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
  143. allArgs[index + 2][0] == '-') {
  144. parseState = ParseMode::ValueError;
  145. } else {
  146. index += 2;
  147. parseState =
  148. this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
  149. std::forward<CallState>(state)...)
  150. ? ParseMode::Valid
  151. : ParseMode::Invalid;
  152. }
  153. }
  154. } else if (this->Type == Values::OneOrMore) {
  155. if (input.size() == this->Name.size()) {
  156. auto nextValueIndex = index + 1;
  157. if (nextValueIndex >= allArgs.size() ||
  158. allArgs[nextValueIndex][0] == '-') {
  159. parseState = ParseMode::ValueError;
  160. } else {
  161. std::string buffer = allArgs[nextValueIndex++];
  162. while (nextValueIndex < allArgs.size() &&
  163. allArgs[nextValueIndex][0] != '-') {
  164. buffer = cmStrCat(buffer, ";", allArgs[nextValueIndex++]);
  165. }
  166. parseState =
  167. this->StoreCall(buffer, std::forward<CallState>(state)...)
  168. ? ParseMode::Valid
  169. : ParseMode::Invalid;
  170. index = (nextValueIndex - 1);
  171. }
  172. } else {
  173. auto value = this->extract_single_value(input, parseState);
  174. if (parseState == ParseMode::Valid) {
  175. parseState =
  176. this->StoreCall(value, std::forward<CallState>(state)...)
  177. ? ParseMode::Valid
  178. : ParseMode::Invalid;
  179. }
  180. }
  181. }
  182. if (parseState == ParseMode::SyntaxError) {
  183. cmSystemTools::Error(
  184. cmStrCat("'", input, "'", this->InvalidSyntaxMessage));
  185. } else if (parseState == ParseMode::ValueError) {
  186. cmSystemTools::Error(this->InvalidValueMessage);
  187. }
  188. return (parseState == ParseMode::Valid);
  189. }
  190. template <typename... Values>
  191. static std::function<FunctionSignature> setToTrue(Values&&... values)
  192. {
  193. return ArgumentLambdaHelper<FunctionSignature>::generateSetToTrue(
  194. std::forward<Values>(values)...);
  195. }
  196. template <typename... Values>
  197. static std::function<FunctionSignature> setToValue(Values&&... values)
  198. {
  199. return ArgumentLambdaHelper<FunctionSignature>::generateSetToValue(
  200. std::forward<Values>(values)...);
  201. }
  202. private:
  203. template <typename T>
  204. class ArgumentLambdaHelper;
  205. template <typename... CallState>
  206. class ArgumentLambdaHelper<bool(const std::string&, CallState...)>
  207. {
  208. public:
  209. static std::function<bool(const std::string&, CallState...)>
  210. generateSetToTrue(bool& value1)
  211. {
  212. return [&value1](const std::string&, CallState&&...) -> bool {
  213. value1 = true;
  214. return true;
  215. };
  216. }
  217. static std::function<bool(const std::string&, CallState...)>
  218. generateSetToTrue(bool& value1, bool& value2)
  219. {
  220. return [&value1, &value2](const std::string&, CallState&&...) -> bool {
  221. value1 = true;
  222. value2 = true;
  223. return true;
  224. };
  225. }
  226. static std::function<bool(const std::string&, CallState...)>
  227. generateSetToValue(std::string& value1)
  228. {
  229. return [&value1](const std::string& arg, CallState&&...) -> bool {
  230. value1 = arg;
  231. return true;
  232. };
  233. }
  234. static std::function<bool(const std::string&, CallState...)>
  235. generateSetToValue(cm::optional<std::string>& value1)
  236. {
  237. return [&value1](const std::string& arg, CallState&&...) -> bool {
  238. value1 = arg;
  239. return true;
  240. };
  241. }
  242. };
  243. std::string extract_single_value(std::string const& input,
  244. ParseMode& parseState) const
  245. {
  246. // parse the string to get the value
  247. auto possible_value = cm::string_view(input).substr(this->Name.size());
  248. if (possible_value.empty()) {
  249. parseState = ParseMode::ValueError;
  250. } else if (possible_value[0] == '=') {
  251. possible_value.remove_prefix(1);
  252. if (possible_value.empty()) {
  253. parseState = ParseMode::ValueError;
  254. }
  255. }
  256. if (parseState == ParseMode::Valid && possible_value[0] == ' ') {
  257. possible_value.remove_prefix(1);
  258. }
  259. return std::string(possible_value);
  260. }
  261. };