]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cmd.c
Moved the cmd preprocessor call from ExecuteString to Cbuf_Execute which
[xonotic/darkplaces.git] / cmd.c
diff --git a/cmd.c b/cmd.c
index 41c38794562dbf90b5ab7bfec9a135bb3dad0274..47892f9afb2e9e07a17e049a2a9b8b6a484a7256 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -66,7 +66,7 @@ static void Cmd_Wait_f (void)
 
        // LordHavoc: inreased this from 8192 to 32768
 static sizebuf_t       cmd_text;
-static qbyte           cmd_text_buf[32768];
+static unsigned char           cmd_text_buf[32768];
 
 /*
 ============
@@ -87,7 +87,7 @@ void Cbuf_AddText (const char *text)
                return;
        }
 
-       SZ_Write (&cmd_text, text, (int)strlen (text));
+       SZ_Write (&cmd_text, (const unsigned char *)text, (int)strlen (text));
 }
 
 
@@ -109,7 +109,7 @@ void Cbuf_InsertText (const char *text)
        templen = cmd_text.cursize;
        if (templen)
        {
-               temp = Mem_Alloc (tempmempool, templen);
+               temp = (char *)Mem_Alloc (tempmempool, templen);
                memcpy (temp, cmd_text.data, templen);
                SZ_Clear (&cmd_text);
        }
@@ -122,7 +122,7 @@ void Cbuf_InsertText (const char *text)
        // add the copied off data
        if (temp != NULL)
        {
-               SZ_Write (&cmd_text, temp, templen);
+               SZ_Write (&cmd_text, (const unsigned char *)temp, templen);
                Mem_Free (temp);
        }
 }
@@ -132,11 +132,14 @@ void Cbuf_InsertText (const char *text)
 Cbuf_Execute
 ============
 */
