Fixed some crashes

This commit is contained in:
Cameron Reed 2022-07-26 21:26:02 -06:00
parent 03db3c64a2
commit fbb7a689e7
3 changed files with 63 additions and 47 deletions

View File

@ -7,6 +7,16 @@ namespace Cam
namespace Arguments namespace Arguments
{ {
enum ERROR {
IMPOSSIBLE = -1,
NO_ERROR,
ERROR_UNKNOWN_OPTION,
ERROR_INCORRECT_TYPE,
ERROR_MISSING_ARGUMENT,
ERROR_MISSING_POSITIONAL_ARGUMENT,
SPECIAL_CASE_HELP
};
enum OPTTYPE enum OPTTYPE
{ {
FLAG = 0, FLAG = 0,
@ -54,18 +64,18 @@ public:
void set_description(const char* description); void set_description(const char* description);
void add_option(Option* opt); void add_option(Option* opt);
void add_positional_argument(PositionalArgument* arg); void add_positional_argument(PositionalArgument* arg);
int parse(int argc, char** argv); ERROR parse(int argc, char** argv);
private: private:
int print_help_message(); ERROR print_help_message();
int handle_long_option(const char* option, const char* next_value); ERROR handle_long_option(const char* option, const char* next_value);
int handle_short_option(const char option, const char* next_value); ERROR handle_short_option(const char option, const char* next_value);
int handle_positional_argument(const char* arg); ERROR handle_positional_argument(const char* arg);
int get_option_data(Option* opt, const char* data_str); ERROR get_option_data(Option* opt, const char* option_name, const char* data_str);
int unknown_option(const char* option); ERROR unknown_option(const char* option);
int unknown_option(const char option); ERROR unknown_option(const char option);
int incorrect_type(const char* option, const char* got); ERROR incorrect_type(const char* option, const char* got);
int missing_argument(const char* option); ERROR missing_argument(const char* option);
int missing_positional_argument(const char* arg); ERROR missing_positional_argument(const char* arg);
private: private:
const char* m_program_name; const char* m_program_name;
const char* m_description; const char* m_description;

View File

@ -68,13 +68,13 @@ void Parser::add_positional_argument(PositionalArgument* arg)
m_positional_args.push_back(arg); m_positional_args.push_back(arg);
} }
int Parser::parse(int argc, char ** argv) ERROR Parser::parse(int argc, char ** argv)
{ {
for (m_opt_index = 1; m_opt_index < argc; m_opt_index++) for (m_opt_index = 1; m_opt_index < argc; m_opt_index++)
{ {
if (argv[m_opt_index][0] == '-' && argv[m_opt_index][1] == '-') { if (argv[m_opt_index][0] == '-' && argv[m_opt_index][1] == '-') {
int ret = handle_long_option(argv[m_opt_index] + 2, m_opt_index + 1 < argc ? argv[m_opt_index + 1] : nullptr); ERROR ret = handle_long_option(argv[m_opt_index] + 2, m_opt_index + 1 < argc ? argv[m_opt_index + 1] : nullptr);
if (ret) if (ret)
return ret; return ret;
@ -82,7 +82,7 @@ int Parser::parse(int argc, char ** argv)
for (uint8_t i = 1; argv[m_opt_index][i] != 0; i++) { for (uint8_t i = 1; argv[m_opt_index][i] != 0; i++) {
bool last = argv[m_opt_index][i + 1] == 0; bool last = argv[m_opt_index][i + 1] == 0;
int ret = handle_short_option(argv[m_opt_index][i], m_opt_index + 1 < argc && last ? argv[m_opt_index + 1] : nullptr); ERROR ret = handle_short_option(argv[m_opt_index][i], m_opt_index + 1 < argc && last ? argv[m_opt_index + 1] : nullptr);
if (ret) if (ret)
return ret; return ret;
if (last) if (last)
@ -91,7 +91,7 @@ int Parser::parse(int argc, char ** argv)
} else { } else {
int ret = handle_positional_argument(argv[m_opt_index]); ERROR ret = handle_positional_argument(argv[m_opt_index]);
if (ret) if (ret)
return ret; return ret;
@ -105,14 +105,16 @@ int Parser::parse(int argc, char ** argv)
} }
} }
return 0; return NO_ERROR;
} }
int Parser::handle_long_option(const char* option, const char* next_value) ERROR Parser::handle_long_option(const char* option, const char* next_value)
{ {
Option* matched_option = nullptr; Option* matched_option = nullptr;
for (Option* opt: m_options) { for (Option* opt: m_options) {
if (opt->m_name == nullptr)
continue;
if (strcmp(opt->m_name, option) == 0) { if (strcmp(opt->m_name, option) == 0) {
matched_option = opt; matched_option = opt;
break; break;
@ -129,16 +131,16 @@ int Parser::handle_long_option(const char* option, const char* next_value)
} else { } else {
matched_option->m_found = true; matched_option->m_found = true;
return get_option_data(matched_option, next_value); return get_option_data(matched_option, matched_option->m_name, next_value);
} }
std::cout << "Congratulations! You have reached an impossible state" << std::endl << std::endl; std::cout << "Congratulations! You have reached an impossible state" << std::endl << std::endl;
std::cout << "Reality is broken :)" << std::endl; std::cout << "Reality is broken :)" << std::endl;
return -1; return IMPOSSIBLE;
} }
int Parser::handle_short_option(const char option, const char* next_value) ERROR Parser::handle_short_option(const char option, const char* next_value)
{ {
Option* matched_option = nullptr; Option* matched_option = nullptr;
@ -159,16 +161,20 @@ int Parser::handle_short_option(const char option, const char* next_value)
} else { } else {
matched_option->m_found = true; matched_option->m_found = true;
return get_option_data(matched_option, next_value); char* name = new char[2];
name[0] = matched_option->m_short_name;
name[1] = 0;
return get_option_data(matched_option, name, next_value);
delete[] name;
} }
std::cout << "Congratulations! You have reached impossible state #2" << std::endl << std::endl; std::cout << "Congratulations! You have reached impossible state #2" << std::endl << std::endl;
std::cout << "Reality is broken :)" << std::endl; std::cout << "Reality is broken :)" << std::endl;
return -1; return IMPOSSIBLE;
} }
int Parser::handle_positional_argument(const char* arg) ERROR Parser::handle_positional_argument(const char* arg)
{ {
if (m_pos_index >= m_positional_args.size()) if (m_pos_index >= m_positional_args.size())
return unknown_option(arg); return unknown_option(arg);
@ -187,16 +193,16 @@ int Parser::handle_positional_argument(const char* arg)
pos_arg->m_found = true; pos_arg->m_found = true;
m_pos_index++; m_pos_index++;
return 0; return NO_ERROR;
} }
int Parser::get_option_data(Option* opt, const char* data_str) ERROR Parser::get_option_data(Option* opt, const char* option_name, const char* data_str)
{ {
if (opt->m_type == FLAG) if (opt->m_type == FLAG)
return 0; return NO_ERROR;
if (data_str == nullptr || data_str[0] == '-') if (data_str == nullptr || data_str[0] == '-')
return missing_argument(opt->m_name); return missing_argument(option_name);
if (opt->m_type == INT) { if (opt->m_type == INT) {
int* val = new int; int* val = new int;
@ -208,48 +214,48 @@ int Parser::get_option_data(Option* opt, const char* data_str)
} }
m_opt_index++; m_opt_index++;
return 0; return NO_ERROR;
} }
int Parser::unknown_option(const char* option) ERROR Parser::unknown_option(const char* option)
{ {
std::cout << m_program_name << ": invalid option '" << option << '\'' << std::endl << std::endl; std::cout << m_program_name << ": invalid option '" << option << '\'' << std::endl << std::endl;
std::cout << "See " << m_program_name << " --help" << std::endl; std::cout << "See " << m_program_name << " --help" << std::endl;
return -1; return ERROR_UNKNOWN_OPTION;
} }
int Parser::unknown_option(const char option) ERROR Parser::unknown_option(const char option)
{ {
std::cout << m_program_name << ": invalid option: " << option << std::endl << std::endl; std::cout << m_program_name << ": invalid option: " << option << std::endl << std::endl;
std::cout << "See " << m_program_name << " --help" << std::endl; std::cout << "See " << m_program_name << " --help" << std::endl;
return -1; return ERROR_UNKNOWN_OPTION;
} }
int Parser::incorrect_type(const char* option, const char* got) ERROR Parser::incorrect_type(const char* option, const char* got)
{ {
std::cout << m_program_name << ": argument '" << option << "' expects an integer as an argument, got " << got << " instead" << std::endl; std::cout << m_program_name << ": argument '" << option << "' expects an integer as an argument, got " << got << " instead" << std::endl;
return -4; return ERROR_INCORRECT_TYPE;
} }
int Arguments::Parser::missing_argument(const char* option) ERROR Parser::missing_argument(const char* option)
{ {
std::cout << m_program_name << ": Missing argument for option '" << option << '\'' << std::endl; std::cout << m_program_name << ": Missing argument for option '" << option << '\'' << std::endl;
return -3; return ERROR_MISSING_ARGUMENT;
} }
int Parser::missing_positional_argument(const char* arg) ERROR Parser::missing_positional_argument(const char* arg)
{ {
std::cout << m_program_name << ": Missing required positional argument '" << arg << "'" << std::endl << std::endl; std::cout << m_program_name << ": Missing required positional argument '" << arg << "'" << std::endl << std::endl;
std::cout << "See " << m_program_name << " --help" << std::endl; std::cout << "See " << m_program_name << " --help" << std::endl;
return -5; return ERROR_MISSING_POSITIONAL_ARGUMENT;
} }
int Parser::print_help_message() ERROR Parser::print_help_message()
{ {
std::cout << "Usage: " << m_program_name << (m_options.size() > 0 ? " [OPTIONS]" : ""); std::cout << "Usage: " << m_program_name << (m_options.size() > 0 ? " [OPTIONS]" : "");
for (PositionalArgument* arg: m_positional_args) for (PositionalArgument* arg: m_positional_args)
@ -273,11 +279,11 @@ int Parser::print_help_message()
if (opt->m_name != nullptr) if (opt->m_name != nullptr)
std::cout << "--" << opt->m_name; std::cout << "--" << opt->m_name;
if (opt->m_short_name != 0) { if (opt->m_name != nullptr) {
for (uint8_t i = 0; i < 16 - strlen(opt->m_name); i++) for (uint8_t i = 0; i < 20 - strlen(opt->m_name) - ((opt->m_short_name != 0) * 4); i++)
std::cout << ' '; std::cout << ' ';
} else { } else {
for (uint8_t i = 0; i < 20 - strlen(opt->m_name); i++) for (uint8_t i = 0; i < 24 - ((opt->m_short_name != 0) * 4); i++)
std::cout << ' '; std::cout << ' ';
} }
@ -287,7 +293,7 @@ int Parser::print_help_message()
if (m_description) if (m_description)
std::cout << std::endl << std::endl << m_description << std::endl; std::cout << std::endl << std::endl << m_description << std::endl;
return 1; return SPECIAL_CASE_HELP;
} }
} // namespace Arguments } // namespace Arguments

View File

@ -8,11 +8,11 @@ int main(int argc, char **argv) {
parser.set_description("A test of argument parsing :)"); parser.set_description("A test of argument parsing :)");
Arguments::Option first("first", 'f', "First arg", Arguments::STRING); Arguments::Option first('f', "First arg", Arguments::STRING);
Arguments::Option second("second", 's', "Second arg", Arguments::INT); Arguments::Option second("second", 's', "Second arg", Arguments::INT);
Arguments::Option third("third", 't', "Third arg", Arguments::FLAG); Arguments::Option third("third", "Third arg", Arguments::FLAG);
Arguments::PositionalArgument name("name", false, Arguments::STRING); Arguments::PositionalArgument name("name", true, Arguments::STRING);
Arguments::PositionalArgument age("age", false, Arguments::INT); Arguments::PositionalArgument age("age", false, Arguments::INT);
parser.add_option(&first); parser.add_option(&first);
@ -23,7 +23,7 @@ int main(int argc, char **argv) {
parser.add_positional_argument(&age); parser.add_positional_argument(&age);
if (parser.parse(argc, argv) != 0) { if (parser.parse(argc, argv) != 0) {
return -1; return 0;
} }
std::cout << "Found:" << std::endl; std::cout << "Found:" << std::endl;