2010-02-15 23:26:55 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
Copyright ( C ) 2007 - 2008 Kristian Duske
2014-09-22 08:55:46 +00:00
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
2010-02-15 23:26:55 +00:00
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 .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// cmd.c -- Quake script command processing module
# include "quakedef.h"
2017-09-17 02:12:53 +00:00
cvar_t cl_nopext = { " cl_nopext " , " 0 " , CVAR_NONE } ; //Spike -- prevent autodetection of protocol extensions, so that servers fall back to only their base protocol (without needing to reconfigure the server. Requires reconnect.
cvar_t cmd_warncmd = { " cl_warncmd " , " 1 " , CVAR_NONE } ; //Spike -- prevent autodetection of protocol extensions, so that servers fall back to only their base protocol (without needing to reconfigure the server. Requires reconnect.
2010-02-15 23:26:55 +00:00
void Cmd_ForwardToServer ( void ) ;
# define MAX_ALIAS_NAME 32
# define CMDLINE_LENGTH 256 //johnfitz -- mirrored in common.c
typedef struct cmdalias_s
{
struct cmdalias_s * next ;
char name [ MAX_ALIAS_NAME ] ;
char * value ;
} cmdalias_t ;
cmdalias_t * cmd_alias ;
qboolean cmd_wait ;
//=============================================================================
/*
= = = = = = = = = = = =
Cmd_Wait_f
Causes execution of the remainder of the command buffer to be delayed until
next frame . This allows commands like :
bind g " impulse 5 ; +attack ; wait ; -attack ; impulse 2 "
= = = = = = = = = = = =
*/
void Cmd_Wait_f ( void )
{
cmd_wait = true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
COMMAND BUFFER
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
sizebuf_t cmd_text ;
/*
= = = = = = = = = = = =
Cbuf_Init
= = = = = = = = = = = =
*/
void Cbuf_Init ( void )
{
2017-04-21 20:43:05 +00:00
SZ_Alloc ( & cmd_text , 1 < < 18 ) ; // space for commands and script files. spike -- was 8192, but modern configs can be _HUGE_, at least if they contain lots of comments/docs for things.
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = =
Cbuf_AddText
Adds command text at the end of the buffer
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
void Cbuf_AddText ( const char * text )
2010-02-15 23:26:55 +00:00
{
int l ;
l = Q_strlen ( text ) ;
if ( cmd_text . cursize + l > = cmd_text . maxsize )
{
Con_Printf ( " Cbuf_AddText: overflow \n " ) ;
return ;
}
2017-09-17 02:12:53 +00:00
SZ_Write ( & cmd_text , text , l ) ;
}
void Cbuf_AddTextLen ( const char * text , int l )
{
if ( cmd_text . cursize + l > = cmd_text . maxsize )
{
Con_Printf ( " Cbuf_AddText: overflow \n " ) ;
return ;
}
SZ_Write ( & cmd_text , text , l ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = =
Cbuf_InsertText
Adds command text immediately after the current command
Adds a \ n to the text
FIXME : actually change the command buffer to do less copying
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
void Cbuf_InsertText ( const char * text )
2010-02-15 23:26:55 +00:00
{
char * temp ;
int templen ;
// copy off any commands still remaining in the exec buffer
templen = cmd_text . cursize ;
if ( templen )
{
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
temp = ( char * ) Z_Malloc ( templen ) ;
2010-02-15 23:26:55 +00:00
Q_memcpy ( temp , cmd_text . data , templen ) ;
SZ_Clear ( & cmd_text ) ;
}
else
temp = NULL ; // shut up compiler
// add the entire text of the file
Cbuf_AddText ( text ) ;
2012-03-03 21:55:53 +00:00
SZ_Write ( & cmd_text , " \n " , 1 ) ;
2010-02-15 23:26:55 +00:00
// add the copied off data
if ( templen )
{
SZ_Write ( & cmd_text , temp , templen ) ;
Z_Free ( temp ) ;
}
}
2018-05-13 07:00:41 +00:00
//Spike: for renderer/server isolation
void Cbuf_Waited ( void )
{
cmd_wait = false ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = =
Cbuf_Execute
2018-05-13 07:00:41 +00:00
Spike : reworked ' wait ' for renderer / server rate independance
2010-02-15 23:26:55 +00:00
= = = = = = = = = = = =
*/
void Cbuf_Execute ( void )
{
int i ;
char * text ;
char line [ 1024 ] ;
2017-09-17 02:12:53 +00:00
int quotes , comment ;
2010-02-15 23:26:55 +00:00
2018-05-13 07:00:41 +00:00
while ( cmd_text . cursize & & ! cmd_wait )
2010-02-15 23:26:55 +00:00
{
// find a \n or ; line break
text = ( char * ) cmd_text . data ;
quotes = 0 ;
2017-09-17 02:12:53 +00:00
comment = 0 ;
2010-02-15 23:26:55 +00:00
for ( i = 0 ; i < cmd_text . cursize ; i + + )
{
if ( text [ i ] = = ' " ' )
quotes + + ;
2017-09-17 02:12:53 +00:00
if ( text [ i ] = = ' / ' & & text [ i + 1 ] = = ' / ' )
comment = true ;
if ( ! ( quotes & 1 ) & & ! comment & & text [ i ] = = ' ; ' )
2010-02-15 23:26:55 +00:00
break ; // don't break if inside a quoted string
if ( text [ i ] = = ' \n ' )
break ;
}
2015-08-23 09:56:31 +00:00
if ( i > ( int ) sizeof ( line ) - 1 )
{
memcpy ( line , text , sizeof ( line ) - 1 ) ;
line [ sizeof ( line ) - 1 ] = 0 ;
}
else
{
memcpy ( line , text , i ) ;
line [ i ] = 0 ;
}
2010-02-15 23:26:55 +00:00
// delete the text from the command buffer and move remaining commands down
// this is necessary because commands (exec, alias) can insert data at the
// beginning of the text buffer
if ( i = = cmd_text . cursize )
cmd_text . cursize = 0 ;
else
{
i + + ;
cmd_text . cursize - = i ;
2010-02-19 23:55:17 +00:00
memmove ( text , text + i , cmd_text . cursize ) ;
2010-02-15 23:26:55 +00:00
}
// execute the command line
Cmd_ExecuteString ( line , src_command ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
SCRIPT COMMANDS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = =
Cmd_StuffCmds_f - - johnfitz - - rewritten to read the " cmdline " cvar , for use with dynamic mod loading
Adds command line parameters as script statements
Commands lead with a + , and continue until a - or another +
quake + prog jctest . qp + cmd amlev1
quake - nosound + cmd amlev1
= = = = = = = = = = = = = = =
*/
void Cmd_StuffCmds_f ( void )
{
extern cvar_t cmdline ;
char cmds [ CMDLINE_LENGTH ] ;
int i , j , plus ;
2010-02-16 10:01:46 +00:00
plus = false ; // On Unix, argv[0] is command name
for ( i = 0 , j = 0 ; cmdline . string [ i ] ; i + + )
2010-02-15 23:26:55 +00:00
{
if ( cmdline . string [ i ] = = ' + ' )
{
plus = true ;
if ( j > 0 )
{
cmds [ j - 1 ] = ' ; ' ;
cmds [ j + + ] = ' ' ;
}
}
else if ( cmdline . string [ i ] = = ' - ' & &
( i = = 0 | | cmdline . string [ i - 1 ] = = ' ' ) ) //johnfitz -- allow hypenated map names with +map
plus = false ;
else if ( plus )
cmds [ j + + ] = cmdline . string [ i ] ;
}
cmds [ j ] = 0 ;
Cbuf_InsertText ( cmds ) ;
}
2021-08-29 11:55:24 +00:00
/* id1/pak0.pak from 2021 re-release doesn't have a default.cfg
* embedding Quakespasm ' s customized default . cfg for that . . . */
# include "default_cfg.h"
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = =
Cmd_Exec_f
= = = = = = = = = = = = = = =
*/
void Cmd_Exec_f ( void )
{
char * f ;
int mark ;
if ( Cmd_Argc ( ) ! = 2 )
{
Con_Printf ( " exec <filename> : execute a script file \n " ) ;
return ;
}
mark = Hunk_LowMark ( ) ;
2011-01-02 21:45:16 +00:00
f = ( char * ) COM_LoadHunkFile ( Cmd_Argv ( 1 ) , NULL ) ;
2021-08-29 11:55:24 +00:00
if ( ! f & & ! strcmp ( Cmd_Argv ( 1 ) , " default.cfg " ) ) {
f = default_cfg ; /* see above.. */
}
2010-02-15 23:26:55 +00:00
if ( ! f )
{
2017-09-17 02:12:53 +00:00
if ( cmd_warncmd . value )
Con_Printf ( " couldn't exec %s \n " , Cmd_Argv ( 1 ) ) ;
2010-02-15 23:26:55 +00:00
return ;
}
2017-09-17 02:12:53 +00:00
if ( cmd_warncmd . value )
Con_Printf ( " execing %s \n " , Cmd_Argv ( 1 ) ) ;
2010-02-15 23:26:55 +00:00
2020-10-17 02:33:41 +00:00
Cbuf_InsertText ( " \n " ) ; //just in case there was no trailing \n.
2010-02-15 23:26:55 +00:00
Cbuf_InsertText ( f ) ;
2022-07-03 12:55:40 +00:00
if ( f ! = default_cfg ) {
Hunk_FreeToLowMark ( mark ) ;
}
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = = = = =
Cmd_Echo_f
Just prints the rest of the line to the console
= = = = = = = = = = = = = = =
*/
void Cmd_Echo_f ( void )
{
int i ;
for ( i = 1 ; i < Cmd_Argc ( ) ; i + + )
Con_Printf ( " %s " , Cmd_Argv ( i ) ) ;
Con_Printf ( " \n " ) ;
}
/*
= = = = = = = = = = = = = = =
Cmd_Alias_f - - johnfitz - - rewritten
Creates a new command that executes a command string ( possibly ; seperated )
= = = = = = = = = = = = = = =
*/
void Cmd_Alias_f ( void )
{
cmdalias_t * a ;
char cmd [ 1024 ] ;
int i , c ;
2010-08-29 02:22:55 +00:00
const char * s ;
2010-02-15 23:26:55 +00:00
switch ( Cmd_Argc ( ) )
{
case 1 : //list all aliases
for ( a = cmd_alias , i = 0 ; a ; a = a - > next , i + + )
Con_SafePrintf ( " %s: %s " , a - > name , a - > value ) ;
if ( i )
Con_SafePrintf ( " %i alias command(s) \n " , i ) ;
else
Con_SafePrintf ( " no alias commands found \n " ) ;
break ;
case 2 : //output current alias string
for ( a = cmd_alias ; a ; a = a - > next )
if ( ! strcmp ( Cmd_Argv ( 1 ) , a - > name ) )
Con_Printf ( " %s: %s " , a - > name , a - > value ) ;
break ;
default : //set alias string
s = Cmd_Argv ( 1 ) ;
if ( strlen ( s ) > = MAX_ALIAS_NAME )
{
Con_Printf ( " Alias name is too long \n " ) ;
return ;
}
2016-08-26 20:44:29 +00:00
// if the alias already exists, reuse it
2010-02-15 23:26:55 +00:00
for ( a = cmd_alias ; a ; a = a - > next )
{
if ( ! strcmp ( s , a - > name ) )
{
Z_Free ( a - > value ) ;
break ;
}
}
if ( ! a )
{
host_cmd.c, console.c, gl_draw.c, image.c, gl_model.c, r_sprite.c, cl_parse.c,
gl_warp.c, host.c, gl_mesh.c, gl_sky.c, gl_texmgr.c, cvar.c, sv_main.c, cvar.h,
gl_screen.c, r_brush.c, gl_vidsdl.c, zone.c, cl_main.c, cmd.c, snd_dma.c,
snd_mem.c, common.c, sv_phys.c: Added explicit casts to eliminate -Wc++-compat
warnings.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@170 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-05-31 07:42:36 +00:00
a = ( cmdalias_t * ) Z_Malloc ( sizeof ( cmdalias_t ) ) ;
2010-02-15 23:26:55 +00:00
a - > next = cmd_alias ;
cmd_alias = a ;
}
strcpy ( a - > name , s ) ;
// copy the rest of the command line
cmd [ 0 ] = 0 ; // start out with a null string
c = Cmd_Argc ( ) ;
2011-12-13 18:40:23 +00:00
for ( i = 2 ; i < c ; i + + )
2010-02-15 23:26:55 +00:00
{
2011-12-27 13:15:31 +00:00
q_strlcat ( cmd , Cmd_Argv ( i ) , sizeof ( cmd ) ) ;
2011-12-13 18:40:23 +00:00
if ( i ! = c - 1 )
2011-12-27 13:15:31 +00:00
q_strlcat ( cmd , " " , sizeof ( cmd ) ) ;
}
if ( q_strlcat ( cmd , " \n " , sizeof ( cmd ) ) > = sizeof ( cmd ) )
{
Con_Printf ( " alias value too long! \n " ) ;
cmd [ 0 ] = ' \n ' ; // nullify the string
cmd [ 1 ] = 0 ;
2010-02-15 23:26:55 +00:00
}
2010-10-04 07:40:12 +00:00
a - > value = Z_Strdup ( cmd ) ;
2010-02-15 23:26:55 +00:00
break ;
}
}
/*
= = = = = = = = = = = = = = =
Cmd_Unalias_f - - johnfitz
= = = = = = = = = = = = = = =
*/
void Cmd_Unalias_f ( void )
{
cmdalias_t * a , * prev ;
switch ( Cmd_Argc ( ) )
{
default :
case 1 :
Con_Printf ( " unalias <name> : delete alias \n " ) ;
break ;
case 2 :
2010-10-24 14:15:27 +00:00
prev = NULL ;
for ( a = cmd_alias ; a ; a = a - > next )
2010-02-15 23:26:55 +00:00
{
if ( ! strcmp ( Cmd_Argv ( 1 ) , a - > name ) )
{
2010-10-24 14:15:27 +00:00
if ( prev )
prev - > next = a - > next ;
else
cmd_alias = a - > next ;
2010-02-15 23:26:55 +00:00
Z_Free ( a - > value ) ;
Z_Free ( a ) ;
return ;
}
prev = a ;
}
2010-10-24 14:15:27 +00:00
Con_Printf ( " No alias named %s \n " , Cmd_Argv ( 1 ) ) ;
2010-02-15 23:26:55 +00:00
break ;
}
}
2017-09-17 02:12:53 +00:00
qboolean Cmd_AliasExists ( const char * aliasname )
{
cmdalias_t * a ;
for ( a = cmd_alias ; a ; a = a - > next )
{
if ( ! q_strcasecmp ( aliasname , a - > name ) )
return true ;
}
return false ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = =
Cmd_Unaliasall_f - - johnfitz
= = = = = = = = = = = = = = =
*/
void Cmd_Unaliasall_f ( void )
{
cmdalias_t * blah ;
while ( cmd_alias )
{
blah = cmd_alias - > next ;
Z_Free ( cmd_alias - > value ) ;
Z_Free ( cmd_alias ) ;
cmd_alias = blah ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
COMMAND EXECUTION
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# define MAX_ARGS 80
static int cmd_argc ;
static char * cmd_argv [ MAX_ARGS ] ;
2010-08-29 02:22:55 +00:00
static char cmd_null_string [ ] = " " ;
static const char * cmd_args = NULL ;
2010-02-15 23:26:55 +00:00
cmd_source_t cmd_source ;
//johnfitz -- better tab completion
//static cmd_function_t *cmd_functions; // possible commands to execute
cmd_function_t * cmd_functions ; // possible commands to execute
//johnfitz
/*
= = = = = = = = = = = =
Cmd_List_f - - johnfitz
= = = = = = = = = = = =
*/
void Cmd_List_f ( void )
{
cmd_function_t * cmd ;
2010-08-29 02:22:55 +00:00
const char * partial ;
int len , count ;
2010-02-15 23:26:55 +00:00
if ( Cmd_Argc ( ) > 1 )
{
partial = Cmd_Argv ( 1 ) ;
len = Q_strlen ( partial ) ;
}
else
{
partial = NULL ;
len = 0 ;
}
count = 0 ;
for ( cmd = cmd_functions ; cmd ; cmd = cmd - > next )
{
if ( partial & & Q_strncmp ( partial , cmd - > name , len ) )
{
continue ;
}
Con_SafePrintf ( " %s \n " , cmd - > name ) ;
count + + ;
}
Con_SafePrintf ( " %i commands " , count ) ;
if ( partial )
{
Con_SafePrintf ( " beginning with \" %s \" " , partial ) ;
}
Con_SafePrintf ( " \n " ) ;
}
2017-04-02 18:18:57 +00:00
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 <substring> : search through commands and cvars for the given substring \n " , Cmd_Argv ( 0 ) ) ;
return ;
}
for ( cmd = cmd_functions ; cmd ; cmd = cmd - > next )
{
2017-09-17 02:12:53 +00:00
if ( q_strcasestr ( cmd - > name , substr ) & & cmd - > srctype ! = src_server )
2017-04-02 18:18:57 +00:00
{
hits + + ;
Con_SafePrintf ( " %s \n " , Cmd_TintSubstring ( cmd - > name , substr , tmpbuf , sizeof ( tmpbuf ) ) ) ;
}
}
2017-09-17 02:12:53 +00:00
2017-04-02 18:18:57 +00:00
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 " ) ;
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = =
Cmd_Init
= = = = = = = = = = = =
*/
void Cmd_Init ( void )
{
Cmd_AddCommand ( " cmdlist " , Cmd_List_f ) ; //johnfitz
Cmd_AddCommand ( " unalias " , Cmd_Unalias_f ) ; //johnfitz
Cmd_AddCommand ( " unaliasall " , Cmd_Unaliasall_f ) ; //johnfitz
Cmd_AddCommand ( " stuffcmds " , Cmd_StuffCmds_f ) ;
Cmd_AddCommand ( " exec " , Cmd_Exec_f ) ;
Cmd_AddCommand ( " echo " , Cmd_Echo_f ) ;
Cmd_AddCommand ( " alias " , Cmd_Alias_f ) ;
Cmd_AddCommand ( " cmd " , Cmd_ForwardToServer ) ;
Cmd_AddCommand ( " wait " , Cmd_Wait_f ) ;
2017-04-02 18:18:57 +00:00
Cmd_AddCommand ( " apropos " , Cmd_Apropos_f ) ;
2017-07-19 05:40:54 +00:00
Cmd_AddCommand ( " find " , Cmd_Apropos_f ) ;
2017-09-17 02:12:53 +00:00
2018-05-01 00:35:14 +00:00
Cvar_RegisterVariable ( & cl_nopext ) ;
2017-09-17 02:12:53 +00:00
Cvar_RegisterVariable ( & cmd_warncmd ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = =
Cmd_Argc
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
int Cmd_Argc ( void )
2010-02-15 23:26:55 +00:00
{
return cmd_argc ;
}
/*
= = = = = = = = = = = =
Cmd_Argv
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
const char * Cmd_Argv ( int arg )
2010-02-15 23:26:55 +00:00
{
2012-03-31 18:30:09 +00:00
if ( arg < 0 | | arg > = cmd_argc )
2010-02-15 23:26:55 +00:00
return cmd_null_string ;
return cmd_argv [ arg ] ;
}
/*
= = = = = = = = = = = =
Cmd_Args
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
const char * Cmd_Args ( void )
2010-02-15 23:26:55 +00:00
{
2020-01-12 07:46:26 +00:00
if ( ! cmd_args )
return " " ;
2010-02-15 23:26:55 +00:00
return cmd_args ;
}
/*
= = = = = = = = = = = =
Cmd_TokenizeString
Parses the given string into command line tokens .
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
void Cmd_TokenizeString ( const char * text )
2010-02-15 23:26:55 +00:00
{
int i ;
// clear the args from the last string
for ( i = 0 ; i < cmd_argc ; i + + )
Z_Free ( cmd_argv [ i ] ) ;
cmd_argc = 0 ;
cmd_args = NULL ;
while ( 1 )
{
// skip whitespace up to a /n
while ( * text & & * text < = ' ' & & * text ! = ' \n ' )
{
text + + ;
}
if ( * text = = ' \n ' )
{ // a newline seperates commands in the buffer
text + + ;
break ;
}
if ( ! * text )
return ;
if ( cmd_argc = = 1 )
cmd_args = text ;
text = COM_Parse ( text ) ;
if ( ! text )
return ;
if ( cmd_argc < MAX_ARGS )
{
2011-12-13 18:35:40 +00:00
cmd_argv [ cmd_argc ] = Z_Strdup ( com_token ) ;
2010-02-15 23:26:55 +00:00
cmd_argc + + ;
}
}
}
/*
= = = = = = = = = = = =
Cmd_AddCommand
2017-09-17 02:12:53 +00:00
spike - - added an extra arg for client ( also renamed and made a macro )
2010-02-15 23:26:55 +00:00
= = = = = = = = = = = =
*/
2021-08-31 02:36:55 +00:00
cmd_function_t * Cmd_AddCommand2 ( const char * cmd_name , xcommand_t function , cmd_source_t srctype , qboolean qcinterceptable )
2010-02-15 23:26:55 +00:00
{
cmd_function_t * cmd ;
cmd_function_t * cursor , * prev ; //johnfitz -- sorted list insert
// fail if the command is a variable name
if ( Cvar_VariableString ( cmd_name ) [ 0 ] )
{
Con_Printf ( " Cmd_AddCommand: %s already defined as a var \n " , cmd_name ) ;
2020-07-02 19:05:51 +00:00
return NULL ;
2010-02-15 23:26:55 +00:00
}
// fail if the command already exists
for ( cmd = cmd_functions ; cmd ; cmd = cmd - > next )
{
2017-09-17 02:12:53 +00:00
if ( ! Q_strcmp ( cmd_name , cmd - > name ) & & cmd - > srctype = = srctype )
2010-02-15 23:26:55 +00:00
{
2018-05-01 00:35:14 +00:00
if ( cmd - > function ! = function & & function )
Con_Printf ( " Cmd_AddCommand: %s already defined \n " , cmd_name ) ;
2020-07-02 19:05:51 +00:00
return NULL ;
2010-02-15 23:26:55 +00:00
}
}
2018-05-01 00:35:14 +00:00
if ( host_initialized )
2020-07-02 19:05:51 +00:00
{
cmd = ( cmd_function_t * ) malloc ( sizeof ( * cmd ) + strlen ( cmd_name ) + 1 ) ;
cmd - > name = strcpy ( ( char * ) ( cmd + 1 ) , cmd_name ) ;
cmd - > dynamic = true ;
}
2018-05-01 00:35:14 +00:00
else
2020-07-02 19:05:51 +00:00
{
cmd = ( cmd_function_t * ) Hunk_Alloc ( sizeof ( * cmd ) ) ;
cmd - > name = cmd_name ;
cmd - > dynamic = false ;
}
2010-02-15 23:26:55 +00:00
cmd - > function = function ;
2017-09-17 02:12:53 +00:00
cmd - > srctype = srctype ;
2021-08-31 02:36:55 +00:00
cmd - > qcinterceptable = qcinterceptable ;
2010-02-15 23:26:55 +00:00
//johnfitz -- insert each entry in alphabetical order
2010-08-29 02:22:55 +00:00
if ( cmd_functions = = NULL | | strcmp ( cmd - > name , cmd_functions - > name ) < 0 ) //insert at front
2010-02-15 23:26:55 +00:00
{
2010-08-29 02:22:55 +00:00
cmd - > next = cmd_functions ;
cmd_functions = cmd ;
}
else //insert later
2010-02-15 23:26:55 +00:00
{
2010-08-29 02:22:55 +00:00
prev = cmd_functions ;
cursor = cmd_functions - > next ;
while ( ( cursor ! = NULL ) & & ( strcmp ( cmd - > name , cursor - > name ) > 0 ) )
2010-02-15 23:26:55 +00:00
{
2010-08-29 02:22:55 +00:00
prev = cursor ;
cursor = cursor - > next ;
}
cmd - > next = prev - > next ;
prev - > next = cmd ;
}
2010-02-15 23:26:55 +00:00
//johnfitz
2020-07-02 19:05:51 +00:00
if ( cmd - > dynamic )
return cmd ;
return NULL ;
}
void Cmd_RemoveCommand ( cmd_function_t * cmd )
{
cmd_function_t * * link ;
for ( link = & cmd_functions ; * link ; link = & ( * link ) - > next )
{
if ( * link = = cmd )
{
* link = cmd - > next ;
free ( cmd ) ;
return ;
}
}
Sys_Error ( " Cmd_RemoveCommand unable to remove command %s " , cmd - > name ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = =
Cmd_Exists
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
qboolean Cmd_Exists ( const char * cmd_name )
2010-02-15 23:26:55 +00:00
{
cmd_function_t * cmd ;
for ( cmd = cmd_functions ; cmd ; cmd = cmd - > next )
{
if ( ! Q_strcmp ( cmd_name , cmd - > name ) )
2020-09-02 08:43:25 +00:00
{
if ( cmd - > srctype ! = src_command ) //these commands only exist in certain situations... so pretend they don't exist here.
continue ;
2010-02-15 23:26:55 +00:00
return true ;
2020-09-02 08:43:25 +00:00
}
2010-02-15 23:26:55 +00:00
}
return false ;
}
/*
= = = = = = = = = = = =
Cmd_CompleteCommand
= = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
const char * Cmd_CompleteCommand ( const char * partial )
2010-02-15 23:26:55 +00:00
{
cmd_function_t * cmd ;
2010-08-29 02:22:55 +00:00
int len ;
2010-02-15 23:26:55 +00:00
len = Q_strlen ( partial ) ;
if ( ! len )
return NULL ;
// check functions
for ( cmd = cmd_functions ; cmd ; cmd = cmd - > next )
if ( ! Q_strncmp ( partial , cmd - > name , len ) )
return cmd - > name ;
return NULL ;
}
/*
= = = = = = = = = = = =
Cmd_ExecuteString
A complete command line has been parsed , so try to execute it
FIXME : lookupnoadd the token to speed search ?
= = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
qboolean Cmd_ExecuteString ( const char * text , cmd_source_t src )
2010-02-15 23:26:55 +00:00
{
cmd_function_t * cmd ;
cmdalias_t * a ;
cmd_source = src ;
Cmd_TokenizeString ( text ) ;
// execute the command line
if ( ! Cmd_Argc ( ) )
2017-09-17 02:12:53 +00:00
return true ; // no tokens
2010-02-15 23:26:55 +00:00
// check functions
for ( cmd = cmd_functions ; cmd ; cmd = cmd - > next )
{
2013-09-25 17:01:40 +00:00
if ( ! q_strcasecmp ( cmd_argv [ 0 ] , cmd - > name ) )
2010-02-15 23:26:55 +00:00
{
2017-09-17 02:12:53 +00:00
if ( src = = src_client & & cmd - > srctype ! = src_client )
2021-08-31 02:36:55 +00:00
continue ;
2017-09-17 02:12:53 +00:00
else if ( src = = src_command & & cmd - > srctype = = src_server )
continue ; //src_command can execute anything but server commands (which it ignores, allowing for alternative behaviour)
else if ( src = = src_server & & cmd - > srctype ! = src_server )
continue ; //src_server may only execute server commands (such commands must be safe to parse within the context of a network message, so no disconnect/connect/playdemo/etc)
2018-05-01 00:35:14 +00:00
else
{
2020-07-02 19:05:51 +00:00
qboolean ret = false ;
2021-08-31 02:36:55 +00:00
qcvm_t * oldvm ;
if ( ! ret & & cmd - > function & & ( ! cmd - > qcinterceptable | | src = = src_client ) )
{
cmd - > function ( ) ;
ret = true ;
}
oldvm = ret ? NULL : qcvm ;
if ( oldvm )
PR_SwitchQCVM ( NULL ) ;
2020-07-02 19:05:51 +00:00
if ( ! ret & & cl . qcvm . extfuncs . CSQC_ConsoleCommand )
2018-05-01 00:35:14 +00:00
{
PR_SwitchQCVM ( & cl . qcvm ) ;
G_INT ( OFS_PARM0 ) = PR_MakeTempString ( text ) ;
PR_ExecuteProgram ( cl . qcvm . extfuncs . CSQC_ConsoleCommand ) ;
ret = G_FLOAT ( OFS_RETURN ) ;
PR_SwitchQCVM ( NULL ) ;
}
2020-07-02 19:05:51 +00:00
if ( ! ret & & cls . menu_qcvm . extfuncs . m_consolecommand )
{
PR_SwitchQCVM ( & cls . menu_qcvm ) ;
G_INT ( OFS_PARM0 ) = PR_MakeTempString ( text ) ;
PR_ExecuteProgram ( cls . menu_qcvm . extfuncs . m_consolecommand ) ;
ret = G_FLOAT ( OFS_RETURN ) ;
PR_SwitchQCVM ( NULL ) ;
}
2021-08-31 02:36:55 +00:00
if ( oldvm )
PR_SwitchQCVM ( oldvm ) ;
if ( ! ret & & cmd - > function )
{
cmd - > function ( ) ;
ret = true ;
}
2020-07-02 19:05:51 +00:00
if ( ! ret )
2018-05-01 00:35:14 +00:00
Con_Printf ( " gamecode not running, cannot \" %s \" \n " , Cmd_Argv ( 0 ) ) ;
}
2017-09-17 02:12:53 +00:00
return true ;
2010-02-15 23:26:55 +00:00
}
}
2017-09-17 02:12:53 +00:00
if ( src = = src_client )
{ //spike -- please don't execute similarly named aliases, nor custom cvars...
Con_DPrintf ( " %s tried to %s \n " , host_client - > name , text ) ;
return false ;
}
if ( src ! = src_command )
return false ;
2010-02-15 23:26:55 +00:00
// check alias
for ( a = cmd_alias ; a ; a = a - > next )
{
2013-09-25 17:01:40 +00:00
if ( ! q_strcasecmp ( cmd_argv [ 0 ] , a - > name ) )
2010-02-15 23:26:55 +00:00
{
Cbuf_InsertText ( a - > value ) ;
2017-09-17 02:12:53 +00:00
return true ;
2010-02-15 23:26:55 +00:00
}
}
// check cvars
if ( ! Cvar_Command ( ) )
2017-09-17 02:12:53 +00:00
if ( cmd_warncmd . value | | developer . value )
Con_Printf ( " Unknown command \" %s \" \n " , Cmd_Argv ( 0 ) ) ;
2010-02-15 23:26:55 +00:00
2017-09-17 02:12:53 +00:00
return true ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = = = = = = = = =
Cmd_ForwardToServer
Sends the entire command line over to the server
= = = = = = = = = = = = = = = = = = =
*/
void Cmd_ForwardToServer ( void )
{
if ( cls . state ! = ca_connected )
{
Con_Printf ( " Can't \" %s \" , not connected \n " , Cmd_Argv ( 0 ) ) ;
return ;
}
if ( cls . demoplayback )
return ; // not really connected
MSG_WriteByte ( & cls . message , clc_stringcmd ) ;
2013-09-25 17:01:40 +00:00
if ( q_strcasecmp ( Cmd_Argv ( 0 ) , " cmd " ) ! = 0 )
2010-02-15 23:26:55 +00:00
{
SZ_Print ( & cls . message , Cmd_Argv ( 0 ) ) ;
SZ_Print ( & cls . message , " " ) ;
}
2017-09-17 02:12:53 +00:00
else
{
//hack zone for compat.
//stuffcmd("cmd foo\n") is a good way to query the client to see if it knows foo because the server is guarenteed a response even if it doesn't understand it, saving a timeout
if ( ! strcmp ( Cmd_Args ( ) , " protocols " ) )
{ //server asked us for a list of protocol numbers that we claim to support. this allows cool servers like fte to autodetect higher limits etc.
//servers may assume that the client's preferred protocol will be listed first.
SZ_Print ( & cls . message , va ( " protocols %i %i %i %i %i " , PROTOCOL_RMQ , PROTOCOL_FITZQUAKE , PROTOCOL_VERSION_BJP3 , PROTOCOL_VERSION_DP7 , PROTOCOL_NETQUAKE ) ) ;
return ;
}
if ( ! strcmp ( Cmd_Args ( ) , " pext " ) & & ! cl_nopext . value )
{ //server asked us for a key+value list of the extensions+attributes we support
2020-09-03 08:37:49 +00:00
SZ_Print ( & cls . message , va ( " pext "
" %#x %#x "
" %#x %#x " ,
PROTOCOL_FTE_PEXT1 , PEXT1_SUPPORTED_CLIENT ,
PROTOCOL_FTE_PEXT2 , PEXT2_SUPPORTED_CLIENT ) ) ;
2017-09-17 02:12:53 +00:00
return ;
}
}
2010-02-15 23:26:55 +00:00
if ( Cmd_Argc ( ) > 1 )
SZ_Print ( & cls . message , Cmd_Args ( ) ) ;
else
SZ_Print ( & cls . message , " \n " ) ;
}
/*
= = = = = = = = = = = = = = = =
Cmd_CheckParm
Returns the position ( 1 to argc - 1 ) in the command ' s argument list
where the given parameter apears , or 0 if not present
= = = = = = = = = = = = = = = =
*/
2010-08-29 02:22:55 +00:00
int Cmd_CheckParm ( const char * parm )
2010-02-15 23:26:55 +00:00
{
int i ;
if ( ! parm )
2022-04-22 14:50:02 +00:00
Sys_Error ( " Cmd_CheckParm: null input \n " ) ;
2010-02-15 23:26:55 +00:00
for ( i = 1 ; i < Cmd_Argc ( ) ; i + + )
2022-04-22 14:50:02 +00:00
if ( ! q_strcasecmp ( parm , Cmd_Argv ( i ) ) )
2010-02-15 23:26:55 +00:00
return i ;
return 0 ;
}
2010-08-29 02:22:55 +00:00