+static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias );
 void Cbuf_Execute (void)
 {
+#define EXECUTESTRING_BUFFER 2048
        int i;
        char *text;
        char line[1024];
+       char preprocessed[EXECUTESTRING_BUFFER];
        int quotes;
 
        // LordHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes
@@ -151,8 +154,8 @@ void Cbuf_Execute (void)
                for (i=0 ; i< cmd_text.cursize ; i++)
                {
                        if (text[i] == '"')
-                               quotes++;
-                       if ( !(quotes&1) &&  text[i] == ';')
+                               quotes ^= 1;
+                       if ( !quotes &&  text[i] == ';')
                                break;  // don't break if inside a quoted string
                        if (text[i] == '\r' || text[i] == '\n')
                                break;
@@ -175,7 +178,8 @@ void Cbuf_Execute (void)
                }
 
 // execute the command line
-               Cmd_ExecuteString (line, src_command);
+               Cmd_PreprocessString( line, preprocessed, EXECUTESTRING_BUFFER, NULL );
+               Cmd_ExecuteString (preprocessed, src_command);
 
                if (cmd_wait)
                {       // skip out while text still remains in buffer, leaving it
@@ -265,7 +269,7 @@ static void Cmd_Exec_f (void)
                return;
        }
 
-       f = (char *)FS_LoadFile (Cmd_Argv(1), tempmempool, false);
+       f = (char *)FS_LoadFile (Cmd_Argv(1), tempmempool, false, NULL);
        if (!f)
        {
                Con_Printf("couldn't exec %s\n",Cmd_Argv(1));
@@ -337,7 +341,7 @@ static void Cmd_Alias_f (void)
        {
                cmdalias_t *prev, *current;
 
-               a = Z_Malloc (sizeof(cmdalias_t));
+               a = (cmdalias_t *)Z_Malloc (sizeof(cmdalias_t));
                strlcpy (a->name, s, sizeof (a->name));
                // insert it at the right alphanumeric position
                for( prev = NULL, current = cmd_alias ; current && strcmp( current->name, a->name ) < 0 ; prev = current, current = current->next )
@@ -362,7 +366,7 @@ static void Cmd_Alias_f (void)
        }
        strlcat (cmd, "\n", sizeof (cmd));
 
-       a->value = Z_Malloc (strlen (cmd) + 1);
+       a->value = (char *)Z_Malloc (strlen (cmd) + 1);
        strcpy (a->value, cmd);
 }
 
@@ -387,13 +391,113 @@ typedef struct cmd_function_s
 static int cmd_argc;
 static const char *cmd_argv[MAX_ARGS];
 static const char *cmd_null_string = "";
-static const char *cmd_args = NULL;
-
+static const char *cmd_args;
 cmd_source_t cmd_source;
 
 
 static cmd_function_t *cmd_functions;          // possible commands to execute
 
+/*
+Cmd_PreprocessString
+
+Preprocesses strings and replaces $*, $param#, $cvar accordingly
+*/
+static void Cmd_PreprocessString( const char *intext, char *outtext, unsigned maxoutlen, cmdalias_t *alias ) {
+       const char *in;
+       unsigned outlen;
+       int inquote;
+
+       // don't crash if there's no room in the outtext buffer
+       if( maxoutlen == 0 ) {
+               return;
+       }
+       maxoutlen--; // because of \0
+
+       in = intext;
+       outlen = 0;
+       inquote = 0;
+
+       while( *in && outlen < maxoutlen ) {
+               if( *in == '$' && !inquote ) {
+                       // this is some kind of expansion, see what comes after the $
+                       in++;
+                       // replacements that can always be used:
+                       // $$ is replaced with $, to allow escaping $
+                       // $<cvarname> is replaced with the contents of the cvar
+                       //
+                       // the following can be used in aliases only:
+                       // $* is replaced with all formal parameters (including name of the alias - this probably is not desirable)
+                       // $0 is replaced with the name of this alias
+                       // $<number> is replaced with an argument to this alias (or copied as-is if no such parameter exists), can be multiple digits
+                       if( *in == '$' ) {
+                               outtext[outlen++] = *in++;
+                       } else if( *in == '*' && alias ) {
+                               const char *linein = Cmd_Args();
+                               // include all params
+                               if (linein) {
+                                       while( *linein && outlen < maxoutlen ) {
+                                               outtext[outlen++] = *linein++;
+                                       }
+                               }
+
+                               in++;
+                       } else if( '0' <= *in && *in <= '9' && alias ) {
+                               char *nexttoken;
+                               int argnum;
+
+                               argnum = strtol( in, &nexttoken, 10 );
+
+                               if( 0 <= argnum && argnum < Cmd_Argc() ) {
+                                       const char *param = Cmd_Argv( argnum );
+                                       while( *param && outlen < maxoutlen ) {
+                                               outtext[outlen++] = *param++;
+                                       }
+                                       in = nexttoken;
+                               } else if( argnum >= Cmd_Argc() ) {
+                                       Con_Printf( "Warning: Not enough parameters passed to alias '%s', at least %i expected:\n    %s\n", alias->name, argnum, alias->value );
+                                       outtext[outlen++] = '$';
+                               }
+                       } else {
+                               cvar_t *cvar;
+                               const char *tempin = in;
+
+                               COM_ParseTokenConsole( &tempin );
+                               if ((cvar = Cvar_FindVar(&com_token[0]))) {
+                                       const char *cvarcontent = cvar->string;
+                                       while( *cvarcontent && outlen < maxoutlen ) {
+                                               outtext[outlen++] = *cvarcontent++;
+                                       }
+                                       in = tempin;
+                               } else {
+                                       Con_Printf( "Warning: could not find cvar %s when expanding alias %s\n    %s\n", com_token, alias->name, alias->value );
+                                       outtext[outlen++] = '$';
+                               }
+                       }
+               } else {
+                       if( *in == '"' ) {
+                               inquote ^= 1;
+                       }
+                       outtext[outlen++] = *in++;
+               }
+       }
+       outtext[outlen] = 0;
+}
+
+/*
+============
+Cmd_ExecuteAlias
+
+Called for aliases and fills in the alias into the cbuffer
+============
+*/
+static void Cmd_ExecuteAlias (cmdalias_t *alias)
+{
+#define ALIAS_BUFFER 1024
+       static char buffer[ ALIAS_BUFFER + 2 ];
+       Cmd_PreprocessString( alias->value, buffer, ALIAS_BUFFER, alias );
+       Cbuf_AddText( buffer );
+}
+
 /*
 ========
 Cmd_List
@@ -429,11 +533,10 @@ static void Cmd_List_f (void)
                count++;
        }
 
-       Con_Printf("%i Command%s", count, (count > 1) ? "s" : "");
        if (partial)
-               Con_Printf(" beginning with \"%s\"", partial);
-
-       Con_Print("\n\n");
+               Con_Printf("%i Command%s beginning with \"%s\"\n\n", count, (count > 1) ? "s" : "", partial);
+       else
+               Con_Printf("%i Command%s\n\n", count, (count > 1) ? "s" : "");
 }
 
 /*
@@ -518,6 +621,7 @@ Cmd_TokenizeString
 Parses the given string into command line tokens.
 ============
 */
+// AK: This function should only be called from ExcuteString because the current design is a bit of an hack
 static void Cmd_TokenizeString (const char *text)
 {
        int l;
@@ -537,7 +641,7 @@ static void Cmd_TokenizeString (const char *text)
                // Windows: \r\n
                if (*text == '\n' || *text == '\r')
                {
-                       // a newline seperates commands in the buffer
+                       // a newline separates commands in the buffer
                        if (*text == '\r' && text[1] == '\n')
                                text++;
                        text++;
@@ -548,7 +652,7 @@ static void Cmd_TokenizeString (const char *text)
                        return;
 
                if (cmd_argc == 1)
-                        cmd_args = text;
+                       cmd_args = text;
 
                if (!COM_ParseTokenConsole(&text))
                        return;
@@ -581,7 +685,7 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
        cmd_function_t *prev, *current;
 
 // fail if the command is a variable name
-       if (Cvar_VariableString(cmd_name)[0])
+       if (Cvar_FindVar( cmd_name ))
        {
                Con_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
                return;
@@ -597,7 +701,7 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
                }
        }
 
-       cmd = Mem_Alloc(cmd_mempool, sizeof(cmd_function_t));
+       cmd = (cmd_function_t *)Mem_Alloc(cmd_mempool, sizeof(cmd_function_t));
        cmd->name = cmd_name;
        cmd->function = function;
        cmd->next = cmd_functions;
@@ -700,7 +804,7 @@ const char **Cmd_CompleteBuildList (const char *partial)
        const char **buf;
 
        len = strlen(partial);
-       buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *));
+       buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *));
        // Loop through the alias list and print all matches
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
                if (!strncasecmp(partial, cmd->name, len))
