From 43b509ba4fcf484186ccaf811ac4e5147f355156 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Sun, 2 Apr 2017 18:18:57 +0000 Subject: [PATCH] Add "apropos" command from QS-Spike git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1393 af15c1b1-3010-417e-b628-4374ebc0bcbd --- Quake/cmd.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ Quake/common.c | 40 ++++++++++++++++++++++++++++++++++ Quake/common.h | 3 +++ 3 files changed, 101 insertions(+) diff --git a/Quake/cmd.c b/Quake/cmd.c index b14143ab..4df16e4b 100644 --- a/Quake/cmd.c +++ b/Quake/cmd.c @@ -499,6 +499,62 @@ void Cmd_List_f (void) Con_SafePrintf ("\n"); } +static char *Cmd_TintSubstring(const char *in, const char *substr, char *out, size_t outsize) +{ + int l; + char *m; + q_strlcpy(out, in, outsize); + while ((m = q_strcasestr(out, substr))) + { + l = strlen(substr); + while (l-->0) + if (*m >= ' ' && *m < 127) + *m++ |= 0x80; + } + return out; +} + +/* +============ +Cmd_Apropos_f + +scans through each command and cvar names+descriptions for the given substring +we don't support descriptions, so this isn't really all that useful, but even without the sake of consistency it still combines cvars+commands under a single command. +============ +*/ +void Cmd_Apropos_f(void) +{ + char tmpbuf[256]; + int hits = 0; + cmd_function_t *cmd; + cvar_t *var; + const char *substr = Cmd_Argv (1); + if (!*substr) + { + Con_SafePrintf ("%s : search through commands and cvars for the given substring\n", Cmd_Argv(0)); + return; + } + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (q_strcasestr(cmd->name, substr)) + { + hits++; + Con_SafePrintf ("%s\n", Cmd_TintSubstring(cmd->name, substr, tmpbuf, sizeof(tmpbuf))); + } + } + + for (var=Cvar_FindVarAfter("", 0) ; var ; var=var->next) + { + if (q_strcasestr(var->name, substr)) + { + hits++; + Con_SafePrintf ("%s (current value: \"%s\")\n", Cmd_TintSubstring(var->name, substr, tmpbuf, sizeof(tmpbuf)), var->string); + } + } + if (!hits) + Con_SafePrintf ("no cvars nor commands contain that substring\n"); +} + /* ============ Cmd_Init @@ -516,6 +572,8 @@ void Cmd_Init (void) Cmd_AddCommand ("alias",Cmd_Alias_f); Cmd_AddCommand ("cmd", Cmd_ForwardToServer); Cmd_AddCommand ("wait", Cmd_Wait_f); + + Cmd_AddCommand ("apropos", Cmd_Apropos_f); } /* diff --git a/Quake/common.c b/Quake/common.c index b1b34593..9fc07658 100644 --- a/Quake/common.c +++ b/Quake/common.c @@ -190,6 +190,46 @@ int q_strncasecmp(const char *s1, const char *s2, size_t n) return (int)(c1 - c2); } +//spike -- grabbed this from fte, because its useful to me +char *q_strcasestr(const char *haystack, const char *needle) +{ + int c1, c2, c2f; + int i; + c2f = *needle; + if (c2f >= 'a' && c2f <= 'z') + c2f -= ('a' - 'A'); + if (!c2f) + return (char*)haystack; + while (1) + { + c1 = *haystack; + if (!c1) + return NULL; + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c1 == c2f) + { + for (i = 1; ; i++) + { + c1 = haystack[i]; + c2 = needle[i]; + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (!c2) + return (char*)haystack; //end of needle means we found a complete match + if (!c1) //end of haystack means we can't possibly find needle in it any more + return NULL; + if (c1 != c2) //mismatch means no match starting at haystack[0] + break; + } + } + haystack++; + } + return NULL; //didn't find it +} + char *q_strlwr (char *str) { char *c; diff --git a/Quake/common.h b/Quake/common.h index 81461140..5fc97b6b 100644 --- a/Quake/common.h +++ b/Quake/common.h @@ -141,6 +141,9 @@ float Q_atof (const char *str); extern int q_strcasecmp (const char * s1, const char * s2); extern int q_strncasecmp (const char *s1, const char *s2, size_t n); +/* locale-insensitive case-insensitive alternative to strstr */ +extern char *q_strcasestr(const char *haystack, const char *needle); + /* locale-insensitive strlwr/upr replacement functions: */ extern char *q_strlwr (char *str); extern char *q_strupr (char *str);