📄 command.c
字号:
// Emacs style mode select -*- C++ -*- //-----------------------------------------------------------------------------//// $Id: command.c,v 1.11 2001/02/24 13:35:19 bpereira Exp $//// Copyright (C) 1998-2000 by DooM Legacy Team.//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License// as published by the Free Software Foundation; either version 2// of the License, or (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.////// $Log: command.c,v $// Revision 1.11 2001/02/24 13:35:19 bpereira// no message//// Revision 1.10 2001/01/25 22:15:41 bpereira// added heretic support//// Revision 1.9 2000/11/11 13:59:45 bpereira// no message//// Revision 1.8 2000/11/02 19:49:35 bpereira// no message//// Revision 1.7 2000/10/08 13:29:59 bpereira// no message//// Revision 1.6 2000/09/28 20:57:14 bpereira// no message//// Revision 1.5 2000/08/31 14:30:54 bpereira// no message//// Revision 1.4 2000/08/03 17:57:41 bpereira// no message//// Revision 1.3 2000/02/27 00:42:10 hurdler// fix CR+LF problem//// Revision 1.2 2000/02/26 00:28:42 hurdler// Mostly bug fix (see borislog.txt 23-2-2000, 24-2-2000)////// DESCRIPTION:// parse and execute commands from console input/scripts/// and remote server.//// handles console variables, which is a simplified version// of commands, each consvar can have a function called when// it is modified.. thus it acts nearly as commands.//// code shamelessly inspired by the QuakeC sources, thanks Id :)////-----------------------------------------------------------------------------#include "doomdef.h"#include "doomstat.h"#include "command.h"#include "console.h"#include "z_zone.h"#include "d_clisrv.h"#include "d_netcmd.h"#include "m_misc.h"#include "m_fixed.h"#include "byteptr.h"#include "p_saveg.h"//========// protos.//========static boolean COM_Exists (char *com_name);static void COM_ExecuteString (char *text);static void COM_Alias_f (void);static void COM_Echo_f (void);static void COM_Exec_f (void);static void COM_Wait_f (void);static void COM_Help_f (void);static void COM_Toggle_f (void);static boolean CV_Command (void);static consvar_t *CV_FindVar (char *name);static char *CV_StringValue (char *var_name);static consvar_t *consvar_vars; // list of registered console variablesstatic char com_token[1024];static char *COM_Parse (char *data);CV_PossibleValue_t CV_OnOff[] = {{0,"Off"}, {1,"On"}, {0,NULL}};CV_PossibleValue_t CV_YesNo[] = {{0,"No"} , {1,"Yes"}, {0,NULL}};CV_PossibleValue_t CV_Unsigned[]= {{0,"MIN"}, {999999999,"MAX"}, {0,NULL}};#define COM_BUF_SIZE 8192 // command buffer sizeint com_wait; // one command per frame (for cmd sequences)// command aliases//typedef struct cmdalias_s{ struct cmdalias_s *next; char *name; char *value; // the command string to replace the alias} cmdalias_t;cmdalias_t *com_alias; // aliases list// =========================================================================// COMMAND BUFFER// =========================================================================vsbuf_t com_text; // variable sized buffer// Add text in the command buffer (for later execution)//void COM_BufAddText (char *text){ int l; l = strlen (text); if (com_text.cursize + l >= com_text.maxsize) { CONS_Printf ("Command buffer full!\n"); return; } VS_Write (&com_text, text, l);}// Adds command text immediately after the current command// Adds a \n to the text//void COM_BufInsertText (char *text){ char *temp; int templen; // copy off any commands still remaining in the exec buffer templen = com_text.cursize; if (templen) { temp = ZZ_Alloc (templen); memcpy (temp, com_text.data, templen); VS_Clear (&com_text); } else temp = NULL; // shut up compiler // add the entire text of the file (or alias) COM_BufAddText (text); // add the copied off data if (templen) { VS_Write (&com_text, temp, templen); Z_Free (temp); }}// Flush (execute) console commands in buffer// does only one if com_wait//void COM_BufExecute (void){ int i; char *text; char line[1024]; int quotes; if (com_wait) { com_wait--; return; } while (com_text.cursize) { // find a '\n' or ; line break text = (char *)com_text.data; quotes = 0; for (i=0 ; i< com_text.cursize ; i++) { if (text[i] == '"') quotes++; if ( !(quotes&1) && text[i] == ';') break; // don't break if inside a quoted string if (text[i] == '\n' || text[i] == '\r') break; } memcpy (line, text, i); line[i] = 0; // flush the command text from the command buffer, _BEFORE_ // executing, to avoid that 'recursive' aliases overflow the // command text buffer, in that case, new commands are inserted // at the beginning, in place of the actual, so it doesn't // overflow if (i == com_text.cursize) // the last command was just flushed com_text.cursize = 0; else { i++; com_text.cursize -= i; memcpy (text, text+i, com_text.cursize); } // execute the command line COM_ExecuteString (line); // delay following commands if a wait was encountered if (com_wait) { com_wait--; break; } }}// =========================================================================// COMMAND EXECUTION// =========================================================================typedef struct xcommand_s{ char *name; struct xcommand_s *next; com_func_t function;} xcommand_t;static xcommand_t *com_commands = NULL; // current commands#define MAX_ARGS 80static int com_argc;static char *com_argv[MAX_ARGS];static char *com_null_string = "";static char *com_args = NULL; // current command args or NULLvoid Got_NetVar(char **p,int playernum);// Initialise command buffer and add basic commands//void COM_Init (void){ // allocate command buffer VS_Alloc (&com_text, COM_BUF_SIZE); // add standard commands COM_AddCommand ("alias",COM_Alias_f); COM_AddCommand ("echo", COM_Echo_f); COM_AddCommand ("exec", COM_Exec_f); COM_AddCommand ("wait", COM_Wait_f); COM_AddCommand ("help", COM_Help_f); COM_AddCommand ("toggle", COM_Toggle_f); RegisterNetXCmd(XD_NETVAR,Got_NetVar);}// Returns how many args for last command//int COM_Argc (void){ return com_argc;}// Returns string pointer for given argument number//char *COM_Argv (int arg){ if ( arg >= com_argc || arg < 0 ) return com_null_string; return com_argv[arg];}// Returns string pointer of all command args//char *COM_Args (void){ return com_args;}int COM_CheckParm (char *check){ int i; for (i = 1;i<com_argc;i++) { if ( !strcasecmp(check, com_argv[i]) ) return i; } return 0;}// Parses the given string into command line tokens.//// Takes a null terminated string. Does not need to be /n terminated.// breaks the string up into arg tokens.static void COM_TokenizeString (char *text){ int i;// clear the args from the last string for (i=0 ; i<com_argc ; i++) Z_Free (com_argv[i]); com_argc = 0; com_args = NULL; while (1) {// skip whitespace up to a /n while (*text && *text <= ' ' && *text != '\n') text++; if (*text == '\n') { // a newline means end of command in buffer, // thus end of this command's args too text++; break; } if (!*text) return; if (com_argc == 1) com_args = text; text = COM_Parse (text); if (!text) return; if (com_argc < MAX_ARGS) { com_argv[com_argc] = ZZ_Alloc (strlen(com_token)+1); strcpy (com_argv[com_argc], com_token); com_argc++; } }}// Add a command before existing ones.//void COM_AddCommand (char *name, com_func_t func){ xcommand_t *cmd; // fail if the command is a variable name if (CV_StringValue(name)[0]) { CONS_Printf ("%s is a variable name\n", name); return; } // fail if the command already exists for (cmd=com_commands ; cmd ; cmd=cmd->next) { if (!strcmp (name, cmd->name)) { CONS_Printf ("Command %s already exists\n", name); return; } } cmd = ZZ_Alloc (sizeof(xcommand_t)); cmd->name = name; cmd->function = func; cmd->next = com_commands; com_commands = cmd;}// Returns true if a command by the name given exists//static boolean COM_Exists (char *com_name){ xcommand_t *cmd; for (cmd=com_commands ; cmd ; cmd=cmd->next) { if (!strcmp (com_name,cmd->name)) return true; } return false;}// Command completion using TAB key like '4dos'// Will skip 'skips' commands//char *COM_CompleteCommand (char *partial, int skips){ xcommand_t *cmd; int len; len = strlen(partial); if (!len) return NULL;// check functions for (cmd=com_commands ; cmd ; cmd=cmd->next) if (!strncmp (partial,cmd->name, len)) if (!skips--) return cmd->name; return NULL;}// Parses a single line of text into arguments and tries to execute it.// The text can come from the command buffer, a remote client, or stdin.//static void COM_ExecuteString (char *text){ xcommand_t *cmd; cmdalias_t *a; COM_TokenizeString (text);// execute the command line if (!COM_Argc()) return; // no tokens// check functions for (cmd=com_commands ; cmd ; cmd=cmd->next) { if (!strcmp (com_argv[0],cmd->name)) { cmd->function (); return; } }// check aliases for (a=com_alias ; a ; a=a->next) { if (!strcmp (com_argv[0], a->name)) { COM_BufInsertText (a->value); return; } }// check cvars if (!CV_Command ()) CONS_Printf ("Unknown command '%s'\n", COM_Argv(0));}// =========================================================================// SCRIPT COMMANDS// =========================================================================// alias command : a command name that replaces another command//static void COM_Alias_f (void){ cmdalias_t *a; char cmd[1024]; int i, c; if (COM_Argc()<3) { CONS_Printf("alias <name> <command>\n"); return; } a = ZZ_Alloc (sizeof(cmdalias_t)); a->next = com_alias; com_alias = a; a->name = Z_StrDup (COM_Argv(1));// copy the rest of the command line cmd[0] = 0; // start out with a null string c = COM_Argc(); for (i=2 ; i< c ; i++) { strcat (cmd, COM_Argv(i)); if (i != c) strcat (cmd, " "); } strcat (cmd, "\n"); a->value = Z_StrDup (cmd);}// Echo a line of text to console//static void COM_Echo_f (void){ int i; for (i=1 ; i<COM_Argc() ; i++) CONS_Printf ("%s ",COM_Argv(i)); CONS_Printf ("\n");}// Execute a script file//static void COM_Exec_f (void){ int length; byte* buf=NULL; if (COM_Argc () != 2) { CONS_Printf ("exec <filename> : run a script file\n"); return; }// load file length = FIL_ReadFile (COM_Argv(1), &buf); //CONS_Printf ("debug file length : %d\n",length); if (!buf) { CONS_Printf ("couldn't execute file %s\n",COM_Argv(1)); return; } CONS_Printf ("executing %s\n",COM_Argv(1));// insert text file into the command buffer COM_BufInsertText (buf);// free buffer Z_Free(buf);}// Delay execution of the rest of the commands to the next frame,// allows sequences of commands like "jump; fire; backward"//static void COM_Wait_f (void){ if (COM_Argc()>1) com_wait = atoi(COM_Argv(1)); else com_wait = 1; // 1 frame}static void COM_Help_f (void){ xcommand_t *cmd; consvar_t *cvar; int i=0; if(COM_Argc()>1) { cvar = CV_FindVar (COM_Argv(1)); if( cvar ) { CONS_Printf("Variable %s:\n",cvar->name); CONS_Printf(" flags :"); if( cvar->flags & CV_SAVE ) CONS_Printf("AUTOSAVE "); if( cvar->flags & CV_FLOAT ) CONS_Printf("FLOAT "); if( cvar->flags & CV_NETVAR ) CONS_Printf("NETVAR "); if( cvar->flags & CV_CALL ) CONS_Printf("ACTION "); CONS_Printf("\n"); if( cvar->PossibleValue ) { if(stricmp(cvar->PossibleValue[0].strvalue,"MIN")==0) { for(i=1;cvar->PossibleValue[i].strvalue!=NULL;i++) if(!stricmp(cvar->PossibleValue[i].strvalue,"MAX")) break; CONS_Printf(" range from %d to %d\n",cvar->PossibleValue[0].value,cvar->PossibleValue[i].value); } else { CONS_Printf(" possible value :\n",cvar->name); while(cvar->PossibleValue[i].strvalue) { CONS_Printf(" %-2d : %s\n",cvar->PossibleValue[i].value,cvar->PossibleValue[i].strvalue); i++; } } } } else CONS_Printf("No Help for this command/variable\n"); } else { // commands
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -