]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cmd.c
apropos command
[xonotic/darkplaces.git] / cmd.c
diff --git a/cmd.c b/cmd.c
index 5d9b0a892a3689265a63f3f21272c58eeb15748d..133865c931aacbe965287f3da20f090dba57b49f 100644 (file)
--- a/cmd.c
+++ b/cmd.c
@@ -70,7 +70,7 @@ typedef struct cmddeferred_s
        double time;
 } cmddeferred_t;
 
-static cmddeferred_t *cmd_deferred_list;
+static cmddeferred_t *cmd_deferred_list = NULL;
 
 /*
 ============
@@ -89,25 +89,44 @@ static void Cmd_Defer_f (void)
                        Con_Printf("No commands are pending.\n");
                while(next)
                {
-                       Con_Printf("-> In %'9.2f: %s\n", next->time-time, next->value);
+                       Con_Printf("-> In %9.2f: %s\n", next->time-time, next->value);
                        next = next->next;
                }
-       } else if(Cmd_Argc() != 3)
+       } else if(Cmd_Argc() == 2 && !strcasecmp("clear", Cmd_Argv(1)))
+       {
+               while(cmd_deferred_list)
+               {
+                       cmddeferred_t *cmd = cmd_deferred_list;
+                       cmd_deferred_list = cmd->next;
+                       Mem_Free(cmd->value);
+                       Mem_Free(cmd);
+               }
+       } else if(Cmd_Argc() == 3)
        {
-               Con_Printf("usage: defer <seconds> <command>\n");
-               return;
-       } else {
                const char *value = Cmd_Argv(2);
                cmddeferred_t *defcmd = (cmddeferred_t*)Mem_Alloc(tempmempool, sizeof(*defcmd));
-               unsigned int len = strlen(value);
+               size_t len = strlen(value);
 
                defcmd->time = Sys_DoubleTime() + atof(Cmd_Argv(1));
                defcmd->value = (char*)Mem_Alloc(tempmempool, len+1);
-               memcpy(defcmd->value, value, len);
-               defcmd->value[len] = 0;
+               memcpy(defcmd->value, value, len+1);
+               defcmd->next = NULL;
 
-               defcmd->next = cmd_deferred_list;
-               cmd_deferred_list = defcmd;
+               if(cmd_deferred_list)
+               {
+                       cmddeferred_t *next = cmd_deferred_list;
+                       while(next->next)
+                               next = next->next;
+                       next->next = defcmd;
+               } else
+                       cmd_deferred_list = defcmd;
+               /* Stupid me... this changes the order... so commands with the same delay go blub :S
+                 defcmd->next = cmd_deferred_list;
+                 cmd_deferred_list = defcmd;*/
+       } else {
+               Con_Printf("usage: defer <seconds> <command>\n"
+                          "       defer clear\n");
+               return;
        }
 }
 
@@ -240,18 +259,19 @@ void Cbuf_Execute_Deferred (void)
                if(cmd->time <= time)
                {
                        Cbuf_AddText(cmd->value);
+                       Cbuf_AddText(";\n");
                        Mem_Free(cmd->value);
-                       
-                       if(prev)
+
+                       if(prev) {
                                prev->next = cmd->next;
-                       else
+                               Mem_Free(cmd);
+                               cmd = prev->next;
+                       } else {
                                cmd_deferred_list = cmd->next;
-                       
-                       Mem_Free(cmd);
-                       
-                       cmd = prev;
-                       if(!cmd)
-                               return;
+                               Mem_Free(cmd);
+                               cmd = cmd_deferred_list;
+                       }
+                       continue;
                }
                prev = cmd;
                cmd = cmd->next;
@@ -271,7 +291,7 @@ void Cbuf_Execute (void)
        char line[MAX_INPUTLINE];
        char preprocessed[MAX_INPUTLINE];
        char *firstchar;
-       int quotes;
+       qboolean quotes, comment;
 
        // LordHavoc: making sure the tokenizebuffer doesn't get filled up by repeated crashes
        cmd_tokenizebufferpos = 0;
@@ -282,17 +302,31 @@ void Cbuf_Execute (void)
 // find a \n or ; line break
                text = (char *)cmd_text.data;
 
