]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cmd.c
made Cmd_ForwardToServer code far more readable and prevented forwarding an empty...
[xonotic/darkplaces.git] / cmd.c
diff --git a/cmd.c b/cmd.c
index 18ac78fe5bb7d851756ca2dd69b5b9f527572a5c..24ef95292c81079bb01fb00598620739bbcdbbf7 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -64,28 +64,9 @@ static void Cmd_Wait_f (void)
 =============================================================================
 */
 
-static sizebuf_t       cmd_text;
-
-/*
-============
-Cbuf_Init
-============
-*/
-void Cbuf_Init (void)
-{
        // LordHavoc: inreased this from 8192 to 32768
-       SZ_Alloc (&cmd_text, 32768, "command buffer"); // space for commands and script files
-}
-
-/*
-============
-Cbuf_Shutdown
-============
-*/
-void Cbuf_Shutdown (void)
-{
-       SZ_Free (&cmd_text);
-}
+static sizebuf_t       cmd_text;
+static qbyte           cmd_text_buf[32768];
 
 /*
 ============
@@ -98,7 +79,7 @@ void Cbuf_AddText (const char *text)
 {
        int             l;
 
-       l = strlen (text);
+       l = (int)strlen (text);
 
        if (cmd_text.cursize + l >= cmd_text.maxsize)
        {
@@ -106,7 +87,7 @@ void Cbuf_AddText (const char *text)
                return;
        }
 
-       SZ_Write (&cmd_text, text, strlen (text));
+       SZ_Write (&cmd_text, text, (int)strlen (text));
 }
 
 
@@ -170,8 +151,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;
@@ -223,6 +204,7 @@ quake +prog jctest.qp +cmd amlev1
 quake -nosound +cmd amlev1
 ===============
 */
+qboolean host_stuffcmdsrun = false;
 void Cmd_StuffCmds_f (void)
 {
        int             i, j, l;
@@ -235,6 +217,7 @@ void Cmd_StuffCmds_f (void)
                return;
        }
 
+       host_stuffcmdsrun = true;
        for (i = 0;i < com_argc;i++)
        {
                if (com_argv[i] && com_argv[i][0] == '+' && (com_argv[i][1] < '0' || com_argv[i][1] > '9'))
@@ -352,11 +335,21 @@ static void Cmd_Alias_f (void)
 
        if (!a)
        {
+               cmdalias_t *prev, *current;
+
                a = Z_Malloc (sizeof(cmdalias_t));
-               a->next = cmd_alias;
-               cmd_alias = a;
+               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 )
+                       ;
+               if( prev ) {
+                       prev->next = a;
+               } else {
+                       cmd_alias = a;
+               }
+               a->next = current;
        }
-       strlcpy (a->name, s, sizeof (a->name));
+
 
 // copy the rest of the command line
        cmd[0] = 0;             // start out with a null string
@@ -401,6 +394,86 @@ cmd_source_t cmd_source;
 
 static cmd_function_t *cmd_functions;          // possible commands to execute
 
