CArgsParser.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include "CArgsParser.h"
  2. #include <AK/StringBuilder.h>
  3. #include <stdio.h>
  4. bool CArgsParserResult::is_present(const String& arg_name) const
  5. {
  6. return m_args.contains(arg_name);
  7. }
  8. String CArgsParserResult::get(const String& arg_name) const
  9. {
  10. return m_args.get(arg_name).value_or({});
  11. }
  12. const Vector<String>& CArgsParserResult::get_single_values() const
  13. {
  14. return m_single_values;
  15. }
  16. CArgsParser::Arg::Arg(const String& name, const String& description, bool required)
  17. : name(name)
  18. , description(description)
  19. , required(required)
  20. {
  21. }
  22. CArgsParser::Arg::Arg(const String& name, const String& value_name, const String& description, bool required)
  23. : name(name)
  24. , description(description)
  25. , value_name(value_name)
  26. , required(required)
  27. {
  28. }
  29. CArgsParser::CArgsParser(const String& program_name)
  30. : m_program_name(program_name)
  31. , m_prefix("-")
  32. {
  33. }
  34. CArgsParserResult CArgsParser::parse(int argc, char** argv)
  35. {
  36. CArgsParserResult res;
  37. // We should have at least one parameter
  38. if (argc < 2)
  39. return {};
  40. // We parse the first parameter at the index 1
  41. if (parse_next_param(1, argv, argc - 1, res) != 0)
  42. return {};
  43. if (!check_required_args(res))
  44. return {};
  45. return res;
  46. }
  47. int CArgsParser::parse_next_param(int index, char** argv, const int params_left, CArgsParserResult& res)
  48. {
  49. if (params_left == 0)
  50. return 0;
  51. String param = argv[index];
  52. // We check if the prefix is found at the beginning of the param name
  53. if (is_param_valid(param)) {
  54. auto prefix_length = m_prefix.length();
  55. String param_name = param.substring(prefix_length, param.length() - prefix_length);
  56. auto arg = m_args.find(param_name);
  57. if (arg == m_args.end()) {
  58. printf("Unknown arg \"");
  59. if (!param_name.is_null())
  60. printf("%s", param_name.characters());
  61. printf("\"\n");
  62. return -1;
  63. }
  64. // If this parameter must be followed by a value, we look for it
  65. if (!arg->value.value_name.is_null()) {
  66. if (params_left < 1) {
  67. printf("Missing value for argument %s\n", arg->value.name.characters());
  68. return -1;
  69. }
  70. String next = String(argv[index + 1]);
  71. if (is_param_valid(next)) {
  72. printf("Missing value for argument %s\n", arg->value.name.characters());
  73. return -1;
  74. }
  75. res.m_args.set(arg->value.name, next);
  76. return parse_next_param(index + 2, argv, params_left - 2, res);
  77. }
  78. // Single argument, not followed by a value
  79. res.m_args.set(arg->value.name, "");
  80. return parse_next_param(index + 1, argv, params_left - 1, res);
  81. }
  82. // Else, it's a value alone, a file name parameter for example
  83. res.m_single_values.append(param);
  84. return parse_next_param(index + 1, argv, params_left - 1, res);
  85. }
  86. bool CArgsParser::is_param_valid(const String& param_name)
  87. {
  88. return param_name.length() >= m_prefix.length() &&
  89. param_name.substring(0, m_prefix.length()) == m_prefix;
  90. }
  91. bool CArgsParser::check_required_args(const CArgsParserResult& res)
  92. {
  93. for (auto& it : m_args) {
  94. if (it.value.required) {
  95. if (!res.is_present(it.value.name))
  96. return false;
  97. }
  98. }
  99. int required_arguments = 0;
  100. for (const auto& a : m_single_args) {
  101. if (a.required) {
  102. required_arguments++;
  103. }
  104. }
  105. if (required_arguments != 0) {
  106. if (res.m_single_values.size() < required_arguments)
  107. return false;
  108. }
  109. return true;
  110. }
  111. void CArgsParser::add_required_arg(const String& name, const String& description)
  112. {
  113. m_args.set(name, Arg(name, description, true));
  114. }
  115. void CArgsParser::add_required_arg(const String& name, const String& value_name, const String& description)
  116. {
  117. m_args.set(name, Arg(name, value_name, description, true));
  118. }
  119. void CArgsParser::add_arg(const String& name, const String& description)
  120. {
  121. m_args.set(name, Arg(name, description, false));
  122. }
  123. void CArgsParser::add_arg(const String& name, const String& value_name, const String& description)
  124. {
  125. m_args.set(name, Arg(name, value_name, description, false));
  126. }
  127. void CArgsParser::add_single_value(const String& name)
  128. {
  129. m_single_args.append(SingleArg { name, false });
  130. }
  131. void CArgsParser::add_required_single_value(const String& name)
  132. {
  133. if (m_single_args.size() != 0) {
  134. // adding required arguments after non-required arguments would be nonsensical
  135. ASSERT(m_single_args.last().required);
  136. }
  137. m_single_args.append(SingleArg { name, true });
  138. }
  139. String CArgsParser::get_usage() const
  140. {
  141. StringBuilder sb;
  142. sb.append("usage : ");
  143. sb.append(m_program_name);
  144. sb.append(" ");
  145. for (auto& it : m_args) {
  146. if (it.value.required)
  147. sb.append("<");
  148. else
  149. sb.append("[");
  150. sb.append(m_prefix);
  151. sb.append(it.value.name);
  152. if (!it.value.value_name.is_null()) {
  153. sb.append(" ");
  154. sb.append(it.value.value_name);
  155. }
  156. if (it.value.required)
  157. sb.append("> ");
  158. else
  159. sb.append("] ");
  160. }
  161. for (auto& arg : m_single_args) {
  162. if (arg.required)
  163. sb.append("<");
  164. else
  165. sb.append("[");
  166. sb.append(arg.name);
  167. if (arg.required)
  168. sb.append("> ");
  169. else
  170. sb.append("] ");
  171. }
  172. sb.append("\n");
  173. for (auto& it : m_args) {
  174. sb.append(" ");
  175. sb.append(m_prefix);
  176. sb.append(it.value.name);
  177. if (!it.value.value_name.is_null()) {
  178. sb.append(" ");
  179. sb.append(it.value.value_name);
  180. }
  181. sb.append(" : ");
  182. sb.append(it.value.description);
  183. sb.append("\n");
  184. }
  185. return sb.to_string();
  186. }
  187. void CArgsParser::print_usage() const
  188. {
  189. printf("%s\n", get_usage().characters());
  190. }