diff options
author | 2022-02-21 08:47:03 -0500 | |
---|---|---|
committer | 2022-02-21 08:52:50 -0500 | |
commit | e10f87d9fcd6fe9754fd230f65f1cd6abe328cd2 (patch) | |
tree | 618df432b30afccfee0b4da9b160b2aa041ae9d8 /src | |
parent | 1f2fb58b875e06fa6eff6628a7da815bbd9cedbe (diff) |
debugcon.cpp: Use std::string_view in command parsing and eliminate initial buffer copy
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/debug/debugcon.cpp | 241 | ||||
-rw-r--r-- | src/emu/debug/debugcon.h | 17 |
2 files changed, 118 insertions, 140 deletions
diff --git a/src/emu/debug/debugcon.cpp b/src/emu/debug/debugcon.cpp index 210087ab1c0..508c2377f54 100644 --- a/src/emu/debug/debugcon.cpp +++ b/src/emu/debug/debugcon.cpp @@ -92,9 +92,9 @@ debugger_console::~debugger_console() } -/*------------------------------------------------- - exit - frees the console system --------------------------------------------------*/ +//------------------------------------------------- +// exit - frees the console system +//------------------------------------------------- void debugger_console::exit() { @@ -119,41 +119,39 @@ void debugger_console::exit() inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const debug_command &b) const { - return core_stricmp(a.command.c_str(), b.command.c_str()) < 0; + return a.command < b.command; } inline bool debugger_console::debug_command::compare::operator()(const char *a, const debug_command &b) const { - return core_stricmp(a, b.command.c_str()) < 0; + return strcmp(a, b.command.c_str()) < 0; } inline bool debugger_console::debug_command::compare::operator()(const debug_command &a, const char *b) const { - return core_stricmp(a.command.c_str(), b) < 0; + return strcmp(a.command.c_str(), b) < 0; } -debugger_console::debug_command::debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler) +debugger_console::debug_command::debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler) : command(_command), params(nullptr), help(nullptr), handler(std::move(_handler)), flags(_flags), minparams(_minparams), maxparams(_maxparams) { } -/*------------------------------------------------------------ - execute_help_custom - execute the helpcustom command -------------------------------------------------------------*/ +//------------------------------------------------------------ +// execute_help_custom - execute the helpcustom command +//------------------------------------------------------------ void debugger_console::execute_help_custom(const std::vector<std::string> ¶ms) { - char buf[64]; for (const debug_command &cmd : m_commandlist) { if (cmd.flags & CMDFLAG_CUSTOM_HELP) { - snprintf(buf, 63, "%s help", cmd.command.c_str()); - buf[63] = 0; - char *temp_params[1] = { buf }; - internal_execute_command(true, 1, &temp_params[0]); + std::string buf = cmd.command + " help"; + std::vector<std::string_view> temp_params = { buf }; + internal_execute_command(true, temp_params); } } } @@ -207,159 +205,145 @@ symbol_table &debugger_console::visible_symtable() -/*------------------------------------------------- - trim_parameter - executes a - command --------------------------------------------------*/ +//------------------------------------------------- +// trim_parameter - trim spaces and quotes around +// a command parameter +//------------------------------------------------- -void debugger_console::trim_parameter(char **paramptr, bool keep_quotes) +std::string_view debugger_console::trim_parameter(std::string_view param, bool keep_quotes) { - char *param = *paramptr; - size_t len = strlen(param); + std::string_view::size_type len = param.length(); bool repeat; - /* loop until all adornments are gone */ + // loop until all adornments are gone do { repeat = false; - /* check for begin/end quotes */ + // check for begin/end quotes if (len >= 2 && param[0] == '"' && param[len - 1] == '"') { if (!keep_quotes) { - param[len - 1] = 0; - param++; + param = param.substr(1, len - 2); len -= 2; } } - /* check for start/end braces */ + // check for start/end braces else if (len >= 2 && param[0] == '{' && param[len - 1] == '}') { - param[len - 1] = 0; - param++; + param = param.substr(1, len - 2); len -= 2; repeat = true; } - /* check for leading spaces */ + // check for leading spaces else if (len >= 1 && param[0] == ' ') { - param++; + param.remove_prefix(1); len--; repeat = true; } - /* check for trailing spaces */ + // check for trailing spaces else if (len >= 1 && param[len - 1] == ' ') { - param[len - 1] = 0; + param.remove_suffix(1); len--; repeat = true; } } while (repeat); - *paramptr = param; + return param; } -/*------------------------------------------------- - internal_execute_command - executes a - command --------------------------------------------------*/ +//------------------------------------------------- +// internal_execute_command - executes a +// command +//------------------------------------------------- -CMDERR debugger_console::internal_execute_command(bool execute, int params, char **param) +CMDERR debugger_console::internal_execute_command(bool execute, std::vector<std::string_view> ¶ms) { // no params is an error - if (params == 0) + if (params.empty()) return CMDERR::none(); // the first parameter has the command and the real first parameter; separate them - char *p, *command; - for (p = param[0]; *p && isspace(u8(*p)); p++) { } - for (command = p; *p && !isspace(u8(*p)); p++) { } - if (*p != 0) - { - *p++ = 0; - for ( ; *p && isspace(u8(*p)); p++) { } - if (*p != 0) - param[0] = p; - else - params = 0; - } + std::string_view command_param = params[0]; + std::string_view::size_type pos = 0; + while (pos < command_param.length() && !isspace(u8(command_param[pos]))) + pos++; + const std::string command(strmakelower(command_param.substr(0, pos))); + while (pos < command_param.length() && isspace(u8(command_param[pos]))) + pos++; + if (pos == command_param.length() && params.size() == 1) + params.clear(); else - { - params = 0; - param[0] = nullptr; - } + params[0].remove_prefix(pos); // search the command list - size_t const len = strlen(command); - auto const found = m_commandlist.lower_bound(command); + auto const found = m_commandlist.lower_bound(command.c_str()); // error if not found - if ((m_commandlist.end() == found) || core_strnicmp(command, found->command.c_str(), len)) + if (m_commandlist.end() == found || std::string_view(command) != std::string_view(found->command).substr(0, command.length())) return CMDERR::unknown_command(0); - if (found->command.length() > len) + if (found->command.length() > command.length()) { auto const next = std::next(found); - if ((m_commandlist.end() != next) && !core_strnicmp(command, next->command.c_str(), len)) + if (m_commandlist.end() != next && std::string_view(command) == std::string_view(next->command).substr(0, command.length())) return CMDERR::ambiguous_command(0); } - // NUL-terminate and trim space around all the parameters - for (int i = 1; i < params; i++) - *param[i]++ = 0; - // now go back and trim quotes and braces and any spaces they reveal - for (int i = 0; i < params; i++) - trim_parameter(¶m[i], found->flags & CMDFLAG_KEEP_QUOTES); + for (std::string_view ¶m : params) + param = trim_parameter(param, found->flags & CMDFLAG_KEEP_QUOTES); // see if we have the right number of parameters - if (params < found->minparams) + if (params.size() < found->minparams) return CMDERR::not_enough_params(0); - if (params > found->maxparams) + if (params.size() > found->maxparams) return CMDERR::too_many_params(0); // execute the handler if (execute) { - std::vector<std::string> params_vec(param, param + params); + std::vector<std::string> params_vec(params.begin(), params.end()); found->handler(params_vec); } return CMDERR::none(); } -/*------------------------------------------------- - internal_parse_command - parses a command - and either executes or just validates it --------------------------------------------------*/ +//------------------------------------------------- +// internal_parse_command - parses a command +// and either executes or just validates it +//------------------------------------------------- -CMDERR debugger_console::internal_parse_command(const std::string &original_command, bool execute) +CMDERR debugger_console::internal_parse_command(std::string_view command, bool execute) { - char command[MAX_COMMAND_LENGTH], parens[MAX_COMMAND_LENGTH]; - char *params[MAX_COMMAND_PARAMS] = { nullptr }; - char *command_start; - char *p, c = 0; - - /* make a copy of the command */ - strcpy(command, original_command.c_str()); + std::string_view::size_type pos = 0; + std::string_view::size_type len = command.length(); - /* loop over all semicolon-separated stuff */ - for (p = command; *p != 0; ) + while (pos < len) { - int paramcount = 0, parendex = 0; + std::string parens; + std::vector<std::string_view> params; bool foundend = false, instring = false, isexpr = false; - /* find a semicolon or the end */ - for (params[paramcount++] = p; !foundend; p++) + // skip leading spaces + while (pos < len && isspace(u8(command[pos]))) + pos++; + std::string_view::size_type startpos = pos; + + // find a semicolon or the end + for (params.push_back(command.substr(pos)); !foundend && pos < len; pos++) { - c = *p; + char c = command[pos]; if (instring) { - if (c == '"' && p[-1] != '\\') + if (c == '"' && command[pos - 1] != '\\') instring = false; } else @@ -369,47 +353,42 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm case '"': instring = true; break; case '(': case '[': - case '{': parens[parendex++] = c; break; - case ')': if (parendex == 0 || parens[--parendex] != '(') return CMDERR::unbalanced_parens(p - command); break; - case ']': if (parendex == 0 || parens[--parendex] != '[') return CMDERR::unbalanced_parens(p - command); break; - case '}': if (parendex == 0 || parens[--parendex] != '{') return CMDERR::unbalanced_parens(p - command); break; - case ',': if (parendex == 0) params[paramcount++] = p; break; - case ';': if (parendex == 0) foundend = true; break; - case '-': if (parendex == 0 && paramcount == 1 && p[1] == '-') isexpr = true; *p = c; break; - case '+': if (parendex == 0 && paramcount == 1 && p[1] == '+') isexpr = true; *p = c; break; - case '=': if (parendex == 0 && paramcount == 1) isexpr = true; *p = c; break; - case 0: foundend = true; break; - default: *p = c; break; + case '{': parens.push_back(c); break; + case ')': if (parens.empty() || parens.back() != '(') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break; + case ']': if (parens.empty() || parens.back() != '[') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break; + case '}': if (parens.empty() || parens.back() != '{') return CMDERR::unbalanced_parens(pos); parens.pop_back(); break; + case ',': if (parens.empty()) { params.back().remove_suffix(len - pos); params.push_back(command.substr(pos + 1)); } break; + case ';': if (parens.empty()) { params.back().remove_suffix(len - pos); foundend = true; } break; + case '-': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '-') isexpr = true; break; + case '+': if (parens.empty() && params.size() == 1 && pos > 0 && command[pos - 1] == '+') isexpr = true; break; + case '=': if (parens.empty() && params.size() == 1) isexpr = true; break; + default: break; } } } - /* check for unbalanced parentheses or quotes */ + // check for unbalanced parentheses or quotes if (instring) - return CMDERR::unbalanced_quotes(p - command); - if (parendex != 0) - return CMDERR::unbalanced_parens(p - command); - - /* NULL-terminate if we ended in a semicolon */ - p--; - if (c == ';') *p++ = 0; + return CMDERR::unbalanced_quotes(pos); + if (!parens.empty()) + return CMDERR::unbalanced_parens(pos); - /* process the command */ - command_start = params[0]; + // process the command + std::string_view command_or_expr = params[0]; - /* allow for "do" commands */ - if (tolower(u8(command_start[0])) == 'd' && tolower(u8(command_start[1])) == 'o' && isspace(u8(command_start[2]))) + // allow for "do" commands + if (command_or_expr.length() > 3 && tolower(u8(command_or_expr[0])) == 'd' && tolower(u8(command_or_expr[1])) == 'o' && isspace(u8(command_or_expr[2]))) { isexpr = true; - command_start += 3; + command_or_expr.remove_prefix(3); } - /* if it smells like an assignment expression, treat it as such */ - if (isexpr && paramcount == 1) + // if it smells like an assignment expression, treat it as such + if (isexpr && params.size() == 1) { try { - parsed_expression(visible_symtable(), command_start).execute(); + parsed_expression(visible_symtable(), command_or_expr).execute(); } catch (expression_error &err) { @@ -418,29 +397,29 @@ CMDERR debugger_console::internal_parse_command(const std::string &original_comm } else { - const CMDERR result = internal_execute_command(execute, paramcount, ¶ms[0]); + const CMDERR result = internal_execute_command(execute, params); if (result.error_class() != CMDERR::NONE) - return CMDERR(result.error_class(), command_start - command); + return CMDERR(result.error_class(), startpos); } } return CMDERR::none(); } -/*------------------------------------------------- - execute_command - execute a command string --------------------------------------------------*/ +//------------------------------------------------- +// execute_command - execute a command string +//------------------------------------------------- -CMDERR debugger_console::execute_command(const std::string &command, bool echo) +CMDERR debugger_console::execute_command(std::string_view command, bool echo) { - /* echo if requested */ + // echo if requested if (echo) printf(">%s\n", command); - /* parse and execute */ + // parse and execute const CMDERR result = internal_parse_command(command, true); - /* display errors */ + // display errors if (result.error_class() != CMDERR::NONE) { if (!echo) @@ -449,7 +428,7 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo) printf("%s\n", cmderr_to_string(result)); } - /* update all views */ + // update all views if (echo) { m_machine.debug_view().update_all(); @@ -459,11 +438,11 @@ CMDERR debugger_console::execute_command(const std::string &command, bool echo) } -/*------------------------------------------------- - validate_command - validate a command string --------------------------------------------------*/ +//------------------------------------------------- +// validate_command - validate a command string +//------------------------------------------------- -CMDERR debugger_console::validate_command(const char *command) +CMDERR debugger_console::validate_command(std::string_view command) { return internal_parse_command(command, false); } @@ -473,7 +452,7 @@ CMDERR debugger_console::validate_command(const char *command) register_command - register a command handler -------------------------------------------------*/ -void debugger_console::register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler) +void debugger_console::register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler) { if (m_machine.phase() != machine_phase::INIT) throw emu_fatalerror("Can only call debugger_console::register_command() at init time!"); diff --git a/src/emu/debug/debugcon.h b/src/emu/debug/debugcon.h index f8a0bafc7c1..974a43e656a 100644 --- a/src/emu/debug/debugcon.h +++ b/src/emu/debug/debugcon.h @@ -23,8 +23,7 @@ CONSTANTS ***************************************************************************/ -#define MAX_COMMAND_LENGTH 4096 -#define MAX_COMMAND_PARAMS 128 +constexpr int MAX_COMMAND_PARAMS = 128; // flags for command parsing constexpr u32 CMDFLAG_NONE = 0x0000; @@ -82,9 +81,9 @@ public: ~debugger_console(); // command handling - CMDERR execute_command(const std::string &command, bool echo); - CMDERR validate_command(const char *command); - void register_command(const char *command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler); + CMDERR execute_command(std::string_view command, bool echo); + CMDERR validate_command(std::string_view command); + void register_command(std::string_view command, u32 flags, int minparams, int maxparams, std::function<void (const std::vector<std::string> &)> &&handler); void source_script(const char *file); void process_source_file(); @@ -123,16 +122,16 @@ private: void execute_help_custom(const std::vector<std::string> ¶ms); void execute_condump(const std::vector<std::string>& params); - void trim_parameter(char **paramptr, bool keep_quotes); - CMDERR internal_execute_command(bool execute, int params, char **param); - CMDERR internal_parse_command(const std::string &original_command, bool execute); + [[nodiscard]] static std::string_view trim_parameter(std::string_view param, bool keep_quotes); + CMDERR internal_execute_command(bool execute, std::vector<std::string_view> ¶ms); + CMDERR internal_parse_command(std::string_view command, bool execute); void print_core(std::string_view text); // core text output void print_core_wrap(std::string_view text, int wrapcol); // core text output struct debug_command { - debug_command(const char *_command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler); + debug_command(std::string_view _command, u32 _flags, int _minparams, int _maxparams, std::function<void (const std::vector<std::string> &)> &&_handler); struct compare { |