CArgsParser.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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);
  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.substring(0, m_prefix.length()) == m_prefix;
  89. }
  90. bool CArgsParser::check_required_args(const CArgsParserResult& res)
  91. {
  92. for (auto& it : m_args) {
  93. if (it.value.required) {
  94. if (!res.is_present(it.value.name))
  95. return false;
  96. }
  97. }
  98. int required_arguments = 0;
  99. for (const auto& a : m_single_args) {
  100. if (a.required) {
  101. required_arguments++;
  102. }
  103. }
  104. if (required_arguments != 0) {
  105. if (res.m_single_values.size() < required_arguments)
  106. return false;
  107. }
  108. return true;
  109. }
  110. void CArgsParser::add_required_arg(const String& name, const String& description)
  111. {
  112. m_args.set(name, Arg(name, description, true));
  113. }
  114. void CArgsParser::add_required_arg(const String& name, const String& value_name, const String& description)
  115. {
  116. m_args.set(name, Arg(name, value_name, description, true));
  117. }
  118. void CArgsParser::add_arg(const String& name, const String& description)
  119. {
  120. m_args.set(name, Arg(name, description, false));
  121. }
  122. void CArgsParser::add_arg(const String& name, const String& value_name, const String& description)
  123. {
  124. m_args.set(name, Arg(name, value_name, description, false));
  125. }
  126. void CArgsParser::add_single_value(const String& name)
  127. {
  128. m_single_args.append(SingleArg { name, false });
  129. }
  130. void CArgsParser::add_required_single_value(const String& name)
  131. {
  132. if (m_single_args.size() != 0) {
  133. // adding required arguments after non-required arguments would be nonsensical
  134. ASSERT(m_single_args.last().required);
  135. }
  136. m_single_args.append(SingleArg { name, true });
  137. }
  138. String CArgsParser::get_usage() const
  139. {
  140. StringBuilder sb;
  141. sb.append("usage : ");
  142. sb.append(m_program_name);
  143. sb.append(" ");
  144. for (auto& it : m_args) {
  145. if (it.value.required)
  146. sb.append("<");
  147. else
  148. sb.append("[");
  149. sb.append(m_prefix);
  150. sb.append(it.value.name);
  151. if (!it.value.value_name.is_null()) {
  152. sb.append(" ");
  153. sb.append(it.value.value_name);
  154. }
  155. if (it.value.required)
  156. sb.append("> ");
  157. else
  158. sb.append("] ");
  159. }
  160. for (auto& arg : m_single_args) {
  161. if (arg.required)
  162. sb.append("<");
  163. else
  164. sb.append("[");
  165. sb.append(arg.name);
  166. if (arg.required)
  167. sb.append("> ");
  168. else
  169. sb.append("] ");
  170. }
  171. sb.append("\n");
  172. for (auto& it : m_args) {
  173. sb.append(" ");
  174. sb.append(m_prefix);
  175. sb.append(it.value.name);
  176. if (!it.value.value_name.is_null()) {
  177. sb.append(" ");
  178. sb.append(it.value.value_name);
  179. }
  180. sb.append(" : ");
  181. sb.append(it.value.description);
  182. sb.append("\n");
  183. }
  184. return sb.to_string();
  185. }
  186. void CArgsParser::print_usage() const
  187. {
  188. printf("%s\n", get_usage().characters());
  189. }