/** * Register a an alias for an already existing command in the console * @param name name of the alias that will be used * @param cmd name of the command that 'name' will be alias of */ void IConsoleAliasRegister(const char *name, const char *cmd) { if (IConsoleAliasGet(name) != NULL) { IConsoleError("an alias with this name already exists; insertion aborted"); return; } char *new_alias = RemoveUnderscores(stredup(name)); char *cmd_aliased = stredup(cmd); IConsoleAlias *item_new = MallocT<IConsoleAlias>(1); item_new->next = NULL; item_new->cmdline = cmd_aliased; item_new->name = new_alias; IConsoleAddSorted(&_iconsole_aliases, item_new); }
/** * Execute a given command passed to us. First chop it up into * individual tokens (separated by spaces), then execute it if possible * @param cmdstr string to be parsed and executed */ void IConsoleCmdExec(const char *cmdstr) { const char *cmdptr; char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE]; uint t_index, tstream_i; bool longtoken = false; bool foundtoken = false; if (cmdstr[0] == '#') return; // comments for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) { if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) { IConsoleError("command contains malformed characters, aborting"); IConsolePrintF(CC_ERROR, "ERROR: command was: '%s'", cmdstr); return; } } DEBUG(console, 4, "Executing cmdline: '%s'", cmdstr); memset(&tokens, 0, sizeof(tokens)); memset(&tokenstream, 0, sizeof(tokenstream)); /* 1. Split up commandline into tokens, separated by spaces, commands * enclosed in "" are taken as one token. We can only go as far as the amount * of characters in our stream or the max amount of tokens we can handle */ for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) { if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break; switch (*cmdptr) { case ' ': // Token separator if (!foundtoken) break; if (longtoken) { tokenstream[tstream_i] = *cmdptr; } else { tokenstream[tstream_i] = '\0'; foundtoken = false; } tstream_i++; break; case '"': // Tokens enclosed in "" are one token longtoken = !longtoken; if (!foundtoken) { tokens[t_index++] = &tokenstream[tstream_i]; foundtoken = true; } break; case '\\': // Escape character for "" if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) { tokenstream[tstream_i++] = *++cmdptr; break; } /* FALL THROUGH */ default: // Normal character tokenstream[tstream_i++] = *cmdptr; if (!foundtoken) { tokens[t_index++] = &tokenstream[tstream_i - 1]; foundtoken = true; } break; } } for (uint i = 0; tokens[i] != NULL; i++) { DEBUG(console, 8, "Token %d is: '%s'", i, tokens[i]); } if (StrEmpty(tokens[0])) return; // don't execute empty commands /* 2. Determine type of command (cmd or alias) and execute * First try commands, then aliases. Execute * the found action taking into account its hooking code */ RemoveUnderscores(tokens[0]); IConsoleCmd *cmd = IConsoleCmdGet(tokens[0]); if (cmd != NULL) { ConsoleHookResult chr = (cmd->hook == NULL ? CHR_ALLOW : cmd->hook(true)); switch (chr) { case CHR_ALLOW: if (!cmd->proc(t_index, tokens)) { // index started with 0 cmd->proc(0, NULL); // if command failed, give help } return; case CHR_DISALLOW: return; case CHR_HIDE: break; } } t_index--; IConsoleAlias *alias = IConsoleAliasGet(tokens[0]); if (alias != NULL) { IConsoleAliasExec(alias, t_index, &tokens[1]); return; } IConsoleError("command not found"); }
/** * An alias is just another name for a command, or for more commands * Execute it as well. * @param *alias is the alias of the command * @param tokencount the number of parameters passed * @param *tokens are the parameters given to the original command (0 is the first param) */ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT]) { char alias_buffer[ICON_MAX_STREAMSIZE] = { '\0' }; char *alias_stream = alias_buffer; DEBUG(console, 6, "Requested command is an alias; parsing..."); for (const char *cmdptr = alias->cmdline; *cmdptr != '\0'; cmdptr++) { switch (*cmdptr) { case '\'': // ' will double for "" alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); break; case ';': // Cmd separator; execute previous and start new command IConsoleCmdExec(alias_buffer); alias_stream = alias_buffer; *alias_stream = '\0'; // Make sure the new command is terminated. cmdptr++; break; case '%': // Some or all parameters cmdptr++; switch (*cmdptr) { case '+': { // All parameters separated: "[param 1]" "[param 2]" for (uint i = 0; i != tokencount; i++) { if (i != 0) alias_stream = strecpy(alias_stream, " ", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, tokens[i], lastof(alias_buffer)); alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); } break; } case '!': { // Merge the parameters to one: "[param 1] [param 2] [param 3...]" alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); for (uint i = 0; i != tokencount; i++) { if (i != 0) alias_stream = strecpy(alias_stream, " ", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, tokens[i], lastof(alias_buffer)); } alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); break; } default: { // One specific parameter: %A = [param 1] %B = [param 2] ... int param = *cmdptr - 'A'; if (param < 0 || param >= tokencount) { IConsoleError("too many or wrong amount of parameters passed to alias, aborting"); IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline); return; } alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, tokens[param], lastof(alias_buffer)); alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); break; } } break; default: *alias_stream++ = *cmdptr; *alias_stream = '\0'; break; } if (alias_stream >= lastof(alias_buffer) - 1) { IConsoleError("Requested alias execution would overflow execution buffer"); return; } } IConsoleCmdExec(alias_buffer); }
/** * An alias is just another name for a command, or for more commands * Execute it as well. * @param *alias is the alias of the command * @param tokencount the number of parameters passed * @param *tokens are the parameters given to the original command (0 is the first param) */ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT]) { const char *cmdptr; char *aliases[ICON_MAX_ALIAS_LINES], aliasstream[ICON_MAX_STREAMSIZE]; uint i; uint a_index, astream_i; memset(&aliases, 0, sizeof(aliases)); memset(&aliasstream, 0, sizeof(aliasstream)); DEBUG(console, 6, "Requested command is an alias; parsing..."); aliases[0] = aliasstream; for (cmdptr = alias->cmdline, a_index = 0, astream_i = 0; *cmdptr != '\0'; cmdptr++) { if (a_index >= lengthof(aliases) || astream_i >= lengthof(aliasstream)) break; switch (*cmdptr) { case '\'': // ' will double for "" aliasstream[astream_i++] = '"'; break; case ';': // Cmd seperator, start new command aliasstream[astream_i] = '\0'; aliases[++a_index] = &aliasstream[++astream_i]; cmdptr++; break; case '%': // Some or all parameters cmdptr++; switch (*cmdptr) { case '+': { // All parameters seperated: "[param 1]" "[param 2]" for (i = 0; i != tokencount; i++) { aliasstream[astream_i++] = '"'; astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i); aliasstream[astream_i++] = '"'; aliasstream[astream_i++] = ' '; } } break; case '!': { // Merge the parameters to one: "[param 1] [param 2] [param 3...]" aliasstream[astream_i++] = '"'; for (i = 0; i != tokencount; i++) { astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[i], astream_i); aliasstream[astream_i++] = ' '; } aliasstream[astream_i++] = '"'; } break; default: { // One specific parameter: %A = [param 1] %B = [param 2] ... int param = *cmdptr - 'A'; if (param < 0 || param >= tokencount) { IConsoleError("too many or wrong amount of parameters passed to alias, aborting"); IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline); return; } aliasstream[astream_i++] = '"'; astream_i += IConsoleCopyInParams(&aliasstream[astream_i], tokens[param], astream_i); aliasstream[astream_i++] = '"'; } break; } break; default: aliasstream[astream_i++] = *cmdptr; break; } } for (i = 0; i <= a_index; i++) IConsoleCmdExec(aliases[i]); // execute each alias in turn }