#include "../qcommon/exe_headers.h" typedef struct cmd_function_s { struct cmd_function_s *next; char *name; xcommand_t function; } cmd_function_t; static cmd_function_t *cmd_functions; // possible commands to execute /* ============ Cmd_AddCommand ============ */ void Cmd_AddCommand( const char *cmd_name, xcommand_t function ) { cmd_function_t *cmd; // fail if the command already exists for ( cmd = cmd_functions ; cmd ; cmd=cmd->next ) { if ( !strcmp( cmd_name, cmd->name ) ) { // allow completion-only commands to be silently doubled if ( function != NULL ) { Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); } return; } } // use a small malloc to avoid zone fragmentation cmd = (struct cmd_function_s *)S_Malloc (sizeof(cmd_function_t)); cmd->name = CopyString( cmd_name ); cmd->function = function; cmd->next = cmd_functions; cmd_functions = cmd; } /* ============ Cmd_RemoveCommand ============ */ void Cmd_RemoveCommand( const char *cmd_name ) { cmd_function_t *cmd, **back; back = &cmd_functions; while( 1 ) { cmd = *back; if ( !cmd ) { // command wasn't active return; } if ( !strcmp( cmd_name, cmd->name ) ) { *back = cmd->next; if (cmd->name) { Z_Free(cmd->name); } Z_Free (cmd); return; } back = &cmd->next; } } /* ============ Cmd_CommandCompletion ============ */ void Cmd_CommandCompletion( void(*callback)(const char *s) ) { cmd_function_t *cmd; for (cmd=cmd_functions ; cmd ; cmd=cmd->next) { callback( cmd->name ); } } /* ============ Cmd_ExecuteString A complete command line has been parsed, so try to execute it ============ */ void Cmd_ExecuteString( const char *text ) { cmd_function_t *cmd, **prev; // execute the command line Cmd_TokenizeString( text ); if ( !Cmd_Argc() ) { return; // no tokens } // check registered command functions for ( prev = &cmd_functions ; *prev ; prev = &cmd->next ) { cmd = *prev; if ( !Q_stricmp( Cmd_Argv(0), cmd->name ) ) { // rearrange the links so that the command will be // near the head of the list next time it is used *prev = cmd->next; cmd->next = cmd_functions; cmd_functions = cmd; // perform the action if ( !cmd->function ) { // let the cgame or game handle it break; } else { cmd->function (); } return; } } // check cvars if ( Cvar_Command() ) { return; } // check client game commands if ( com_cl_running && com_cl_running->integer && CL_GameCommand() ) { return; } // check server game commands if ( com_sv_running && com_sv_running->integer && SV_GameCommand() ) { return; } // check ui commands if ( com_cl_running && com_cl_running->integer && UI_GameCommand() ) { return; } // send it as a server command if we are connected // this will usually result in a chat message //CL_ForwardCommandToServer ( text ); CL_ForwardCommandToServer ( text ); } /* ============ Cmd_List_f ============ */ void Cmd_List_f (void) { cmd_function_t *cmd; int i; char *match; if ( Cmd_Argc() > 1 ) { match = Cmd_Argv( 1 ); } else { match = NULL; } i = 0; for (cmd=cmd_functions ; cmd ; cmd=cmd->next) { if (match && !Com_Filter(match, cmd->name, qfalse)) continue; Com_Printf ("%s\n", cmd->name); i++; } Com_Printf ("%i commands\n", i); }