diff --git a/engine/common/cmd.c b/engine/common/cmd.c index e78848a3f..9fe805a50 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -981,7 +981,7 @@ typedef struct cmd_function_s static int cmd_argc; static char *cmd_argv[MAX_ARGS]; static char *cmd_null_string = ""; -static char *cmd_args = NULL; +static char *cmd_args = NULL, *cmd_args_buf; @@ -1026,7 +1026,20 @@ char *VARGS Cmd_Args (void) void Cmd_Args_Set(char *newargs) { - cmd_args = newargs; + if (cmd_args_buf) + Z_Free(cmd_args_buf); + + if (newargs) + { + cmd_args_buf = (char*)Z_Malloc (Q_strlen(newargs)+1); + Q_strcpy (cmd_args_buf, newargs); + cmd_args = cmd_args_buf; + } + else + { + cmd_args = NULL; + cmd_args_buf = NULL; + } } /* @@ -1063,6 +1076,64 @@ void Cmd_ShiftArgs (int ammount, qboolean expandstring) } } +char *Cmd_ExpandCvar(char *cvarname, int maxaccesslevel, int *len) +{ + char *ret = NULL, *end, *namestart; + char *fixup = NULL, fixval=0; + cvar_t *var; + static char temp[12]; + + namestart = cvarname; + if (*cvarname == '{') + { + fixup = &cvarname[strlen(cvarname)-1]; + if (*fixup != '}') + return NULL; + fixval = *fixup; + *fixup = 0; + cvarname++; + } + else + { + fixup = &cvarname[strlen(cvarname)]; + fixval = *fixup; + } + + strtol(cvarname, &end, 10); + if (fixval && *end == '\0') //only expand $0 if its actually ${0} - this avoids conflicting with the $0 macro + { //purely numerical + ret = Cmd_Argv(atoi(cvarname)); + } + else if (!strcmp(cvarname, "*") || !stricmp(cvarname, "cmd_args")) + { + ret = Cmd_Args(); + } + else if (!strnicmp(cvarname, "cmd_argv", 8)) + { + ret = Cmd_Argv(atoi(cvarname+8)); + } + else if (!stricmp(cvarname, "cmd_argc")) + { + Q_snprintfz(temp, sizeof(temp), "%u", Cmd_Argc()); + ret = temp; + } + else if ( (var = Cvar_FindVar(cvarname)) != NULL ) + { + if (var->restriction <= maxaccesslevel && !((var->flags & CVAR_NOUNSAFEEXPAND) && Cmd_IsInsecure())) + { + ret = var->string; + } + } + *fixup = fixval; + if (ret) + { + *len = fixup - namestart; + if (fixval) + (*len)++; + } + return ret; +} + /* ================ Cmd_ExpandString @@ -1077,11 +1148,10 @@ char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel, unsigned int c; char buf[255]; int i, len; - cvar_t *var, *bestvar; int quotes = 0; char *str; - char *bestmacro; - int name_length, macro_length; + char *bestmacro, *bestvar; + int name_length, macro_length, var_length; qboolean striptrailing; len = 0; @@ -1100,9 +1170,11 @@ char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel, // Copy the text after '$' to a temp buffer i = 0; buf[0] = 0; + buf[1] = 0; bestvar = NULL; bestmacro = NULL; macro_length=0; + var_length = 0; while ((c = *data) > 32) { if (c == '$') @@ -1110,10 +1182,10 @@ char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel, data++; buf[i++] = c; buf[i] = 0; - if ( (var = Cvar_FindVar(buf+striptrailing)) != NULL ) + if (!bestmacro) { - if (var->restriction <= maxaccesslevel && !((var->flags & CVAR_NOUNSAFEEXPAND) && Cmd_IsInsecure())) - bestvar = var; + if ((str = Cmd_ExpandCvar(buf+striptrailing, maxaccesslevel, &var_length))) + bestvar = str; } #ifndef SERVERONLY if (expandmacros && (str = TP_MacroString (buf+striptrailing, ¯o_length))) @@ -1128,8 +1200,8 @@ char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel, } else if (bestvar) { - str = bestvar->string; - name_length = strlen(bestvar->name); + str = bestvar; + name_length = var_length; } else { @@ -1178,6 +1250,70 @@ char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel, return dest; } +char *Cmd_ExpandStringArguments (char *data, char *dest, int destlen) +{ + char c; + int quotes = 0; + int len = 0; + + char *str, *strend; + int old_len; + while ( (c = *data) != 0) + { + if (c == '"') + quotes++; + + if (c == '%' && !(quotes&1)) + { + if (data[1] == '%') + { + str = "%"; + old_len = 2; + } + else if (data[1] == '*') + { + str = Cmd_Args(); + old_len = 2; + } + else if (strtol(data+1, &strend, 10)) + { + str = Cmd_Argv(atoi(data+1)); + old_len = strend - data; + } + else + { + str = NULL; + old_len = 0; + } + + if (str) + { + // check buffer size + if (len + strlen(str) >= destlen-1) + break; + + strcpy(&dest[len], str); + len += strlen(str); + dest[len] = 0; + data += old_len; + + continue; + } + } + + dest[len] = c; + data++; + len++; + dest[len] = 0; + if (len >= destlen-1) + break; + } + + dest[len] = 0; + + return dest; +} + /* ============ Cmd_TokenizeString @@ -1194,7 +1330,7 @@ void Cmd_TokenizeString (char *text, qboolean expandmacros, qboolean qctokenize) Z_Free (cmd_argv[i]); cmd_argc = 0; - cmd_args = NULL; + Cmd_Args_Set(NULL); while (1) { @@ -1214,7 +1350,9 @@ void Cmd_TokenizeString (char *text, qboolean expandmacros, qboolean qctokenize) return; if (cmd_argc == 1) - cmd_args = text; + { + Cmd_Args_Set(text); + } text = COM_StringParse (text, expandmacros, qctokenize); if (!text) @@ -1689,7 +1827,7 @@ void Cmd_ExecuteString (char *text, int level) cmd_function_t *cmd; cmdalias_t *a; - static char dest[8192]; + char dest[8192]; Cmd_ExecLevel = level; @@ -1737,7 +1875,6 @@ void Cmd_ExecuteString (char *text, int level) { if (!Q_strcasecmp (cmd_argv[0], a->name)) { - int i; int execlevel; #ifndef SERVERONLY //an emergency escape mechansim, to avoid infinatly recursing aliases. @@ -1761,23 +1898,16 @@ void Cmd_ExecuteString (char *text, int level) // if the alias value is a command or cvar and // the alias is called with parameters, add them - if (Cmd_Argc() > 1 && !strchr(a->value, ' ') && !strchr(a->value, '\t') && - (Cvar_FindVar(a->value) || (Cmd_Exists(a->value) && a->value[0] != '+' && a->value[0] != '-')) + if (Cmd_Argc() > 1 && (!strncmp(a->value, "cmd ", 4) || (!strchr(a->value, ' ') && !strchr(a->value, '\t') && + (Cvar_FindVar(a->value) || (Cmd_Exists(a->value) && a->value[0] != '+' && a->value[0] != '-')))) ) { Cbuf_InsertText (Cmd_Args(), execlevel, false); Cbuf_InsertText (" ", execlevel, false); } - Cbuf_InsertText (a->value, execlevel, false); - - if (execlevel>=RESTRICT_SERVER) - return; //don't do the cmd_argc/cmd_argv stuff. When it's from the server, we had a tendancy to lock aliases, so don't set them anymore. - - Cbuf_InsertText (va("set cmd_argc \"%i\"\n", cmd_argc), execlevel, false); - - for (i = 0; i < cmd_argc; i++) - Cbuf_InsertText (va("set cmd_argv%i \"%s\"\n", i, cmd_argv[i]), execlevel, false); + Cmd_ExpandStringArguments (a->value, dest, sizeof(dest)); + Cbuf_InsertText (dest, execlevel, false); return; } }