-               quotes = 0;
-               for (i=0 ; i< cmd_text.cursize ; i++)
+               quotes = false;
+               comment = false;
+               for (i=0 ; i < cmd_text.cursize ; i++)
                {
-                       if (text[i] == '"')
-                               quotes ^= 1;
-                       // make sure i doesn't get > cursize which causes a negative
-                       // size in memmove, which is fatal --blub
-                       if (i < (cmd_text.cursize-1) && (text[i] == '\\' && (text[i+1] == '"' || text[i+1] == '\\')))
-                               i++;
-                       if ( !quotes &&  text[i] == ';')
-                               break;  // don't break if inside a quoted string
+                       if(!comment)
+                       {
+                               if (text[i] == '"')
+                                       quotes = !quotes;
+
+                               if(quotes)
+                               {
+                                       // make sure i doesn't get > cursize which causes a negative
+                                       // size in memmove, which is fatal --blub
+                                       if (i < (cmd_text.cursize-1) && (text[i] == '\\' && (text[i+1] == '"' || text[i+1] == '\\')))
+                                               i++;
+                               }
+                               else
+                               {
+                                       if(text[i] == '/' && text[i + 1] == '/')
+                                               comment = true;
+                                       if(text[i] == ';')
+                                               break;  // don't break if inside a quoted string or comment
+                               }
+                       }
+
                        if (text[i] == '\r' || text[i] == '\n')
                                break;
                }
@@ -574,7 +608,7 @@ static void Cmd_Alias_f (void)
        {
                Con_Print("Current alias commands:\n");
                for (a = cmd_alias ; a ; a=a->next)
-                       Con_Printf("%s : %s\n", a->name, a->value);
+                       Con_Printf("%s : %s", a->name, a->value);
                return;
        }
 
@@ -625,6 +659,8 @@ static void Cmd_Alias_f (void)
        strlcat (cmd, "\n", sizeof (cmd));
 
        alloclen = strlen (cmd) + 1;
+       if(alloclen >= 2)
+               cmd[alloclen - 2] = '\n'; // to make sure a newline is appended even if too long
        a->value = (char *)Z_Malloc (alloclen);
        memcpy (a->value, cmd, alloclen);
 }
