cmd.c

Go to the documentation of this file.
00001 
00014 /*
00015 Copyright (C) 1997-2001 Id Software, Inc.
00016 
00017 This program is free software; you can redistribute it and/or
00018 modify it under the terms of the GNU General Public License
00019 as published by the Free Software Foundation; either version 2
00020 of the License, or (at your option) any later version.
00021 
00022 This program is distributed in the hope that it will be useful,
00023 but WITHOUT ANY WARRANTY; without even the implied warranty of
00024 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00025 
00026 See the GNU General Public License for more details.
00027 
00028 You should have received a copy of the GNU General Public License
00029 along with this program; if not, write to the Free Software
00030 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00031 
00032 */
00033 
00034 #include "common.h"
00035 #include "msg.h"
00036 #include "../shared/parse.h"
00037 
00038 void Cmd_ForwardToServer(void);
00039 #define ALIAS_HASH_SIZE 32
00040 
00041 #define MAX_ALIAS_NAME  32
00042 
00043 typedef struct cmd_alias_s {
00044     char name[MAX_ALIAS_NAME];
00045     char *value;
00046     qboolean archive;   
00047     struct cmd_alias_s *hash_next;
00048     struct cmd_alias_s *next;
00049 } cmd_alias_t;
00050 
00051 static cmd_alias_t *cmd_alias;
00052 static cmd_alias_t *cmd_alias_hash[ALIAS_HASH_SIZE];
00053 static qboolean cmdWait;
00054 static qboolean cmdClosed;
00055 
00056 #define ALIAS_LOOP_COUNT    16
00057 static int alias_count;             /* for detecting runaway loops */
00058 
00059 
00064 static void Cmd_Open_f (void)
00065 {
00066     Com_DPrintf(DEBUG_COMMANDS, "Cmd_Close_f: command buffer opened again\n");
00067     cmdClosed = qfalse;
00068 }
00069 
00075 static void Cmd_Close_f (void)
00076 {
00077     Com_DPrintf(DEBUG_COMMANDS, "Cmd_Close_f: command buffer closed\n");
00078     cmdClosed = qtrue;
00079 }
00080 
00086 static void Cmd_Wait_f (void)
00087 {
00088     cmdWait = qtrue;
00089 }
00090 
00091 /*
00092 =============================================================================
00093 COMMAND BUFFER
00094 =============================================================================
00095 */
00096 
00097 #define CMD_BUFFER_SIZE 8192
00098 static sizebuf_t cmd_text;
00099 static byte cmd_text_buf[CMD_BUFFER_SIZE];
00100 static char defer_text_buf[CMD_BUFFER_SIZE];
00101 
00105 void Cbuf_Init (void)
00106 {
00107     SZ_Init(&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
00108 }
00109 
00114 void Cbuf_AddText (const char *text)
00115 {
00116     int l;
00117 
00118     if (cmdClosed) {
00119         text = strstr(text, "cmdopen");
00120         if (text == NULL) {
00121             Com_DPrintf(DEBUG_COMMANDS, "Cbuf_AddText: currently closed\n");
00122             return;
00123         }
00124     }
00125 
00126     l = strlen(text);
00127 
00128     if (cmd_text.cursize + l >= cmd_text.maxsize) {
00129         Com_Printf("Cbuf_AddText: overflow (%i) (%s)\n", cmd_text.maxsize, text);
00130         Com_Printf("buffer content: %s\n", cmd_text_buf);
00131         return;
00132     }
00133     SZ_Write(&cmd_text, text, l);
00134 }
00135 
00136 
00142 void Cbuf_InsertText (const char *text)
00143 {
00144     char *temp;
00145     int templen;
00146 
00147     if (!text || !*text)
00148         return;
00149 
00150     /* copy off any commands still remaining in the exec buffer */
00151     templen = cmd_text.cursize;
00152     if (templen) {
00153         temp = Mem_Alloc(templen);
00154         memcpy(temp, cmd_text.data, templen);
00155         SZ_Clear(&cmd_text);
00156     } else
00157         temp = NULL;            /* shut up compiler */
00158 
00159     /* add the entire text of the file */
00160     Cbuf_AddText(text);
00161 
00162     /* add the copied off data */
00163     if (templen) {
00164         SZ_Write(&cmd_text, temp, templen);
00165         Mem_Free(temp);
00166     }
00167 }
00168 
00169 
00176 void Cbuf_CopyToDefer (void)
00177 {
00178     memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
00179     defer_text_buf[cmd_text.cursize] = 0;
00180     cmd_text.cursize = 0;
00181 }
00182 
00186 void Cbuf_InsertFromDefer (void)
00187 {
00188     Cbuf_InsertText(defer_text_buf);
00189     defer_text_buf[0] = 0;
00190 }
00191 
00199 void Cbuf_Execute (void)
00200 {
00201     unsigned int i;
00202     char line[1024];
00203 
00204     /* don't allow infinite alias loops */
00205     alias_count = 0;
00206 
00207     while (cmd_text.cursize) {
00208         /* find a \n or ; line break */
00209         char *text = (char *) cmd_text.data;
00210         int quotes = 0;
00211 
00212         for (i = 0; i < cmd_text.cursize; i++) {
00213             if (text[i] == '"')
00214                 quotes++;
00215             /* don't break if inside a quoted string */
00216             if (!(quotes & 1) && text[i] == ';')
00217                 break;
00218             if (text[i] == '\n')
00219                 break;
00220         }
00221 
00222         if (i > sizeof(line) - 1)
00223             i = sizeof(line) - 1;
00224 
00225         memcpy(line, text, i);
00226         line[i] = 0;
00227 
00228         /* delete the text from the command buffer and move remaining commands down
00229          * this is necessary because commands (exec, alias) can insert data at the
00230          * beginning of the text buffer */
00231         if (i == cmd_text.cursize)
00232             cmd_text.cursize = 0;
00233         else {
00234             i++;
00235             cmd_text.cursize -= i;
00236             memmove(text, text + i, cmd_text.cursize);
00237         }
00238 
00239         /* execute the command line */
00240         Cmd_ExecuteString(line);
00241 
00242         if (cmdWait) {
00243             /* skip out while text still remains in buffer, leaving it
00244              * for next frame */
00245             cmdWait = qfalse;
00246             break;
00247         }
00248     }
00249 }
00250 
00251 
00260 void Cbuf_AddEarlyCommands (qboolean clear)
00261 {
00262     int i;
00263 
00264     for (i = 0; i < Com_Argc(); i++) {
00265         const char *s = Com_Argv(i);
00266         if (strncmp(s, "+set", 4))
00267             continue;
00268         Cbuf_AddText(va("set %s %s\n", Com_Argv(i + 1), Com_Argv(i + 2)));
00269         if (clear) {
00270             Com_ClearArgv(i);
00271             Com_ClearArgv(i + 1);
00272             Com_ClearArgv(i + 2);
00273         }
00274         i += 2;
00275     }
00276 }
00277 
00284 qboolean Cbuf_AddLateCommands (void)
00285 {
00286     int i, j;
00287     int s;
00288     char *text, *build, c;
00289     int argc;
00290     qboolean ret;
00291 
00292     /* build the combined string to parse from */
00293     s = 0;
00294     argc = Com_Argc();
00295     for (i = 1; i < argc; i++) {
00296         s += strlen(Com_Argv(i)) + 1;
00297     }
00298     if (!s)
00299         return qfalse;
00300 
00301     text = Mem_Alloc(s + 1);
00302     text[0] = 0;
00303     for (i = 1; i < argc; i++) {
00304         Q_strcat(text, Com_Argv(i), s);
00305         if (i != argc - 1)
00306             Q_strcat(text, " ", s);
00307     }
00308 
00309     /* pull out the commands */
00310     build = Mem_Alloc(s + 1);
00311     build[0] = 0;
00312 
00313     for (i = 0; i < s - 1; i++) {
00314         if (text[i] == '+') {
00315             i++;
00316 
00317             for (j = i; text[j] != '+' && text[j] != '-' && text[j] != 0; j++) {}
00318 
00319             c = text[j];
00320             text[j] = 0;
00321 
00322             Q_strcat(build, text + i, s);
00323             Q_strcat(build, "\n", s);
00324             text[j] = c;
00325             i = j - 1;
00326         }
00327     }
00328 
00329     ret = (build[0] != 0);
00330     if (ret)
00331         Cbuf_AddText(build);
00332 
00333     Mem_Free(text);
00334     Mem_Free(build);
00335 
00336     return ret;
00337 }
00338 
00339 
00340 /*
00341 ==============================================================================
00342 SCRIPT COMMANDS
00343 ==============================================================================
00344 */
00345 
00346 static void Cmd_Exec_f (void)
00347 {
00348     byte *f;
00349     char *f2;
00350     int len;
00351 
00352     if (Cmd_Argc() != 2) {
00353         Com_Printf("Usage: %s <filename> : execute a script file\n", Cmd_Argv(0));
00354         return;
00355     }
00356 
00357     len = FS_LoadFile(Cmd_Argv(1), &f);
00358     if (!f) {
00359         Com_Printf("couldn't execute %s\n", Cmd_Argv(1));
00360         return;
00361     }
00362     Com_Printf("executing %s\n", Cmd_Argv(1));
00363 
00364     /* the file doesn't have a trailing 0, so we need to copy it off */
00365     f2 = Mem_Alloc(len + 2);
00366     memcpy(f2, f, len);
00367     /* make really sure that there is a newline */
00368     f2[len] = '\n';
00369     f2[len + 1] = 0;
00370 
00371     Cbuf_InsertText(f2);
00372 
00373     Mem_Free(f2);
00374     FS_FreeFile(f);
00375 }
00376 
00377 
00381 static void Cmd_Echo_f (void)
00382 {
00383     int i;
00384 
00385     for (i = 1; i < Cmd_Argc(); i++)
00386         Com_Printf("%s ", Cmd_Argv(i));
00387     Com_Printf("\n");
00388 }
00389 
00393 static void Cmd_Alias_f (void)
00394 {
00395     cmd_alias_t *a;
00396     char cmd[MAX_STRING_CHARS];
00397     size_t len;
00398     unsigned int hash;
00399     int i, c;
00400     const char *s;
00401 
00402     if (Cmd_Argc() == 1) {
00403         Com_Printf("Current alias commands:\n");
00404         for (a = cmd_alias; a; a = a->next)
00405             Com_Printf("%s : %s\n", a->name, a->value);
00406         return;
00407     }
00408 
00409     s = Cmd_Argv(1);
00410     len = strlen(s);
00411     if (len == 0)
00412         return;
00413 
00414     if (len >= MAX_ALIAS_NAME) {
00415         Com_Printf("Alias name is too long\n");
00416         return;
00417     }
00418 
00419     /* if the alias already exists, reuse it */
00420     hash = Com_HashKey(s, ALIAS_HASH_SIZE);
00421     for (a = cmd_alias_hash[hash]; a; a = a->hash_next) {
00422         if (!strcmp(s, a->name)) {
00423             Mem_Free(a->value);
00424             break;
00425         }
00426     }
00427 
00428     if (!a) {
00429         a = Mem_PoolAlloc(sizeof(*a), com_aliasSysPool, 0);
00430         a->next = cmd_alias;
00431         /* cmd_alias_hash should be null on the first run */
00432         a->hash_next = cmd_alias_hash[hash];
00433         cmd_alias_hash[hash] = a;
00434         cmd_alias = a;
00435     }
00436     Q_strncpyz(a->name, s, sizeof(a->name));
00437 
00438     /* copy the rest of the command line */
00439     cmd[0] = 0;                 /* start out with a null string */
00440     c = Cmd_Argc();
00441     for (i = 2; i < c; i++) {
00442         Q_strcat(cmd, Cmd_Argv(i), sizeof(cmd));
00443         if (i != (c - 1))
00444             Q_strcat(cmd, " ", sizeof(cmd));
00445     }
00446 
00447     if (!strcmp(Cmd_Argv(0), "aliasa"))
00448         a->archive = qtrue;
00449 
00450     a->value = Mem_PoolStrDup(cmd, com_aliasSysPool, 0);
00451 }
00452 
00458 void Cmd_WriteAliases (qFILE *f)
00459 {
00460     cmd_alias_t *a;
00461 
00462     for (a = cmd_alias; a; a = a->next)
00463         if (a->archive) {
00464             int i;
00465             FS_Printf(f, "aliasa %s \"", a->name);
00466             for (i = 0; i < strlen(a->value); i++) {
00467                 if (a->value[i] == '"')
00468                     FS_Printf(f, "\\\"");
00469                 else
00470                     FS_Printf(f, "%c", a->value[i]);
00471             }
00472             FS_Printf(f, "\"\n");
00473         }
00474 }
00475 
00476 /*
00477 =============================================================================
00478 COMMAND EXECUTION
00479 =============================================================================
00480 */
00481 
00482 #define CMD_HASH_SIZE 32
00483 
00484 typedef struct cmd_function_s {
00485     struct cmd_function_s *next;
00486     struct cmd_function_s *hash_next;
00487     const char *name;
00488     const char *description;
00489     xcommand_t function;
00490     int (*completeParam) (const char *partial, const char **match);
00491     void* userdata;
00492 } cmd_function_t;
00493 
00494 static int cmd_argc;
00495 static char *cmd_argv[MAX_STRING_TOKENS];
00496 static char cmd_args[MAX_STRING_CHARS];
00497 static void *cmd_userdata;
00498 
00499 static cmd_function_t *cmd_functions;   /* possible commands to execute */
00500 static cmd_function_t *cmd_functions_hash[CMD_HASH_SIZE];
00501 
00507 int Cmd_Argc (void)
00508 {
00509     return cmd_argc;
00510 }
00511 
00518 const char *Cmd_Argv (int arg)
00519 {
00520     if (arg >= cmd_argc)
00521         return "";
00522     return cmd_argv[arg];
00523 }
00524 
00528 const char *Cmd_Args (void)
00529 {
00530     return cmd_args;
00531 }
00532 
00536 void *Cmd_Userdata (void)
00537 {
00538     return cmd_userdata;
00539 }
00540 
00545 void Cmd_BufClear (void)
00546 {
00547     int i;
00548 
00549     /* clear the args from the last string */
00550     for (i = 0; i < cmd_argc; i++) {
00551         Mem_Free(cmd_argv[i]);
00552         cmd_argv[i] = NULL;
00553     }
00554 
00555     cmd_argc = 0;
00556     cmd_args[0] = 0;
00557     cmd_userdata = NULL;
00558 }
00559 
00568 void Cmd_TokenizeString (const char *text, qboolean macroExpand)
00569 {
00570     const char *com_token, *expanded;
00571 
00572     Cmd_BufClear();
00573 
00574     /* macro expand the text */
00575     if (macroExpand) {
00576         expanded = Com_MacroExpandString(text);
00577         if (expanded)
00578             text = expanded;
00579     }
00580 
00581     while (1) {
00582         /* skip whitespace up to a newline */
00583         while (*text && *text <= ' ' && *text != '\n') {
00584             text++;
00585         }
00586 
00587         if (*text == '\n') {    /* a newline seperates commands in the buffer */
00588             text++;
00589             break;
00590         }
00591 
00592         if (!*text)
00593             return;
00594 
00595         /* set cmd_args to everything after the first arg */
00596         if (cmd_argc == 1) {
00597             size_t l;
00598 
00599             Q_strncpyz(cmd_args, text, sizeof(cmd_args));
00600 
00601             /* strip off any trailing whitespace */
00602             l = strlen(cmd_args) - 1;
00603             for (; l >= 0; l--)
00604                 if (cmd_args[l] <= ' ')
00605                     cmd_args[l] = 0;
00606                 else
00607                     break;
00608         }
00609 
00610         com_token = Com_Parse(&text);
00611         if (!text)
00612             return;
00613 
00614         if (cmd_argc < MAX_STRING_TOKENS) {
00615             /* check first char of string if it is a variable */
00616             if (com_token[0] == '*') {
00617                 com_token++;
00618                 com_token = Cvar_GetString(com_token);
00619             }
00620             assert(!cmd_argv[cmd_argc]);
00621             cmd_argv[cmd_argc] = Mem_PoolStrDup(com_token, com_cmdSysPool, 0);
00622             cmd_argc++;
00623         }
00624     }
00625 }
00626 
00633 const char* Cmd_GetCommandDesc (const char* cmd_name)
00634 {
00635     cmd_function_t *cmd;
00636     char *sep = NULL;
00637     unsigned int hash;
00638     char searchName[MAX_VAR];
00639 
00640     /* remove parameters */
00641     Q_strncpyz(searchName, cmd_name, sizeof(searchName));
00642     sep = strstr(searchName, " ");
00643     if (sep)
00644         *sep = '\0';
00645 
00646     /* fail if the command already exists */
00647     hash = Com_HashKey(searchName, CMD_HASH_SIZE);
00648     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00649         if (!strcmp(searchName, cmd->name)) {
00650             if (cmd->description)
00651                 return cmd->description;
00652             else
00653                 return "";
00654         }
00655     }
00656     return "";
00657 }
00658 
00667 int Cmd_GenericCompleteFunction (size_t len, const char **match, int matches, const char **list)
00668 {
00669     static char matchString[MAX_QPATH];
00670     int lenResult = 0;
00671     int i;
00672 
00673     switch (matches) {
00674     /* exactly one match */
00675     case 1:
00676         *match = list[0];
00677         lenResult = strlen(list[0]);
00678         break;
00679     /* no matches */
00680     case 0:
00681         break;
00682     /* more than one match */
00683     default:
00684         /* get the shortest matching string of the results */
00685         lenResult = len;
00686         while (qtrue) {
00687             const char matchChar = list[0][lenResult];
00688             for (i = 1; i < matches; i++) {
00689                 if (matchChar != list[i][lenResult])
00690                     break;
00691             }
00692             if (i != matches)
00693                 break;
00694             else
00695                 lenResult++;
00696         }
00697         break;
00698     }
00699     /* len is >= 1 here */
00700     if (matches && len != lenResult) {
00701         if (lenResult >= MAX_QPATH)
00702             lenResult = MAX_QPATH - 1;
00703         Q_strncpyz(matchString, list[0], lenResult + 1);
00704         *match = matchString;
00705     }
00706     return matches;
00707 }
00708 
00715 void Cmd_AddParamCompleteFunction (const char *cmd_name, int (*function)(const char *partial, const char **match))
00716 {
00717     cmd_function_t *cmd;
00718     unsigned int hash;
00719 
00720     if (!cmd_name || !cmd_name[0])
00721         return;
00722 
00723     hash = Com_HashKey(cmd_name, CMD_HASH_SIZE);
00724     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00725         if (!strcmp(cmd_name, cmd->name)) {
00726             cmd->completeParam = function;
00727             return;
00728         }
00729     }
00730 }
00731 
00741 void* Cmd_GetUserdata (const char *cmd_name)
00742 {
00743     cmd_function_t *cmd;
00744     unsigned int hash;
00745 
00746     if (!cmd_name || !cmd_name[0]) {
00747         Com_Printf("Cmd_GetUserdata: Invalide parameter\n");
00748         return NULL;
00749     }
00750 
00751     hash = Com_HashKey(cmd_name, CMD_HASH_SIZE);
00752     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00753         if (!strcmp(cmd_name, cmd->name)) {
00754             return cmd->userdata;
00755         }
00756     }
00757 
00758     Com_Printf("Cmd_GetUserdata: '%s' not found\n", cmd_name);
00759     return NULL;
00760 }
00761 
00770 void Cmd_AddUserdata (const char *cmd_name, void* userdata)
00771 {
00772     cmd_function_t *cmd;
00773     unsigned int hash;
00774 
00775     if (!cmd_name || !cmd_name[0])
00776         return;
00777 
00778     hash = Com_HashKey(cmd_name, CMD_HASH_SIZE);
00779     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00780         if (!strcmp(cmd_name, cmd->name)) {
00781             cmd->userdata = userdata;
00782             return;
00783         }
00784     }
00785 }
00786 
00794 void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *desc)
00795 {
00796     cmd_function_t *cmd;
00797     unsigned int hash;
00798 
00799     if (!cmd_name || !cmd_name[0])
00800         return;
00801 
00802     /* fail if the command is a variable name */
00803     if (Cvar_GetString(cmd_name)[0]) {
00804         Com_Printf("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
00805         return;
00806     }
00807 
00808     /* fail if the command already exists */
00809     hash = Com_HashKey(cmd_name, CMD_HASH_SIZE);
00810     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00811         if (!strcmp(cmd_name, cmd->name)) {
00812             Com_DPrintf(DEBUG_COMMANDS, "Cmd_AddCommand: %s already defined\n", cmd_name);
00813             return;
00814         }
00815     }
00816 
00817     cmd = Mem_PoolAlloc(sizeof(*cmd), com_cmdSysPool, 0);
00818     cmd->name = cmd_name;
00819     cmd->description = desc;
00820     cmd->function = function;
00821     cmd->completeParam = NULL;
00822     HASH_Add(cmd_functions_hash, cmd, hash);
00823     cmd->next = cmd_functions;
00824     cmd_functions = cmd;
00825 }
00826 
00832 void Cmd_RemoveCommand (const char *cmd_name)
00833 {
00834     cmd_function_t *cmd, **back;
00835     unsigned int hash;
00836     hash = Com_HashKey(cmd_name, CMD_HASH_SIZE);
00837     back = &cmd_functions_hash[hash];
00838 
00839     while (1) {
00840         cmd = *back;
00841         if (!cmd) {
00842             Com_Printf("Cmd_RemoveCommand: %s not added\n", cmd_name);
00843             return;
00844         }
00845         if (!Q_strcasecmp(cmd_name, cmd->name)) {
00846             *back = cmd->hash_next;
00847             break;
00848         }
00849         back = &cmd->hash_next;
00850     }
00851 
00852     back = &cmd_functions;
00853     while (1) {
00854         cmd = *back;
00855         if (!cmd) {
00856             Com_Printf("Cmd_RemoveCommand: %s not added\n", cmd_name);
00857             return;
00858         }
00859         if (!strcmp(cmd_name, cmd->name)) {
00860             *back = cmd->next;
00861             Mem_Free(cmd);
00862             return;
00863         }
00864         back = &cmd->next;
00865     }
00866 }
00867 
00872 qboolean Cmd_Exists (const char *cmd_name)
00873 {
00874     cmd_function_t *cmd;
00875     unsigned int hash;
00876     hash = Com_HashKey(cmd_name, CMD_HASH_SIZE);
00877 
00878     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00879         if (!strcmp(cmd_name, cmd->name))
00880             return qtrue;
00881     }
00882 
00883     return qfalse;
00884 }
00885 
00894 int Cmd_CompleteCommandParameters (const char *command, const char *partial, const char **match)
00895 {
00896     const cmd_function_t *cmd;
00897     unsigned int hash;
00898 
00899     /* check for partial matches in commands */
00900     hash = Com_HashKey(command, CMD_HASH_SIZE);
00901     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00902         if (!Q_strcasecmp(command, cmd->name)) {
00903             if (!cmd->completeParam)
00904                 return 0;
00905             return cmd->completeParam(partial, match);
00906         }
00907     }
00908     return 0;
00909 }
00910 
00918 int Cmd_CompleteCommand (const char *partial, const char **match)
00919 {
00920     const cmd_function_t *cmd;
00921     const cmd_alias_t *a;
00922     const char *localMatch[MAX_COMPLETE];
00923     int len, matches = 0;
00924 
00925     len = strlen(partial);
00926 
00927     if (!len)
00928         return 0;
00929 
00930     /* check for partial matches in commands */
00931     for (cmd = cmd_functions; cmd; cmd = cmd->next) {
00932         if (!strncmp(partial, cmd->name, len)) {
00933             Com_Printf("[cmd] %s\n", cmd->name);
00934             if (cmd->description)
00935                 Com_Printf(COLORED_GREEN "      %s\n", cmd->description);
00936             localMatch[matches++] = cmd->name;
00937             if (matches >= MAX_COMPLETE)
00938                 break;
00939         }
00940     }
00941 
00942     /* and then aliases */
00943     if (matches < MAX_COMPLETE) {
00944         for (a = cmd_alias; a; a = a->next) {
00945             if (!strncmp(partial, a->name, len)) {
00946                 Com_Printf("[ali] %s\n", a->name);
00947                 localMatch[matches++] = a->name;
00948                 if (matches >= MAX_COMPLETE)
00949                     break;
00950             }
00951         }
00952     }
00953 
00954     return Cmd_GenericCompleteFunction(len, match, matches, localMatch);
00955 }
00956 
00957 
00962 void Cmd_ExecuteString (const char *text)
00963 {
00964     const cmd_function_t *cmd;
00965     const cmd_alias_t *a;
00966     const char *str;
00967     unsigned int hash;
00968 
00969     Com_DPrintf(DEBUG_COMMANDS, "ExecuteString: '%s'\n", text);
00970 
00971     Cmd_TokenizeString(text, qtrue);
00972 
00973     /* execute the command line */
00974     if (!Cmd_Argc())
00975         /* no tokens */
00976         return;
00977 
00978     str = Cmd_Argv(0);
00979 
00980     /* check functions */
00981     hash = Com_HashKey(str, CMD_HASH_SIZE);
00982     for (cmd = cmd_functions_hash[hash]; cmd; cmd = cmd->hash_next) {
00983         if (!Q_strcasecmp(str, cmd->name)) {
00984             if (!cmd->function) {   /* forward to server command */
00985                 Cmd_ExecuteString(va("cmd %s", text));
00986             } else {
00987                 cmd_userdata = cmd->userdata;
00988                 cmd->function();
00989             }
00990             return;
00991         }
00992     }
00993 
00994     /* check alias */
00995     hash = Com_HashKey(str, ALIAS_HASH_SIZE);
00996     for (a = cmd_alias_hash[hash]; a; a = a->hash_next) {
00997         if (!Q_strcasecmp(str, a->name)) {
00998             if (++alias_count == ALIAS_LOOP_COUNT) {
00999                 Com_Printf("ALIAS_LOOP_COUNT\n");
01000                 return;
01001             }
01002             Cbuf_InsertText(a->value);
01003             return;
01004         }
01005     }
01006 
01007     /* check cvars */
01008     if (Cvar_Command())
01009         return;
01010 
01011     /* send it as a server command if we are connected */
01012     Cmd_ForwardToServer();
01013 }
01014 
01018 static void Cmd_List_f (void)
01019 {
01020     const cmd_function_t *cmd;
01021     const cmd_alias_t *alias;
01022     int i = 0, j = 0, c, l = 0;
01023     const char *token = NULL;
01024 
01025     c = Cmd_Argc();
01026 
01027     if (c == 2) {
01028         token = Cmd_Argv(1);
01029         l = strlen(token);
01030     }
01031 
01032     for (cmd = cmd_functions; cmd; cmd = cmd->next, i++) {
01033         if (c == 2 && strncmp(cmd->name, token, l)) {
01034             i--;
01035             continue;
01036         }
01037         Com_Printf("[cmd] %s\n", cmd->name);
01038         if (cmd->description)
01039             Com_Printf(COLORED_GREEN "      %s\n", cmd->description);
01040     }
01041     /* check alias */
01042     for (alias = cmd_alias; alias; alias = alias->next, j++) {
01043         if (c == 2 && strncmp(alias->name, token, l)) {
01044             j--;
01045             continue;
01046         }
01047         Com_Printf("[ali] %s\n", alias->name);
01048     }
01049     Com_Printf("%i commands\n", i);
01050     Com_Printf("%i macros\n", j);
01051 }
01052 
01053 
01060 static int Cmd_CompleteExecCommand (const char *partial, const char **match)
01061 {
01062     const char *filename;
01063     size_t len;
01064 
01065     FS_BuildFileList("*.cfg");
01066 
01067     len = strlen(partial);
01068     if (!len) {
01069         while ((filename = FS_NextFileFromFileList("*.cfg")) != NULL) {
01070             Com_Printf("%s\n", filename);
01071         }
01072     }
01073 
01074     FS_NextFileFromFileList(NULL);
01075     return 0;
01076 }
01077 
01081 void Cmd_Dummy_f (void)
01082 {
01083 }
01084 
01085 #ifdef DEBUG
01086 
01091 static void Cmd_Test_f (void)
01092 {
01093     cmd_function_t *cmd;
01094 
01095     for (cmd = cmd_functions; cmd; cmd = cmd->next) {
01096         if (strcmp(cmd->name, "quit"))
01097             Cmd_ExecuteString(cmd->name);
01098     }
01099 }
01100 
01101 void Cmd_PrintDebugCommands (void)
01102 {
01103     const cmd_function_t *cmd;
01104     const char* otherCommands[] = {"mem_stats", "cl_configstrings", "cl_userinfo", "devmap"};
01105     int num = lengthof(otherCommands);
01106 
01107     Com_Printf("Debug commands:\n");
01108     for (cmd = cmd_functions; cmd; cmd = cmd->next) {
01109         if (!strncmp(cmd->name, "debug_", 6))
01110             Com_Printf(" * %s\n   %s\n", cmd->name, cmd->description);
01111     }
01112 
01113     Com_Printf("Other useful commands:\n");
01114     while (num) {
01115         const char *desc = Cmd_GetCommandDesc(otherCommands[num - 1]);
01116         Com_Printf(" * %s\n   %s\n", otherCommands[num - 1], desc);
01117         num--;
01118     }
01119     Com_Printf(" * sv debug_showall\n"
01120             "   make everything visible to everyone\n"
01121             " * sv debug_actorinvlist\n"
01122             "   Show the whole inv of all actors on the server console\n"
01123             );
01124     Com_Printf("\n");
01125 }
01126 #endif
01127 
01128 void Cmd_Init (void)
01129 {
01130     /* register our commands */
01131     Cmd_AddCommand("cmdlist", Cmd_List_f, "List all commands to game console");
01132     Cmd_AddCommand("exec", Cmd_Exec_f, "Execute a script file");
01133     Cmd_AddParamCompleteFunction("exec", Cmd_CompleteExecCommand);
01134     Cmd_AddCommand("echo", Cmd_Echo_f, "Print to game console");
01135     Cmd_AddCommand("wait", Cmd_Wait_f, NULL);
01136     Cmd_AddCommand("alias", Cmd_Alias_f, "Creates a new command that executes a command string");
01137     Cmd_AddCommand("aliasa", Cmd_Alias_f, "Creates a new, persistent command that executes a command string");
01138     Cmd_AddCommand("cmdclose", Cmd_Close_f, "Close the command buffer");
01139     Cmd_AddCommand("cmdopen", Cmd_Open_f, "Open the command buffer again");
01140 #ifdef DEBUG
01141     Cmd_AddCommand("debug_cmdtest", Cmd_Test_f, "Calls every command in the current list");
01142 #endif
01143 }
01144 
01145 void Cmd_Shutdown (void)
01146 {
01147     memset(cmd_functions_hash, 0, sizeof(cmd_functions_hash));
01148     memset(cmd_functions, 0, sizeof(cmd_functions));
01149     cmd_argc = 0;
01150 }

Generated by  doxygen 1.6.2