]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cmd.c
host: Refactor Host_Frame; simplify control flow.
[xonotic/darkplaces.git] / cmd.c
diff --git a/cmd.c b/cmd.c
index 3b3fdfd146745b184669b9952f337763517363a8..490a987ec5abcd7394d3b87fff6f9bc846a717b0 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -22,9 +22,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "quakedef.h"
 #include "thread.h"
 
-cmd_state_t cmd_client;
-cmd_state_t cmd_server;
-cmd_state_t cmd_serverfromclient;
+cmd_state_t *cmd_client;
+cmd_state_t *cmd_server;
+cmd_state_t *cmd_serverfromclient;
 
 cmd_userdefined_t cmd_userdefined_all;
 cmd_userdefined_t cmd_userdefined_null;
@@ -34,13 +34,9 @@ typedef struct cmd_iter_s {
 }
 cmd_iter_t;
 
-static cmd_iter_t cmd_iter_all[] = {
-       {&cmd_client},
-       {&cmd_server},
-       {&cmd_serverfromclient},
-       {NULL},
-};
+static cmd_iter_t *cmd_iter_all;
 
+mempool_t *cbuf_mempool;
 
 // we only run the +whatever commandline arguments once
 qbool host_stuffcmdsrun = false;
@@ -87,35 +83,40 @@ static void Cmd_Defer_f (cmd_state_t *cmd)
 
        if(Cmd_Argc(cmd) == 1)
        {
-               if(List_IsEmpty(&cbuf->deferred))
+               if(List_Is_Empty(&cbuf->deferred))
                        Con_Printf("No commands are pending.\n");
                else
                {
                        llist_t *pos;
-               List_ForEach(pos, &cbuf->deferred)
+               List_For_Each(pos, &cbuf->deferred)
                {
-                               current = List_Container(*pos, cmd_input_t, list);
+                               current = List_Entry(*pos, cmd_input_t, list);
                                Con_Printf("-> In %9.2f: %s\n", current->delay, current->text);
                        }
                }
        }
        else if(Cmd_Argc(cmd) == 2 && !strcasecmp("clear", Cmd_Argv(cmd, 1)))
        {
-               while(!List_IsEmpty(&cbuf->deferred))
+               while(!List_Is_Empty(&cbuf->deferred))
                        List_Move_Tail(cbuf->deferred.next, &cbuf->free);
        }
        else if(Cmd_Argc(cmd) == 3)
        {
                const char *text = Cmd_Argv(cmd, 2);
                current = Cbuf_LinkGet(cbuf, NULL);
-               current->size = strlen(text);
+               current->length = strlen(text);
                current->source = cmd;
                current->delay = atof(Cmd_Argv(cmd, 1));
 
-               memcpy(current->text, text, current->size + 1);
+               if(current->size < current->length)
+               {
+                       current->text = (char *)Mem_Realloc(cbuf_mempool, current->text, current->length + 1);
+                       current->size = current->length;
+               }
 
-               List_Move_Tail(&current->list, &cbuf->deferred);
+               strlcpy(current->text, text, current->length + 1);
 
+               List_Move_Tail(&current->list, &cbuf->deferred);
        }
        else
        {
@@ -181,9 +182,9 @@ static cmd_input_t *Cbuf_LinkGet(cmd_buf_t *cbuf, cmd_input_t *existing)
        cmd_input_t *ret = NULL;
        if(existing && existing->pending)
                ret = existing;
-       else if(!List_IsEmpty(&cbuf->free))
+       else if(!List_Is_Empty(&cbuf->free))
        {
-               ret = List_Container(*cbuf->free.next, cmd_input_t, list);
+               ret = List_Entry(*cbuf->free.next, cmd_input_t, list);
                ret->length = 0;
                ret->pending = false;
        }
@@ -192,7 +193,7 @@ static cmd_input_t *Cbuf_LinkGet(cmd_buf_t *cbuf, cmd_input_t *existing)
 
 static cmd_input_t *Cmd_AllocInputNode(void)
 {
-       cmd_input_t *node = (cmd_input_t *)Z_Malloc(sizeof(cmd_input_t));
+       cmd_input_t *node = (cmd_input_t *)Mem_Alloc(cbuf_mempool, sizeof(cmd_input_t));
        node->list.prev = node->list.next = &node->list;
        node->size = node->length = node->pending = 0;
        return node;
@@ -289,10 +290,10 @@ static size_t Cmd_ParseInput (cmd_input_t **output, char **input)
 
                (*output)->length += cmdsize;
 
-               if((*output)->size < (*output)->length + 1)
+               if((*output)->size < (*output)->length)
                {
-                       (*output)->text = (char *)Mem_Realloc(tempmempool, (*output)->text, (*output)->size + cmdsize + 1);
-                       (*output)->size = (*output)->length + 1;
+                       (*output)->text = (char *)Mem_Realloc(cbuf_mempool, (*output)->text, (*output)->length + 1);
+                       (*output)->size = (*output)->length;
                }
 
                strlcpy(&(*output)->text[offset], &(*input)[start], cmdsize + 1);
@@ -357,8 +358,8 @@ void Cbuf_AddText (cmd_state_t *cmd, const char *text)
                Con_Print("Cbuf_AddText: overflow\n");
        else
        {
-               Cbuf_LinkCreate(cmd, &llist, (List_IsEmpty(&cbuf->start) ? NULL : List_Container(*cbuf->start.prev, cmd_input_t, list)), text);
-               if(!List_IsEmpty(&llist))
+               Cbuf_LinkCreate(cmd, &llist, (List_Is_Empty(&cbuf->start) ? NULL : List_Entry(*cbuf->start.prev, cmd_input_t, list)), text);
+               if(!List_Is_Empty(&llist))
                        List_Splice_Tail(&llist, &cbuf->start);
        }
        Cbuf_Unlock(cbuf);
@@ -381,12 +382,12 @@ void Cbuf_InsertText (cmd_state_t *cmd, const char *text)
        Cbuf_Lock(cbuf);
 
        // we need to memmove the existing text and stuff this in before it...
-       if (cbuf->size + l >= (size_t)cbuf->maxsize)
+       if (cbuf->size + l >= cbuf->maxsize)
                Con_Print("Cbuf_InsertText: overflow\n");
        else
        {
-               Cbuf_LinkCreate(cmd, &llist, List_Container(*cbuf->start.next, cmd_input_t, list), text);
-               if(!List_IsEmpty(&llist))
+               Cbuf_LinkCreate(cmd, &llist, List_Entry(*cbuf->start.next, cmd_input_t, list), text);
+               if(!List_Is_Empty(&llist))
                        List_Splice(&llist, &cbuf->start);
        }
 
@@ -411,13 +412,13 @@ static void Cbuf_Execute_Deferred (cmd_buf_t *cbuf)
                return;
        cbuf->deferred_oldtime = host.realtime;
 
-    List_ForEach(pos, &cbuf->deferred)
+    List_For_Each(pos, &cbuf->deferred)
        {
-               current = List_Container(*pos, cmd_input_t, list);
+               current = List_Entry(*pos, cmd_input_t, list);
                current->delay -= eat;
                if(current->delay <= 0)
                {
-                       cbuf->size += current->size;
+                       cbuf->size += current->length;
                        List_Move(pos, &cbuf->start);
                        // We must return and come back next frame or the engine will freeze. Fragile... like glass :3
                        return;
@@ -440,15 +441,18 @@ void Cbuf_Execute (cmd_buf_t *cbuf)
        // LadyHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes
        cbuf->tokenizebufferpos = 0;
 
-       while (!List_IsEmpty(&cbuf->start))
+       while (!List_Is_Empty(&cbuf->start))
        {
                /*
                 * Delete the text from the command buffer and move remaining
                 * commands down. This is necessary because commands (exec, alias)
                 * can insert data at the beginning of the text buffer
                 */
-               current = List_Container(*cbuf->start.next, cmd_input_t, list);
-
+               current = List_Entry(*cbuf->start.next, cmd_input_t, list);
+               
+               // Recycle memory so using WASD doesn't cause a malloc and free
+               List_Move_Tail(&current->list, &cbuf->free);
+               
                /*
                 * Assume we're rolling with the current command-line and
                 * always set this false because alias expansion or cbuf insertion
@@ -473,9 +477,6 @@ void Cbuf_Execute (cmd_buf_t *cbuf)
                        Cmd_ExecuteString (current->source, current->text, src_local, false);
                }
 
-               // Recycle memory so using WASD doesn't cause a malloc and free
-               List_Move_Tail(&current->list, &cbuf->free);
-
                current = NULL;
 
                if (cbuf->wait)
@@ -1500,7 +1501,7 @@ static void Cmd_List_f (cmd_state_t *cmd)
        }
 
        count = 0;
-       for (func = cmd->userdefined->csqc_functions; func; func = func->next)
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
        {
                if (partial && (ispattern ? !matchpattern_with_separator(func->name, partial, false, "", false) : strncmp(partial, func->name, len)))
                        continue;
@@ -1568,7 +1569,7 @@ static void Cmd_Apropos_f(cmd_state_t *cmd)
                        }
                }
        }
-       for (func = cmd->userdefined->csqc_functions; func; func = func->next)
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
        {
                if (!matchpattern_with_separator(func->name, partial, true, "", false))
                        if (!matchpattern_with_separator(func->description, partial, true, "", false))
@@ -1596,6 +1597,25 @@ static void Cmd_Apropos_f(cmd_state_t *cmd)
        Con_Printf("%i result%s\n\n", count, (count > 1) ? "s" : "");
 }
 
+static cmd_state_t *Cmd_AddInterpreter(cmd_buf_t *cbuf, cvar_state_t *cvars, int cvars_flagsmask, int cmds_flagsmask, cmd_userdefined_t *userdefined, int autoflags, xcommand_t autofunction)
+{
+       cmd_state_t *cmd = (cmd_state_t *)Mem_Alloc(tempmempool, sizeof(cmd_state_t));
+       
+       cmd->mempool = Mem_AllocPool("commands", 0, NULL);
+       // space for commands and script files
+       cmd->cbuf = cbuf;
+       cmd->null_string = "";
+
+       cmd->cvars = cvars;
+       cmd->cvars_flagsmask = cvars_flagsmask;
+       cmd->cmd_flags = cmds_flagsmask;
+       cmd->auto_flags = autoflags;
+       cmd->auto_function = autofunction;
+       cmd->userdefined = userdefined;
+
+       return cmd;
+}
+
 /*
 ============
 Cmd_Init
@@ -1603,8 +1623,9 @@ Cmd_Init
 */
 void Cmd_Init(void)
 {
-       cmd_iter_t *cmd_iter;
-       cmd_buf_t *cbuf = (cmd_buf_t *)Z_Malloc(sizeof(cmd_buf_t));
+       cmd_buf_t *cbuf;
+       cbuf_mempool = Mem_AllocPool("Command buffer", 0, NULL);
+       cbuf = (cmd_buf_t *)Mem_Alloc(cbuf_mempool, sizeof(cmd_buf_t));
        cbuf->maxsize = 655360;
        cbuf->lock = Thread_CreateMutex();
        cbuf->wait = false;
@@ -1614,36 +1635,19 @@ void Cmd_Init(void)
        cbuf->deferred.prev = cbuf->deferred.next = &(cbuf->deferred);
        cbuf->free.prev = cbuf->free.next = &(cbuf->free);
 
-       for (cmd_iter = cmd_iter_all; cmd_iter->cmd; cmd_iter++)
-       {
-               cmd_state_t *cmd = cmd_iter->cmd;
-               cmd->mempool = Mem_AllocPool("commands", 0, NULL);
-               // space for commands and script files
-               cmd->cbuf = cbuf;
-               cmd->null_string = "";
-       }
+       // FIXME: Get rid of cmd_iter_all eventually. This is just a hack to reduce the amount of work to make the interpreters dynamic.
+       cmd_iter_all = (cmd_iter_t *)Mem_Alloc(tempmempool, sizeof(cmd_iter_t) * 4);
+
        // client console can see server cvars because the user may start a server
-       cmd_client.cvars = &cvars_all;
-       cmd_client.cvars_flagsmask = CF_CLIENT | CF_SERVER;
-       cmd_client.cmd_flags = CF_CLIENT | CF_CLIENT_FROM_SERVER;
-       cmd_client.auto_flags = CF_SERVER_FROM_CLIENT;
-       cmd_client.auto_function = CL_ForwardToServer_f; // FIXME: Move this to the client.
-       cmd_client.userdefined = &cmd_userdefined_all;
+       cmd_iter_all[0].cmd = cmd_client = Cmd_AddInterpreter(cbuf, &cvars_all, CF_CLIENT | CF_SERVER, CF_CLIENT | CF_CLIENT_FROM_SERVER, &cmd_userdefined_all, CF_SERVER_FROM_CLIENT, CL_ForwardToServer_f);
+
        // dedicated server console can only see server cvars, there is no client
-       cmd_server.cvars = &cvars_all;
-       cmd_server.cvars_flagsmask = CF_SERVER;
-       cmd_server.cmd_flags = CF_SERVER;
-       cmd_server.auto_flags = 0;
-       cmd_server.auto_function = NULL;
-       cmd_server.userdefined = &cmd_userdefined_all;
+       cmd_iter_all[1].cmd = cmd_server = Cmd_AddInterpreter(cbuf, &cvars_all, CF_SERVER, CF_SERVER, &cmd_userdefined_all, 0, NULL);
+
        // server commands received from clients have no reason to access cvars, cvar expansion seems perilous.
-       cmd_serverfromclient.cvars = &cvars_null;
-       cmd_serverfromclient.cvars_flagsmask = 0;
-       cmd_serverfromclient.cmd_flags = CF_SERVER_FROM_CLIENT | CF_USERINFO;
-       cmd_serverfromclient.auto_flags = 0;
-       cmd_serverfromclient.auto_function = NULL;
-       cmd_serverfromclient.userdefined = &cmd_userdefined_null;
+       cmd_iter_all[2].cmd = cmd_serverfromclient = Cmd_AddInterpreter(cbuf, &cvars_null, 0, CF_SERVER_FROM_CLIENT | CF_USERINFO, &cmd_userdefined_null, 0, NULL);
 
+       cmd_iter_all[3].cmd = NULL;
 //
 // register our commands
 //
@@ -1753,6 +1757,7 @@ static void Cmd_TokenizeString (cmd_state_t *cmd, const char *text)
 
        cmd->argc = 0;
        cmd->args = NULL;
+       cmd->cmdline = NULL;
 
        while (1)
        {
@@ -1776,6 +1781,8 @@ static void Cmd_TokenizeString (cmd_state_t *cmd, const char *text)
                if (!*text)
                        return;
 
+               if(!cmd->argc)
+                       cmd->cmdline = text;
                if (cmd->argc == 1)
                        cmd->args = text;
 
@@ -1867,33 +1874,34 @@ void Cmd_AddCommand(int flags, const char *cmd_name, xcommand_t function, const
                        }
                        else
                        {
-                               // mark csqcfunc if the function already exists in the csqc_functions list
-                               for (func = cmd->userdefined->csqc_functions; func; func = func->next)
+                               // mark qcfunc if the function already exists in the qc_functions list
+                               for (func = cmd->userdefined->qc_functions; func; func = func->next)
                                {
                                        if (!strcmp(cmd_name, func->name))
                                        {
-                                               func->csqcfunc = true; //[515]: csqc
+                                               func->qcfunc = true; //[515]: csqc
                                                continue;
                                        }
                                }
 
 
                                func = (cmd_function_t *)Mem_Alloc(cmd->mempool, sizeof(cmd_function_t));
+                               func->flags = flags;
                                func->name = cmd_name;
                                func->function = function;
                                func->description = description;
-                               func->csqcfunc = true; //[515]: csqc
-                               func->next = cmd->userdefined->csqc_functions;
+                               func->qcfunc = true; //[515]: csqc
+                               func->next = cmd->userdefined->qc_functions;
                                func->autofunc = false;
 
                                // insert it at the right alphanumeric position
-                               for (prev = NULL, current = cmd->userdefined->csqc_functions; current && strcmp(current->name, func->name) < 0; prev = current, current = current->next)
+                               for (prev = NULL, current = cmd->userdefined->qc_functions; current && strcmp(current->name, func->name) < 0; prev = current, current = current->next)
                                        ;
                                if (prev) {
                                        prev->next = func;
                                }
                                else {
-                                       cmd->userdefined->csqc_functions = func;
+                                       cmd->userdefined->qc_functions = func;
                                }
                                func->next = current;
                        }
@@ -1906,30 +1914,6 @@ next:
        }
 }
 
-static int Cmd_Compare(const char *s1, const char *s2, size_t len, qbool casesensitive)
-{
-       if(len)
-               return (casesensitive ? strncmp(s1, s2, len) : strncasecmp(s1, s2, len));
-       else
-               return (casesensitive ? strcmp(s1, s2) : strcasecmp(s1, s2));
-}
-
-cmd_function_t *Cmd_GetCommand(cmd_state_t *cmd, const char *partial, size_t len, qbool casesensitive)
-{
-       cmd_function_t *func = NULL;
-
-       // check functions
-       for (func = cmd->userdefined->csqc_functions; func; func = func->next)
-               if (!Cmd_Compare(partial, func->name, len, casesensitive))
-                       break;
-
-       for (func=cmd->engine_functions ; func ; func=func->next)
-               if (!Cmd_Compare(partial, func->name, len, casesensitive))
-                       break;
-
-       return func;
-}
-
 /*
 ============
 Cmd_Exists
@@ -1937,11 +1921,20 @@ Cmd_Exists
 */
 qbool Cmd_Exists (cmd_state_t *cmd, const char *cmd_name)
 {
-       if(Cmd_GetCommand(cmd, cmd_name, 0, true))
-               return true;
+       cmd_function_t  *func;
+
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
+               if (!strcmp(cmd_name, func->name))
+                       return true;
+
+       for (func=cmd->engine_functions ; func ; func=func->next)
+               if (!strcmp (cmd_name,func->name))
+                       return true;
+
        return false;
 }
 
+
 /*
 ============
 Cmd_CompleteCommand
@@ -1950,10 +1943,22 @@ Cmd_CompleteCommand
 const char *Cmd_CompleteCommand (cmd_state_t *cmd, const char *partial)
 {
        cmd_function_t *func;
+       size_t len;
+
+       len = strlen(partial);
+
+       if (!len)
+               return NULL;
+
+// check functions
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
+               if (!strncasecmp(partial, func->name, len))
+                       return func->name;
+
+       for (func = cmd->engine_functions; func; func = func->next)
+               if (!strncasecmp(partial, func->name, len))
+                       return func->name;
 
-       func = Cmd_GetCommand(cmd, partial, strlen(partial), false);
-       if(func)
-               return func->name;
        return NULL;
 }
 
@@ -1979,7 +1984,7 @@ int Cmd_CompleteCountPossible (cmd_state_t *cmd, const char *partial)
                return 0;
 
        // Loop through the command list and count all partial matches
-       for (func = cmd->userdefined->csqc_functions; func; func = func->next)
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
                if (!strncasecmp(partial, func->name, len))
                        h++;
 
@@ -2010,7 +2015,7 @@ const char **Cmd_CompleteBuildList (cmd_state_t *cmd, const char *partial)
        len = strlen(partial);
        buf = (const char **)Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *));
        // Loop through the functions lists and print all matches
-       for (func = cmd->userdefined->csqc_functions; func; func = func->next)
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
                if (!strncasecmp(partial, func->name, len))
                        buf[bpos++] = func->name;
        for (func = cmd->engine_functions; func; func = func->next)
@@ -2027,7 +2032,7 @@ void Cmd_CompleteCommandPrint (cmd_state_t *cmd, const char *partial)
        cmd_function_t *func;
        size_t len = strlen(partial);
        // Loop through the command list and print all matches
-       for (func = cmd->userdefined->csqc_functions; func; func = func->next)
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
                if (!strncasecmp(partial, func->name, len))
                        Con_Printf("^2%s^7: %s\n", func->name, func->description);
        for (func = cmd->engine_functions; func; func = func->next)
@@ -2136,7 +2141,7 @@ const char **Cmd_CompleteAliasBuildList (cmd_state_t *cmd, const char *partial)
 void Cmd_ClearCSQCCommands (cmd_state_t *cmd)
 {
        cmd_function_t *func;
-       cmd_function_t **next = &cmd->userdefined->csqc_functions;
+       cmd_function_t **next = &cmd->userdefined->qc_functions;
        
        while(*next)
        {
@@ -2173,12 +2178,23 @@ void Cmd_ExecuteString (cmd_state_t *cmd, const char *text, cmd_source_t src, qb
                goto done; // no tokens
 
 // check functions
-       func = Cmd_GetCommand(cmd, cmd->argv[0], 0, false);
-       if(func)
+       for (func = cmd->userdefined->qc_functions; func; func = func->next)
        {
-               if (func->csqcfunc && CL_VM_ConsoleCommand(text))       //[515]: csqc
-                       goto done;
-               else
+               if (!strcasecmp(cmd->argv[0], func->name))
+               {
+                       if(func->qcfunc)
+                       {
+                               if((func->flags & CF_CLIENT) && CL_VM_ConsoleCommand(text))
+                                       goto done;
+                               else if((func->flags & CF_SERVER) && SV_VM_ConsoleCommand(text))
+                                       goto done;
+                       }
+               }
+       }
+
+       for (func = cmd->engine_functions; func; func=func->next)
+       {
+               if (!strcasecmp (cmd->argv[0], func->name))
                {
                        switch (src)
                        {
@@ -2198,6 +2214,7 @@ void Cmd_ExecuteString (cmd_state_t *cmd, const char *text, cmd_source_t src, qb
                                        goto done;
                                }
                        }
+                       break;
                }
        }
 
@@ -2263,7 +2280,7 @@ void Cmd_SaveInitState(void)
                cmd_state_t *cmd = cmd_iter->cmd;
                cmd_function_t *f;
                cmd_alias_t *a;
-               for (f = cmd->userdefined->csqc_functions; f; f = f->next)
+               for (f = cmd->userdefined->qc_functions; f; f = f->next)
                        f->initstate = true;
                for (f = cmd->engine_functions; f; f = f->next)
                        f->initstate = true;
@@ -2284,7 +2301,7 @@ void Cmd_RestoreInitState(void)
                cmd_state_t *cmd = cmd_iter->cmd;
                cmd_function_t *f, **fp;
                cmd_alias_t *a, **ap;
-               for (fp = &cmd->userdefined->csqc_functions; (f = *fp);)
+               for (fp = &cmd->userdefined->qc_functions; (f = *fp);)
                {
                        if (f->initstate)
                                fp = &f->next;