@@ -692,7 +728,7 @@ static const char *Cmd_GetDirectCvarValue(const char *varname, cmdalias_t *alias
                                                *is_multiple = true;
 
                                        // kill pre-argument whitespace
-                                       for (;*p && *p <= ' ';p++)
+                                       for (;*p && ISWHITESPACE(*p);p++)
                                                ;
 
                                        return p;
@@ -806,7 +842,8 @@ static const char *Cmd_GetCvarValue(const char *var, size_t varlen, cmdalias_t *
                // Exception: $* and $n- don't use the quoted form by default
                varstr = Cmd_GetDirectCvarValue(varname, alias, &is_multiple);
                if(is_multiple)
-                       varfunc = "asis";
+                       if(!varfunc)
+                               varfunc = "asis";
        }
 
        if(!varstr)
@@ -987,12 +1024,14 @@ static void Cmd_List_f (void)
 {
        cmd_function_t *cmd;
        const char *partial;
-       int len, count;
+       size_t len;
+       int count;
+       qboolean ispattern;
 
        if (Cmd_Argc() > 1)
        {
                partial = Cmd_Argv (1);
-               len = (int)strlen(partial);
+               len = strlen(partial);
        }
        else
        {
@@ -1000,21 +1039,86 @@ static void Cmd_List_f (void)
                len = 0;
        }
 
+       ispattern = partial && (strchr(partial, '*') || strchr(partial, '?'));
+
        count = 0;
        for (cmd = cmd_functions; cmd; cmd = cmd->next)
        {
-               if (partial && strncmp(partial, cmd->name, len))
+               if (partial && (ispattern ? !matchpattern_with_separator(cmd->name, partial, false, "", false) : strncmp(partial, cmd->name, len)))
                        continue;
                Con_Printf("%s : %s\n", cmd->name, cmd->description);
                count++;
        }
 
-       if (partial)
-               Con_Printf("%i Command%s beginning with \"%s\"\n\n", count, (count > 1) ? "s" : "", partial);
+       if (len)
+       {
+               if(ispattern)
+                       Con_Printf("%i Command%s matching \"%s\"\n\n", count, (count > 1) ? "s" : "", partial);
+               else
+                       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" : "");
 }
 
+static void Cmd_Apropos_f(void)
+{
+       cmd_function_t *cmd;
+       cvar_t *cvar;
+       cmdalias_t *alias;
+       const char *partial;
+       size_t len;
+       int count;
+       qboolean ispattern;
+
+       if (Cmd_Argc() > 1)
+       {
+               partial = Cmd_Args();
+               len = strlen(partial);
+       }
+       else
+       {
+               Con_Printf("usage: apropos <string>\n");
+               return;
+       }
+
+       ispattern = partial && (strchr(partial, '*') || strchr(partial, '?'));
+       if(!ispattern)
+       {
+               partial = va("*%s*", partial);
+               len += 2;
+       }
+
+       count = 0;
+       Con_Printf("Cvars:\n");
+       for (cvar = cvar_vars; cvar; cvar = cvar->next)
+       {
+               if (!matchpattern_with_separator(cvar->name, partial, false, "", false))
+               if (!matchpattern_with_separator(cvar->description, partial, false, "", false))
+                       continue;
+               Con_Printf("^3%s^7: %s\n", cvar->name, cvar->description);
+               count++;
+       }
+       Con_Printf("Commands:\n");
+       for (cmd = cmd_functions; cmd; cmd = cmd->next)
+       {
+               if (!matchpattern_with_separator(cmd->name, partial, false, "", false))
+               if (!matchpattern_with_separator(cmd->description, partial, false, "", false))
+                       continue;
+               Con_Printf("^3%s^7: %s\n", cmd->name, cmd->description);
+               count++;
+       }
+       Con_Printf("Aliases:\n");
+       for (alias = cmd_alias; alias; alias = alias->next)
+       {
+               if (!matchpattern_with_separator(alias->name, partial, false, "", false))
+               if (!matchpattern_with_separator(alias->value, partial, false, "", false))
+                       continue;
+               Con_Printf("^3%s^7: %s", alias->name, alias->value);
+               count++;
+       }
+}
+
 /*
 ============
 Cmd_Init
@@ -1047,6 +1151,7 @@ void Cmd_Init_Commands (void)
        // Added/Modified by EvilTypeGuy eviltypeguy@qeradiant.com
        Cmd_AddCommand ("cmdlist", Cmd_List_f, "lists all console commands beginning with the specified prefix");
        Cmd_AddCommand ("cvarlist", Cvar_List_f, "lists all console variables beginning with the specified prefix");
+       Cmd_AddCommand ("apropos", Cmd_Apropos_f, "lists all console variables/commands/aliases containing the specified string in the name or description");
 
        Cmd_AddCommand ("cvar_lockdefaults", Cvar_LockDefaults_f, "stores the current values of all cvars into their default values, only used once during startup after parsing default.cfg");
        Cmd_AddCommand ("cvar_resettodefaults_all", Cvar_ResetToDefaults_All_f, "sets all cvars to their locked default values");
@@ -1122,7 +1227,7 @@ static void Cmd_TokenizeString (const char *text)
        while (1)
        {
                // skip whitespace up to a /n
-               while (*text && *text <= ' ' && *text != '\r' && *text != '\n')
+               while (*text && ISWHITESPACE(*text) && *text != '\r' && *text != '\n')
                        text++;
 
                // line endings:
@@ -1448,11 +1553,13 @@ FIXME: lookupnoadd the token to speed search?
 void Cmd_ExecuteString (const char *text, cmd_source_t src)
 {
        int oldpos;
+       int found;
        cmd_function_t *cmd;
        cmdalias_t *a;
 
        oldpos = cmd_tokenizebufferpos;
        cmd_source = src;
+       found = false;
 
        Cmd_TokenizeString (text);
 
@@ -1487,8 +1594,9 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
                                }
                                else
                                        Con_Printf("Command \"%s\" can not be executed\n", Cmd_Argv(0));
-                               cmd_tokenizebufferpos = oldpos;
-                               return;
+                               found = true;
+                               goto command_found;
+                               break;
                        case src_client:
                                if (cmd->clientfunction)
                                {
@@ -1501,11 +1609,13 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
                        break;
                }
        }
+command_found:
 
        // if it's a client command and no command was found, say so.
        if (cmd_source == src_client)
        {
                Con_Printf("player \"%s\" tried to %s\n", host_client->name, text);
+               cmd_tokenizebufferpos = oldpos;
                return;
        }
 
@@ -1520,6 +1630,12 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src)
                }
        }
 
+       if(found) // if the command was hooked and found, all is good
+       {
+               cmd_tokenizebufferpos = oldpos;
+               return;
+       }
+
 // check cvars
        if (!Cvar_Command () && host_framecount > 0)
                Con_Printf("Unknown command \"%s\"\n", Cmd_Argv(0));