]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cmd.c
cmd: Check for empty cbuf when inserting too
[xonotic/darkplaces.git] / cmd.c
diff --git a/cmd.c b/cmd.c
index 903b923b2fb8f3c1d66fded30c658d0590ef8b69..a12fae8ea0c4fa52839d66a46267e73b927936bf 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -22,8 +22,7 @@ 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_local;
 cmd_state_t *cmd_serverfromclient;
 
 cmd_userdefined_t cmd_userdefined_all;
@@ -87,12 +86,8 @@ static void Cmd_Defer_f (cmd_state_t *cmd)
                        Con_Printf("No commands are pending.\n");
                else
                {
-                       llist_t *pos;
-               List_For_Each(pos, &cbuf->deferred)
-               {
-                               current = List_Entry(*pos, cmd_input_t, list);
+                       List_For_Each_Entry(current, &cbuf->deferred, 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)))
@@ -184,7 +179,7 @@ static cmd_input_t *Cbuf_LinkGet(cmd_buf_t *cbuf, cmd_input_t *existing)
                ret = existing;
        else if(!List_Is_Empty(&cbuf->free))
        {
-               ret = List_Entry(*cbuf->free.next, cmd_input_t, list);
+               ret = List_Entry(cbuf->free.next, cmd_input_t, list);
                ret->length = 0;
                ret->pending = false;
        }
@@ -199,6 +194,11 @@ static cmd_input_t *Cmd_AllocInputNode(void)
        return node;
 }
 
+
+// Cloudwalk FIXME: The entire design of this thing is overly complicated.
+// We could very much safely have one input node per line whether or not
+// the command was terminated. We don't need to split up input nodes per command
+// executed.
 static size_t Cmd_ParseInput (cmd_input_t **output, char **input)
 {
        size_t pos, cmdsize = 0, start = 0;
@@ -285,6 +285,7 @@ static size_t Cmd_ParseInput (cmd_input_t **output, char **input)
                if(!*output)
                        *output = Cmd_AllocInputNode();
 
+               // Append, since this input line hasn't closed yet.
                if((*output)->pending)
                        offset = (*output)->length;
 
@@ -297,6 +298,11 @@ static size_t Cmd_ParseInput (cmd_input_t **output, char **input)
                }
 
                strlcpy(&(*output)->text[offset], &(*input)[start], cmdsize + 1);
+               
+               /*
+                * If we were still looking ahead by the time we broke from the loop, the command input
+                * hasn't terminated yet and we're still expecting more, so keep this node open for appending later.
+                */
                (*output)->pending = !lookahead;
        }
 
