| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | #include "CArgsParser.h"
 | 
					
						
							|  |  |  | #include <AK/StringBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | bool CArgsParserResult::is_present(const String& arg_name) const | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_args.contains(arg_name); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | String CArgsParserResult::get(const String& arg_name) const | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-24 10:25:43 +02:00
										 |  |  |     return m_args.get(arg_name).value_or({}); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | const Vector<String>& CArgsParserResult::get_single_values() const | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_single_values; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | CArgsParser::Arg::Arg(const String& name, const String& description, bool required) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     : name(name) | 
					
						
							|  |  |  |     , description(description) | 
					
						
							|  |  |  |     , required(required) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | CArgsParser::Arg::Arg(const String& name, const String& value_name, const String& description, bool required) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     : name(name) | 
					
						
							|  |  |  |     , description(description) | 
					
						
							|  |  |  |     , value_name(value_name) | 
					
						
							|  |  |  |     , required(required) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | CArgsParser::CArgsParser(const String& program_name) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     : m_program_name(program_name) | 
					
						
							|  |  |  |     , m_prefix("-") | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-22 15:47:08 +02:00
										 |  |  | CArgsParserResult CArgsParser::parse(int argc, char** argv) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  |     CArgsParserResult res; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |     // We should have at least one parameter
 | 
					
						
							|  |  |  |     if (argc < 2) | 
					
						
							|  |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |     // We parse the first parameter at the index 1
 | 
					
						
							|  |  |  |     if (parse_next_param(1, argv, argc - 1, res) != 0) | 
					
						
							|  |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |     if (!check_required_args(res)) | 
					
						
							|  |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-22 15:47:08 +02:00
										 |  |  | int CArgsParser::parse_next_param(int index, char** argv, const int params_left, CArgsParserResult& res) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (params_left == 0) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     String param = argv[index]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // We check if the prefix is found at the beginning of the param name
 | 
					
						
							|  |  |  |     if (is_param_valid(param)) { | 
					
						
							|  |  |  |         auto prefix_length = m_prefix.length(); | 
					
						
							|  |  |  |         String param_name = param.substring(prefix_length, param.length() - prefix_length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto arg = m_args.find(param_name); | 
					
						
							|  |  |  |         if (arg == m_args.end()) { | 
					
						
							|  |  |  |             printf("Unknown arg \""); | 
					
						
							|  |  |  |             if (!param_name.is_null()) | 
					
						
							|  |  |  |                 printf("%s", param_name.characters()); | 
					
						
							|  |  |  |             printf("\"\n"); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // If this parameter must be followed by a value, we look for it
 | 
					
						
							|  |  |  |         if (!arg->value.value_name.is_null()) { | 
					
						
							|  |  |  |             if (params_left < 1) { | 
					
						
							|  |  |  |                 printf("Missing value for argument %s\n", arg->value.name.characters()); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             String next = String(argv[index + 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (is_param_valid(next)) { | 
					
						
							|  |  |  |                 printf("Missing value for argument %s\n", arg->value.name.characters()); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             res.m_args.set(arg->value.name, next); | 
					
						
							|  |  |  |             return parse_next_param(index + 2, argv, params_left - 2, res); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Single argument, not followed by a value
 | 
					
						
							|  |  |  |         res.m_args.set(arg->value.name, ""); | 
					
						
							|  |  |  |         return parse_next_param(index + 1, argv, params_left - 1, res); | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |     // Else, it's a value alone, a file name parameter for example
 | 
					
						
							|  |  |  |     res.m_single_values.append(param); | 
					
						
							|  |  |  |     return parse_next_param(index + 1, argv, params_left - 1, res); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | bool CArgsParser::is_param_valid(const String& param_name) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-08-17 12:22:31 +03:00
										 |  |  |     return param_name.length() >= m_prefix.length() && | 
					
						
							|  |  |  |         param_name.substring(0, m_prefix.length()) == m_prefix; | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | bool CArgsParser::check_required_args(const CArgsParserResult& res) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     for (auto& it : m_args) { | 
					
						
							|  |  |  |         if (it.value.required) { | 
					
						
							|  |  |  |             if (!res.is_present(it.value.name)) | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:17:43 +02:00
										 |  |  |     int required_arguments = 0; | 
					
						
							|  |  |  |     for (const auto& a : m_single_args) { | 
					
						
							|  |  |  |         if (a.required) { | 
					
						
							|  |  |  |             required_arguments++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (required_arguments != 0) { | 
					
						
							|  |  |  |         if (res.m_single_values.size() < required_arguments) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  |             return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | void CArgsParser::add_required_arg(const String& name, const String& description) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-17 12:51:44 +02:00
										 |  |  |     m_args.set(name, Arg(name, description, true)); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | void CArgsParser::add_required_arg(const String& name, const String& value_name, const String& description) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-17 12:51:44 +02:00
										 |  |  |     m_args.set(name, Arg(name, value_name, description, true)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | void CArgsParser::add_arg(const String& name, const String& description) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:51:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     m_args.set(name, Arg(name, description, false)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | void CArgsParser::add_arg(const String& name, const String& value_name, const String& description) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:51:44 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     m_args.set(name, Arg(name, value_name, description, false)); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | void CArgsParser::add_single_value(const String& name) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     m_single_args.append(SingleArg { name, false }); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | void CArgsParser::add_required_single_value(const String& name) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-17 15:17:43 +02:00
										 |  |  |     if (m_single_args.size() != 0) { | 
					
						
							|  |  |  |         // adding required arguments after non-required arguments would be nonsensical
 | 
					
						
							|  |  |  |         ASSERT(m_single_args.last().required); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     m_single_args.append(SingleArg { name, true }); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | String CArgsParser::get_usage() const | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     StringBuilder sb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sb.append("usage : "); | 
					
						
							|  |  |  |     sb.append(m_program_name); | 
					
						
							|  |  |  |     sb.append(" "); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& it : m_args) { | 
					
						
							|  |  |  |         if (it.value.required) | 
					
						
							|  |  |  |             sb.append("<"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             sb.append("["); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         sb.append(m_prefix); | 
					
						
							|  |  |  |         sb.append(it.value.name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!it.value.value_name.is_null()) { | 
					
						
							|  |  |  |             sb.append(" "); | 
					
						
							|  |  |  |             sb.append(it.value.value_name); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |         if (it.value.required) | 
					
						
							|  |  |  |             sb.append("> "); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             sb.append("] "); | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:17:43 +02:00
										 |  |  |     for (auto& arg : m_single_args) { | 
					
						
							|  |  |  |         if (arg.required) | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  |             sb.append("<"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             sb.append("["); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:17:43 +02:00
										 |  |  |         sb.append(arg.name); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:17:43 +02:00
										 |  |  |         if (arg.required) | 
					
						
							|  |  |  |             sb.append("> "); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2019-05-17 15:17:43 +02:00
										 |  |  |             sb.append("] "); | 
					
						
							| 
									
										
										
										
											2019-05-17 12:59:37 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  |     sb.append("\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& it : m_args) { | 
					
						
							|  |  |  |         sb.append("    "); | 
					
						
							|  |  |  |         sb.append(m_prefix); | 
					
						
							|  |  |  |         sb.append(it.value.name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!it.value.value_name.is_null()) { | 
					
						
							|  |  |  |             sb.append(" "); | 
					
						
							|  |  |  |             sb.append(it.value.value_name); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         sb.append(" : "); | 
					
						
							|  |  |  |         sb.append(it.value.description); | 
					
						
							|  |  |  |         sb.append("\n"); | 
					
						
							| 
									
										
										
										
											2019-05-13 05:31:23 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return sb.to_string(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-17 15:35:30 +02:00
										 |  |  | void CArgsParser::print_usage() const | 
					
						
							| 
									
										
										
										
											2019-05-17 12:46:51 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     printf("%s\n", get_usage().characters()); | 
					
						
							|  |  |  | } |