@@ -785,7 +889,7 @@ const char **Cmd_CompleteAliasBuildList (const char *partial)
        const char **buf;
 
        len = strlen(partial);
-       buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *));
+       buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *));
        // Loop through the alias list and print all matches
        for (alias = cmd_alias; alias; alias = alias->next)
                if (!strncasecmp(partial, alias->name, len))
@@ -811,6 +915,7 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
 
        oldpos = cmd_tokenizebufferpos;
        cmd_source = src;
+
        Cmd_TokenizeString (text);
 
 // execute the command line
@@ -836,7 +941,7 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
        {
                if (!strcasecmp (cmd_argv[0], a->name))
                {
-                       Cbuf_InsertText (a->value);
+                       Cmd_ExecuteAlias(a);
                        cmd_tokenizebufferpos = oldpos;
                        return;
                }
@@ -872,7 +977,7 @@ void Cmd_ForwardStringToServer (const char *s)
        // attention, it has been eradicated from here, its only (former) use in
        // all of darkplaces.
        MSG_WriteByte(&cls.message, clc_stringcmd);
-       SZ_Write(&cls.message, s, (int)strlen(s) + 1);
+       SZ_Write(&cls.message, (const unsigned char *)s, (int)strlen(s) + 1);
 }
 
 /*
@@ -885,10 +990,19 @@ Sends the entire command line over to the server
 void Cmd_ForwardToServer (void)
 {
        const char *s;
-       if (strcasecmp(Cmd_Argv(0), "cmd"))
-               s = va("%s %s", Cmd_Argv(0), Cmd_Argc() > 1 ? Cmd_Args() : "");
-       else
+       if (!strcasecmp(Cmd_Argv(0), "cmd"))
+       {
+               // we want to strip off "cmd", so just send the args
                s = Cmd_Argc() > 1 ? Cmd_Args() : "";
+       }
+       else
+       {
+               // we need to keep the command name, so send Cmd_Argv(0), a space and then Cmd_Args()
+               s = va("%s %s", Cmd_Argv(0), Cmd_Argc() > 1 ? Cmd_Args() : "");
+       }
+       // don't send an empty forward message if the user tries "cmd" by itself
+       if (!s || !*s)
+               return;
        Cmd_ForwardStringToServer(s);
 }