+/*
+============
+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 ];
+       const char *in;
+       char *out;
+       unsigned outlen;
+       int inquote;
+
+       in = alias->value;
+       out = buffer;
+       outlen = 0;
+       inquote = 0;
+
+       while( *in && outlen < ALIAS_BUFFER )
+       {
+               if( *in == '"' )
+               {
+                       inquote ^= 1;
+               }
+               else if( *in == '$' && !inquote )
+               {
+                       // $* is replaced with all formal parameters, $num is parsed as an argument (or as $num if there arent enough parameters), $bla becomes $bla and $$bla becomes $$bla
+                       // read over the $
+                       in++;
+                       if( *in == '*' )
+                       {
+                               const char *linein = Cmd_Args();
+                               // include all params
+                               while( *linein && outlen < ALIAS_BUFFER ) {
+                                       *out++ = *linein++;
+                                       outlen++;
+                               }
+
+                               in++;
+                       } else {
+                               char *nexttoken;
+                               int argnum;
+
+                               argnum = strtol( in, &nexttoken, 10 );
+
+                               if( 0 < argnum && argnum < Cmd_Argc() )
+                               {
+                                       const char *param = Cmd_Argv( argnum );
+                                       while( *param && outlen < ALIAS_BUFFER ) {
+                                               *out++ = *param++;
+                                               outlen++;
+                                       }
+                                       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 );
+                                       *out++ = '$';
+                                       outlen++;
+                               }
+                               // not a number
+                               else if( argnum == 0 )
+                               {
+                                       *out++ = '$';
+                                       outlen++;
+                               }
+                       }
+               } else {
+                       *out++ = *in++;
+                       outlen++;
+               }
+       }
+       *out++ = '\n';
+       *out++ = 0;
+       Cbuf_AddText( buffer );
+}
+
 /*
 ========
 Cmd_List
@@ -419,7 +492,7 @@ static void Cmd_List_f (void)
        if (Cmd_Argc() > 1)
        {
                partial = Cmd_Argv (1);
-               len = strlen(partial);
+               len = (int)strlen(partial);
        }
        else
        {
@@ -451,7 +524,14 @@ Cmd_Init
 void Cmd_Init (void)
 {
        cmd_mempool = Mem_AllocPool("commands", 0, NULL);
+       // space for commands and script files
+       cmd_text.data = cmd_text_buf;
+       cmd_text.maxsize = sizeof(cmd_text_buf);
+       cmd_text.cursize = 0;
+}
 
+void Cmd_Init_Commands (void)
+{
 //
 // register our commands
 //
@@ -528,12 +608,18 @@ static void Cmd_TokenizeString (const char *text)
        while (1)
        {
                // skip whitespace up to a /n
-               while (*text && *text <= ' ' && *text != '\n')
+               while (*text && *text <= ' ' && *text != '\r' && *text != '\n')
                        text++;
 
-               if (*text == '\n')
+               // line endings:
+               // UNIX: \n
+               // Mac: \r
+               // Windows: \r\n
+               if (*text == '\n' || *text == '\r')
                {
                        // a newline seperates commands in the buffer
+                       if (*text == '\r' && text[1] == '\n')
+                               text++;
                        text++;
                        break;
                }
@@ -547,18 +633,43 @@ static void Cmd_TokenizeString (const char *text)
                if (!COM_ParseTokenConsole(&text))
                        return;
 
+               // check for $cvar
+               // (perhaps use another target buffer?)
+               if (com_token[0] == '$' && com_token[1])
+               {
+                       cvar_t *cvar;
+
+                       cvar = Cvar_FindVar(&com_token[1]);
+                       if (cvar)
+                       {
+                               strcpy(com_token, cvar->string);
+                       }
+                       else if( com_token[1] == '$' )
+                       {
+                               // remove the first $
+                               char *pos;
+
+                               for( pos = com_token ; *pos ; pos++ )
+                               {
+                                       *pos = *(pos + 1);
+                               }
+                       }
+               }
+
                if (cmd_argc < MAX_ARGS)
                {
-                       l = strlen(com_token) + 1;
+                       l = (int)strlen(com_token) + 1;
                        if (cmd_tokenizebufferpos + l > CMD_TOKENIZELENGTH)
-                               Sys_Error("Cmd_TokenizeString: ran out of %i character buffer space for command arguements\n", CMD_TOKENIZELENGTH);
+                       {
+                               Con_Printf("Cmd_TokenizeString: ran out of %i character buffer space for command arguements\n", CMD_TOKENIZELENGTH);
+                               break;
+                       }
                        strcpy (cmd_tokenizebuffer + cmd_tokenizebufferpos, com_token);
                        cmd_argv[cmd_argc] = cmd_tokenizebuffer + cmd_tokenizebufferpos;
                        cmd_tokenizebufferpos += l;
                        cmd_argc++;
                }
        }
-
 }
 
 
@@ -570,9 +681,10 @@ Cmd_AddCommand
 void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
 {
        cmd_function_t *cmd;
+       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;
@@ -592,7 +704,16 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function)
        cmd->name = cmd_name;
        cmd->function = function;
        cmd->next = cmd_functions;
-       cmd_functions = cmd;
+
+// insert it at the right alphanumeric position
+       for( prev = NULL, current = cmd_functions ; current && strcmp( current->name, cmd->name ) < 0 ; prev = current, current = current->next )
+               ;
+       if( prev ) {
+               prev->next = cmd;
+       } else {
+               cmd_functions = cmd;
+       }
+       cmd->next = current;
 }
 
 /*
@@ -620,7 +741,7 @@ Cmd_CompleteCommand
 const char *Cmd_CompleteCommand (const char *partial)
 {
        cmd_function_t *cmd;
-       int len;
+       size_t len;
 
        len = strlen(partial);
 
@@ -647,7 +768,8 @@ const char *Cmd_CompleteCommand (const char *partial)
 int Cmd_CompleteCountPossible (const char *partial)
 {
        cmd_function_t *cmd;
-       int len, h;
+       size_t len;
+       int h;
 
        h = 0;
        len = strlen(partial);
@@ -675,9 +797,9 @@ int Cmd_CompleteCountPossible (const char *partial)
 const char **Cmd_CompleteBuildList (const char *partial)
 {
        cmd_function_t *cmd;
-       int len = 0;
-       int bpos = 0;
-       int sizeofbuf = (Cmd_CompleteCountPossible (partial) + 1) * sizeof (const char *);
+       size_t len = 0;
+       size_t bpos = 0;
+       size_t sizeofbuf = (Cmd_CompleteCountPossible (partial) + 1) * sizeof (const char *);
        const char **buf;
 
        len = strlen(partial);
@@ -703,7 +825,7 @@ const char **Cmd_CompleteBuildList (const char *partial)
 const char *Cmd_CompleteAlias (const char *partial)
 {
        cmdalias_t *alias;
-       int len;
+       size_t len;
 
        len = strlen(partial);
 
@@ -730,7 +852,7 @@ const char *Cmd_CompleteAlias (const char *partial)
 int Cmd_CompleteAliasCountPossible (const char *partial)
 {
        cmdalias_t      *alias;
-       int                     len;
+       size_t          len;
        int                     h;
 
        h = 0;
@@ -760,9 +882,9 @@ int Cmd_CompleteAliasCountPossible (const char *partial)
 const char **Cmd_CompleteAliasBuildList (const char *partial)
 {
        cmdalias_t *alias;
-       int len = 0;
-       int bpos = 0;
-       int sizeofbuf = (Cmd_CompleteAliasCountPossible (partial) + 1) * sizeof (const char *);
+       size_t len = 0;
+       size_t bpos = 0;
+       size_t sizeofbuf = (Cmd_CompleteAliasCountPossible (partial) + 1) * sizeof (const char *);
        const char **buf;
 
        len = strlen(partial);
@@ -801,36 +923,30 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
                return;         // no tokens
        }
 
-// check functions (only after host_initialized)
-       if (host_initialized || !strcasecmp(cmd_argv[0], "exec") || !strcasecmp(cmd_argv[0], "set") || !strcasecmp(cmd_argv[0], "seta"))
+// check functions
+       for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
        {
-               for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
+               if (!strcasecmp (cmd_argv[0],cmd->name))
                {
-                       if (!strcasecmp (cmd_argv[0],cmd->name))
-                       {
-                               cmd->function ();
-                               cmd_tokenizebufferpos = oldpos;
-                               return;
-                       }
+                       cmd->function ();
+                       cmd_tokenizebufferpos = oldpos;
+                       return;
                }
        }
 
-// check alias (only after host_initialized)
-       if (host_initialized)
+// check alias
+       for (a=cmd_alias ; a ; a=a->next)
        {
-               for (a=cmd_alias ; a ; a=a->next)
+               if (!strcasecmp (cmd_argv[0], a->name))
                {
-                       if (!strcasecmp (cmd_argv[0], a->name))
-                       {
-                               Cbuf_InsertText (a->value);
-                               cmd_tokenizebufferpos = oldpos;
-                               return;
-                       }
+                       Cmd_ExecuteAlias(a);
+                       cmd_tokenizebufferpos = oldpos;
+                       return;
                }
        }
 
-// check cvars (always)
-       if (!Cvar_Command () && host_initialized)
+// check cvars
+       if (!Cvar_Command () && host_framecount > 0)
                Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(0));
 
        cmd_tokenizebufferpos = oldpos;
@@ -859,7 +975,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, strlen(s) + 1);
+       SZ_Write(&cls.message, s, (int)strlen(s) + 1);
 }
 
 /*
@@ -872,10 +988,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);
 }
 
@@ -894,7 +1019,10 @@ int Cmd_CheckParm (const char *parm)
        int i;
 
        if (!parm)
-               Sys_Error ("Cmd_CheckParm: NULL");
+       {
+               Con_Printf ("Cmd_CheckParm: NULL");
+               return 0;
+       }
 
        for (i = 1; i < Cmd_Argc (); i++)
                if (!strcasecmp (parm, Cmd_Argv (i)))