@@ -317,12 +323,14 @@ static void Cbuf_LinkCreate(cmd_state_t *cmd, llist_t *head, cmd_input_t *existi
        // Slide the pointer down until we reach the end
        while(*in)
        {
+               // Check if the current node is still accepting input (input line hasn't terminated)
                current = Cbuf_LinkGet(cbuf, existing);
                newsize = Cmd_ParseInput(&current, &in);
 
                // Valid command
                if(newsize)
                {
+                       // current will match existing if the input line hasn't terminated yet
                        if(current != existing)
                        {
                                current->source = cmd;
@@ -358,7 +366,7 @@ void Cbuf_AddText (cmd_state_t *cmd, const char *text)
                Con_Print("Cbuf_AddText: overflow\n");
        else
        {
-               Cbuf_LinkCreate(cmd, &llist, (List_Is_Empty(&cbuf->start) ? NULL : List_Entry(*cbuf->start.prev, cmd_input_t, list)), text);
+               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);
        }
@@ -386,7 +394,7 @@ void Cbuf_InsertText (cmd_state_t *cmd, const char *text)
                Con_Print("Cbuf_InsertText: overflow\n");
        else
        {
-               Cbuf_LinkCreate(cmd, &llist, List_Entry(*cbuf->start.next, cmd_input_t, list), text);
+               Cbuf_LinkCreate(cmd, &llist, (List_Is_Empty(&cbuf->start) ? NULL : List_Entry(cbuf->start.next, cmd_input_t, list)), text);
                if(!List_Is_Empty(&llist))
                        List_Splice(&llist, &cbuf->start);
        }
@@ -401,7 +409,6 @@ Cbuf_Execute_Deferred --blub
 */
 static void Cbuf_Execute_Deferred (cmd_buf_t *cbuf)
 {
-       llist_t *pos;
        cmd_input_t *current;
        double eat;
 
@@ -412,14 +419,13 @@ static void Cbuf_Execute_Deferred (cmd_buf_t *cbuf)
                return;
        cbuf->deferred_oldtime = host.realtime;
 
-    List_For_Each(pos, &cbuf->deferred)
+       List_For_Each_Entry(current, &cbuf->deferred, cmd_input_t, list)
        {
-               current = List_Entry(*pos, cmd_input_t, list);
                current->delay -= eat;
                if(current->delay <= 0)
                {
                        cbuf->size += current->length;
-                       List_Move(pos, &cbuf->start);
+                       List_Move(&current->list, &cbuf->start);
                        // We must return and come back next frame or the engine will freeze. Fragile... like glass :3
                        return;
                }
@@ -448,7 +454,7 @@ void Cbuf_Execute (cmd_buf_t *cbuf)
                 * commands down. This is necessary because commands (exec, alias)
                 * can insert data at the beginning of the text buffer
                 */
-               current = List_Entry(*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);
@@ -503,12 +509,7 @@ static void Cbuf_Frame_Input(void)
        char *line;
 
        while ((line = Sys_ConsoleInput()))
-       {
-               if (cls.state == ca_dedicated)
-                       Cbuf_AddText(cmd_server, line);
-               else
-                       Cbuf_AddText(cmd_client, line);
-       }
+                       Cbuf_AddText(cmd_local, line);
 }
 
 void Cbuf_Frame(cmd_buf_t *cbuf)
@@ -1587,12 +1588,12 @@ static void Cmd_Apropos_f(cmd_state_t *cmd)
                        Cvar_PrintHelp(cvar, cvar->name, true);
                        count++;
                }
-               for (int i = 0; i < cvar->aliasindex; i++)
+               for (char **cvar_alias = cvar->aliases; cvar_alias && *cvar_alias; cvar_alias++)
                {
-                       if (matchpattern_with_separator(cvar->aliases[i], partial, true, "", false))
+                       if (matchpattern_with_separator(*cvar_alias, partial, true, "", false))
                        {
                                Con_Printf ("cvar ");
-                               Cvar_PrintHelp(cvar, cvar->aliases[i], true);
+                               Cvar_PrintHelp(cvar, *cvar_alias, true);
                                count++;
                        }
                }
@@ -1662,24 +1663,19 @@ void Cmd_Init(void)
        cbuf->free.prev = cbuf->free.next = &(cbuf->free);
 
        // 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_iter_all[0].cmd = cmd_client = Cmd_AddInterpreter(cbuf, &cvars_all, CF_CLIENT | CF_SERVER, CF_CLIENT | CF_CLIENT_FROM_SERVER, &cmd_userdefined_all);
-       cmd_client->Handle = Cmd_CL_Callback;
-       cmd_client->NotFound = NULL;
+       cmd_iter_all = (cmd_iter_t *)Mem_Alloc(tempmempool, sizeof(cmd_iter_t) * 3);
 
-       // dedicated server console can only see server cvars, there is no client
-       cmd_iter_all[1].cmd = cmd_server = Cmd_AddInterpreter(cbuf, &cvars_all, CF_SERVER, CF_SERVER, &cmd_userdefined_all);
-       cmd_server->Handle = Cmd_SV_Callback;
-       cmd_server->NotFound = NULL;
+       // local console
+       cmd_iter_all[0].cmd = cmd_local = Cmd_AddInterpreter(cbuf, &cvars_all, CF_CLIENT | CF_SERVER, CF_CLIENT | CF_CLIENT_FROM_SERVER | CF_SERVER_FROM_CLIENT, &cmd_userdefined_all);
+       cmd_local->Handle = Cmd_CL_Callback;
+       cmd_local->NotFound = NULL;
 
        // server commands received from clients have no reason to access cvars, cvar expansion seems perilous.
-       cmd_iter_all[2].cmd = cmd_serverfromclient = Cmd_AddInterpreter(cbuf, &cvars_null, 0, CF_SERVER_FROM_CLIENT | CF_USERINFO, &cmd_userdefined_null);
+       cmd_iter_all[1].cmd = cmd_serverfromclient = Cmd_AddInterpreter(cbuf, &cvars_null, 0, CF_SERVER_FROM_CLIENT | CF_USERINFO, &cmd_userdefined_null);
        cmd_serverfromclient->Handle = Cmd_SV_Callback;
        cmd_serverfromclient->NotFound = Cmd_SV_NotFound;
 
-       cmd_iter_all[3].cmd = NULL;
+       cmd_iter_all[2].cmd = NULL;
 //
 // register our commands
 //
@@ -1850,7 +1846,7 @@ void Cmd_AddCommand(int flags, const char *cmd_name, xcommand_t function, const
        cmd_state_t *cmd;
        int i;
 
-       for (i = 0; i < 3; i++)
+       for (i = 0; i < 2; i++)
        {
                cmd = cmd_iter_all[i].cmd;
                if (flags & cmd->cmd_flags)
@@ -2167,6 +2163,18 @@ void Cmd_ClearCSQCCommands (cmd_state_t *cmd)
 
 extern cvar_t sv_cheats;
 
+/*
+ * Cloudwalk FIXME: This idea sounded great in my head but...
+ * How do we handle commands that can be received by the client,
+ * but which the server can also execute locally?
+ * 
+ * If we create a callback where the engine will forward to server
+ * but try to execute the command locally if it's dedicated,
+ * we're back to intermixing client and server code which I'm
+ * trying to avoid. There's no other way I can think of to
+ * implement that behavior that doesn't involve an #ifdef, or
+ * making a mess of hooks.
+ */
 qbool Cmd_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src)
 {
        if (func->function)
@@ -2178,15 +2186,27 @@ qbool Cmd_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd
 
 qbool Cmd_CL_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src)
 {
-       if(func->qcfunc && (func->flags & CF_CLIENT))
-               return CL_VM_ConsoleCommand(text);
-       else if ((func->flags & CF_SERVER_FROM_CLIENT) && src == src_local)
+       // TODO: Assign these functions to QC commands directly?
+       if(func->qcfunc)
        {
-               CL_ForwardToServer_f(cmd);
-               return true;
+               if(((func->flags & CF_CLIENT) && CL_VM_ConsoleCommand(text)) ||
+                  ((func->flags & CF_SERVER) && SV_VM_ConsoleCommand(text)))
+                       return true;
        }
-       else
-               return Cmd_Callback(cmd, func, text, src);
+       if (func->flags & CF_SERVER_FROM_CLIENT)
+       {
+               if(host_isclient.integer)
+               {
+                       CL_ForwardToServer_f(cmd);
+                       return true;
+               }
+               else if(!(func->flags & CF_SERVER))
+               {
+                       Con_Printf("Cannot execute client commands from a dedicated server console.\n");
+                       return true;
+               }
+       }
+       return Cmd_Callback(cmd, func, text, src);
 }
 
 qbool Cmd_SV_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src)
@@ -2201,8 +2221,7 @@ qbool Cmd_SV_Callback(cmd_state_t *cmd, cmd_function_t *func, const char *text,
                        func->function(cmd);
                return true;
        }
-       else
-               return Cmd_Callback(cmd, func, text, src);
+       return false;
 }
 
 qbool Cmd_SV_NotFound(cmd_state_t *cmd, cmd_function_t *func, const char *text, cmd_source_t src)
@@ -2391,3 +2410,7 @@ void Cmd_RestoreInitState(void)
        }
        Cvar_RestoreInitState(&cvars_all);
 }
+
+void Cmd_NoOperation_f(cmd_state_t *cmd)
+{
+}