cmCommandLineArgument.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. };
  16. std::string InvalidSyntaxMessage;
  17. std::string InvalidValueMessage;
  18. std::string Name;
  19. Values Type;
  20. std::function<FunctionSignature> StoreCall;
  21. template <typename FunctionType>
  22. cmCommandLineArgument(std::string n, Values t, FunctionType&& func)
  23. : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
  24. , InvalidValueMessage(cmStrCat("Invalid value used with ", n))
  25. , Name(std::move(n))
  26. , Type(t)
  27. , StoreCall(std::forward<FunctionType>(func))
  28. {
  29. }
  30. template <typename FunctionType>
  31. cmCommandLineArgument(std::string n, std::string failedMsg, Values t,
  32. FunctionType&& func)
  33. : InvalidSyntaxMessage(cmStrCat("Invalid syntax used with ", n))
  34. , InvalidValueMessage(std::move(failedMsg))
  35. , Name(std::move(n))
  36. , Type(t)
  37. , StoreCall(std::forward<FunctionType>(func))
  38. {
  39. }
  40. bool matches(std::string const& input) const
  41. {
  42. return (this->Type == Values::Zero) ? (input == this->Name)
  43. : cmHasPrefix(input, this->Name);
  44. }
  45. template <typename T, typename... CallState>
  46. bool parse(std::string const& input, T& index,
  47. std::vector<std::string> const& allArgs,
  48. CallState&&... state) const
  49. {
  50. enum class ParseMode
  51. {
  52. Valid,
  53. Invalid,
  54. SyntaxError,
  55. ValueError
  56. };
  57. ParseMode parseState = ParseMode::Valid;
  58. if (this->Type == Values::Zero) {
  59. if (input.size() == this->Name.size()) {
  60. parseState =
  61. this->StoreCall(std::string{}, std::forward<CallState>(state)...)
  62. ? ParseMode::Valid
  63. : ParseMode::Invalid;
  64. } else {
  65. parseState = ParseMode::SyntaxError;
  66. }
  67. } else if (this->Type == Values::One || this->Type == Values::ZeroOrOne) {
  68. if (input.size() == this->Name.size()) {
  69. ++index;
  70. if (index >= allArgs.size() || allArgs[index][0] == '-') {
  71. if (this->Type == Values::ZeroOrOne) {
  72. parseState =
  73. this->StoreCall(std::string{}, std::forward<CallState>(state)...)
  74. ? ParseMode::Valid
  75. : ParseMode::Invalid;
  76. } else {
  77. parseState = ParseMode::ValueError;
  78. }
  79. } else {
  80. parseState =
  81. this->StoreCall(allArgs[index], std::forward<CallState>(state)...)
  82. ? ParseMode::Valid
  83. : ParseMode::Invalid;
  84. }
  85. } else {
  86. // parse the string to get the value
  87. auto possible_value = cm::string_view(input).substr(this->Name.size());
  88. if (possible_value.empty()) {
  89. parseState = ParseMode::SyntaxError;
  90. parseState = ParseMode::ValueError;
  91. } else if (possible_value[0] == '=') {
  92. possible_value.remove_prefix(1);
  93. if (possible_value.empty()) {
  94. parseState = ParseMode::ValueError;
  95. } else {
  96. parseState = this->StoreCall(std::string(possible_value),
  97. std::forward<CallState>(state)...)
  98. ? ParseMode::Valid
  99. : ParseMode::Invalid;
  100. }
  101. }
  102. if (parseState == ParseMode::Valid) {
  103. parseState = this->StoreCall(std::string(possible_value),
  104. std::forward<CallState>(state)...)
  105. ? ParseMode::Valid
  106. : ParseMode::Invalid;
  107. }
  108. }
  109. } else if (this->Type == Values::Two) {
  110. if (input.size() == this->Name.size()) {
  111. if (index + 2 >= allArgs.size() || allArgs[index + 1][0] == '-' ||
  112. allArgs[index + 2][0] == '-') {
  113. parseState = ParseMode::ValueError;
  114. } else {
  115. index += 2;
  116. parseState =
  117. this->StoreCall(cmStrCat(allArgs[index - 1], ";", allArgs[index]),
  118. std::forward<CallState>(state)...)
  119. ? ParseMode::Valid
  120. : ParseMode::Invalid;
  121. }
  122. }
  123. }
  124. if (parseState == ParseMode::SyntaxError) {
  125. cmSystemTools::Error(this->InvalidSyntaxMessage);
  126. } else if (parseState == ParseMode::ValueError) {
  127. cmSystemTools::Error(this->InvalidValueMessage);
  128. }
  129. return (parseState == ParseMode::Valid);
  130. }
  131. };