mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-11-10 06:31:48 +00:00
intelligent TAB-completion handling (support for mapnames, binds, etc)
This commit is contained in:
parent
047f312ea7
commit
4f9754adfe
9 changed files with 436 additions and 424 deletions
|
@ -758,6 +758,13 @@ int Key_GetKey( const char* binding )
|
|||
}
|
||||
|
||||
|
||||
void Key_KeyNameCompletion( void (*callback)(const char *s) )
|
||||
{
|
||||
for( int i = 0; keynames[i].name != NULL; i++ )
|
||||
callback( keynames[i].name );
|
||||
}
|
||||
|
||||
|
||||
// write bindings to a config file as "bind key value" so they can be exec'ed later
|
||||
|
||||
void Key_WriteBindings( fileHandle_t f )
|
||||
|
@ -830,6 +837,22 @@ static void Key_Bind_f()
|
|||
}
|
||||
|
||||
|
||||
static void Key_CompleteBind_f( int startArg, int compArg )
|
||||
{
|
||||
if ( compArg == startArg + 1 )
|
||||
Field_AutoCompleteKeyName( startArg, compArg );
|
||||
else if ( compArg >= startArg + 2 )
|
||||
Field_AutoCompleteFrom( compArg, compArg, qtrue, qtrue );
|
||||
}
|
||||
|
||||
|
||||
static void Key_CompleteUnbind_f( int startArg, int compArg )
|
||||
{
|
||||
if ( compArg == startArg + 1 )
|
||||
Field_AutoCompleteKeyName( startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
static void Key_Bindlist_f()
|
||||
{
|
||||
for ( int i = 0; i < MAX_KEYS; ++i ) {
|
||||
|
@ -845,7 +868,9 @@ void CL_InitKeyCommands()
|
|||
COMPILE_TIME_ASSERT( K_LAST_KEY <= MAX_KEYS );
|
||||
|
||||
Cmd_AddCommand( "bind", Key_Bind_f );
|
||||
Cmd_SetAutoCompletion( "bind", Key_CompleteBind_f );
|
||||
Cmd_AddCommand( "unbind", Key_Unbind_f );
|
||||
Cmd_SetAutoCompletion( "unbind", Key_CompleteUnbind_f );
|
||||
Cmd_AddCommand( "unbindall", Key_Unbindall_f );
|
||||
Cmd_AddCommand( "bindlist", Key_Bindlist_f );
|
||||
}
|
||||
|
|
|
@ -263,6 +263,13 @@ static void CL_Record_f()
|
|||
}
|
||||
|
||||
|
||||
static void CL_CompleteDemoRecord_f( int startArg, int compArg )
|
||||
{
|
||||
if ( startArg + 1 == compArg )
|
||||
Field_AutoCompleteDemoNameWrite( startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
|
@ -425,6 +432,13 @@ void CL_PlayDemo_f()
|
|||
}
|
||||
|
||||
|
||||
static void CL_CompleteDemoPlay_f( int startArg, int compArg )
|
||||
{
|
||||
if ( startArg + 1 == compArg )
|
||||
Field_AutoCompleteDemoNameRead( startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CL_StartDemoLoop
|
||||
|
@ -995,6 +1009,13 @@ static void CL_Rcon_f( void )
|
|||
}
|
||||
|
||||
|
||||
static void CL_CompleteRcon_f( int startArg, int compArg )
|
||||
{
|
||||
if ( startArg < compArg )
|
||||
Field_AutoCompleteFrom( startArg + 1, compArg, qtrue, qtrue );
|
||||
}
|
||||
|
||||
|
||||
// if we are pure we need to send back a command with our referenced pk3 checksums
|
||||
|
||||
static void CL_SendPureChecksums()
|
||||
|
@ -1947,6 +1968,19 @@ qbool CL_CDKeyValidate( const char *key, const char *checksum )
|
|||
}
|
||||
|
||||
|
||||
static void CL_CallVote_f()
|
||||
{
|
||||
CL_ForwardCommandToServer( Cmd_Cmd() );
|
||||
}
|
||||
|
||||
|
||||
static void CL_CompleteCallVote_f( int startArg, int compArg )
|
||||
{
|
||||
if ( compArg == startArg + 2 && !Q_stricmp( Cmd_Argv( startArg + 1 ), "map" ) )
|
||||
Field_AutoCompleteMapName( startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
void CL_Init()
|
||||
{
|
||||
//QSUBSYSTEM_INIT_START( "Client" );
|
||||
|
@ -2019,7 +2053,9 @@ void CL_Init()
|
|||
Cmd_AddCommand ("vid_restart", CL_Vid_Restart_f);
|
||||
Cmd_AddCommand ("disconnect", CL_Disconnect_f);
|
||||
Cmd_AddCommand ("record", CL_Record_f);
|
||||
Cmd_SetAutoCompletion ("record", CL_CompleteDemoRecord_f);
|
||||
Cmd_AddCommand ("demo", CL_PlayDemo_f);
|
||||
Cmd_SetAutoCompletion ("demo", CL_CompleteDemoPlay_f);
|
||||
Cmd_AddCommand ("cinematic", CL_PlayCinematic_f);
|
||||
Cmd_AddCommand ("stoprecord", CL_StopRecord_f);
|
||||
Cmd_AddCommand ("connect", CL_Connect_f);
|
||||
|
@ -2027,6 +2063,7 @@ void CL_Init()
|
|||
Cmd_AddCommand ("localservers", CL_LocalServers_f);
|
||||
Cmd_AddCommand ("globalservers", CL_GlobalServers_f);
|
||||
Cmd_AddCommand ("rcon", CL_Rcon_f);
|
||||
Cmd_SetAutoCompletion ("rcon", CL_CompleteRcon_f);
|
||||
Cmd_AddCommand ("ping", CL_Ping_f );
|
||||
Cmd_AddCommand ("serverstatus", CL_ServerStatus_f );
|
||||
Cmd_AddCommand ("showip", CL_ShowIP_f );
|
||||
|
@ -2036,6 +2073,12 @@ void CL_Init()
|
|||
Cmd_AddCommand ("video", CL_Video_f );
|
||||
Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
|
||||
|
||||
// we use these until we get proper handling on the mod side
|
||||
Cmd_AddCommand ("cv", CL_CallVote_f );
|
||||
Cmd_AddCommand ("callvote", CL_CallVote_f );
|
||||
Cmd_SetAutoCompletion ("cv", CL_CompleteCallVote_f );
|
||||
Cmd_SetAutoCompletion ("callvote", CL_CompleteCallVote_f );
|
||||
|
||||
CL_InitRef();
|
||||
|
||||
SCR_Init();
|
||||
|
@ -2093,6 +2136,10 @@ void CL_Shutdown()
|
|||
Cmd_RemoveCommand ("video");
|
||||
Cmd_RemoveCommand ("stopvideo");
|
||||
|
||||
// we use these until we get proper handling on the mod side
|
||||
Cmd_RemoveCommand ("cv");
|
||||
Cmd_RemoveCommand ("callvote");
|
||||
|
||||
Cvar_Set( "cl_running", "0" );
|
||||
|
||||
recursive = qfalse;
|
||||
|
|
|
@ -158,7 +158,7 @@ void Cbuf_Execute()
|
|||
// SCRIPT COMMANDS
|
||||
|
||||
|
||||
void Cmd_Exec_f()
|
||||
static void Cmd_Exec_f()
|
||||
{
|
||||
char *f;
|
||||
int len;
|
||||
|
@ -184,9 +184,16 @@ void Cmd_Exec_f()
|
|||
}
|
||||
|
||||
|
||||
static void Cmd_CompleteExec_f( int startArg, int compArg )
|
||||
{
|
||||
if ( startArg + 1 == compArg )
|
||||
Field_AutoCompleteConfigName( startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
// inserts the current value of a variable as command text
|
||||
|
||||
void Cmd_Vstr_f()
|
||||
static void Cmd_Vstr_f()
|
||||
{
|
||||
if (Cmd_Argc() != 2) {
|
||||
Com_Printf( "vstr <variablename> : execute a variable command\n" );
|
||||
|
@ -196,6 +203,13 @@ void Cmd_Vstr_f()
|
|||
}
|
||||
|
||||
|
||||
static void Cmd_CompleteVstr_f( int startArg, int compArg )
|
||||
{
|
||||
if ( compArg == startArg + 1 )
|
||||
Field_AutoCompleteFrom( compArg, compArg, qfalse, qtrue );
|
||||
}
|
||||
|
||||
|
||||
// just prints the rest of the line to the console
|
||||
|
||||
void Cmd_Echo_f()
|
||||
|
@ -215,11 +229,14 @@ typedef struct cmd_function_s
|
|||
struct cmd_function_s *next;
|
||||
char *name;
|
||||
xcommand_t function;
|
||||
xcommandCompletion_t completion;
|
||||
} cmd_function_t;
|
||||
|
||||
|
||||
static int cmd_argc;
|
||||
static char* cmd_argv[MAX_STRING_TOKENS]; // points into cmd_tokenized
|
||||
static int cmd_argoffsets[MAX_STRING_TOKENS]; // offsets into cmd_cmd
|
||||
static qbool cmd_quoted[MAX_STRING_TOKENS]; // set to 1 if the input was quoted
|
||||
static char cmd_tokenized[BIG_INFO_STRING+MAX_STRING_TOKENS]; // will have 0 bytes inserted
|
||||
static char cmd_cmd[BIG_INFO_STRING]; // the original command we received (no token processing)
|
||||
|
||||
|
@ -261,6 +278,28 @@ const char* Cmd_ArgsFrom( int arg )
|
|||
}
|
||||
|
||||
|
||||
qbool Cmd_ArgQuoted( int arg )
|
||||
{
|
||||
if (arg < 0 || arg >= cmd_argc)
|
||||
return qfalse;
|
||||
|
||||
return cmd_quoted[arg];
|
||||
}
|
||||
|
||||
|
||||
int Cmd_ArgIndexFromOffset( int offset )
|
||||
{
|
||||
for (int i = 0; i < cmd_argc; ++i) {
|
||||
const int start = cmd_argoffsets[i];
|
||||
const int end = start + strlen( cmd_argv[i] );
|
||||
if (offset >= start && offset <= end)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
const char* Cmd_Args()
|
||||
{
|
||||
return Cmd_ArgsFrom(1);
|
||||
|
@ -305,6 +344,7 @@ static void Cmd_TokenizeString2( const char* text, qbool ignoreQuotes )
|
|||
Q_strncpyz( cmd_cmd, text, sizeof(cmd_cmd) );
|
||||
|
||||
char* out = cmd_tokenized;
|
||||
const char* const textStart = text;
|
||||
|
||||
while ( 1 ) {
|
||||
if ( cmd_argc == MAX_STRING_TOKENS ) {
|
||||
|
@ -342,6 +382,8 @@ static void Cmd_TokenizeString2( const char* text, qbool ignoreQuotes )
|
|||
// handle quoted strings - NOTE: this doesn't handle \" escaping
|
||||
if ( !ignoreQuotes && *text == '"' ) {
|
||||
cmd_argv[cmd_argc] = out;
|
||||
cmd_argoffsets[cmd_argc] = text + 1 - textStart; // jump past the opening quote
|
||||
cmd_quoted[cmd_argc] = qtrue;
|
||||
cmd_argc++;
|
||||
text++;
|
||||
while ( *text && *text != '"' ) {
|
||||
|
@ -357,6 +399,8 @@ static void Cmd_TokenizeString2( const char* text, qbool ignoreQuotes )
|
|||
|
||||
// regular token
|
||||
cmd_argv[cmd_argc] = out;
|
||||
cmd_argoffsets[cmd_argc] = text - textStart;
|
||||
cmd_quoted[cmd_argc] = qfalse;
|
||||
cmd_argc++;
|
||||
|
||||
// skip until whitespace, quote, or command
|
||||
|
@ -396,7 +440,7 @@ void Cmd_TokenizeStringIgnoreQuotes( const char* text )
|
|||
}
|
||||
|
||||
|
||||
void Cmd_AddCommand( const char *cmd_name, xcommand_t function )
|
||||
void Cmd_AddCommand( const char* cmd_name, xcommand_t function )
|
||||
{
|
||||
cmd_function_t* cmd;
|
||||
|
||||
|
@ -415,12 +459,13 @@ void Cmd_AddCommand( const char *cmd_name, xcommand_t function )
|
|||
cmd = (cmd_function_t*)S_Malloc(sizeof(cmd_function_t));
|
||||
cmd->name = CopyString( cmd_name );
|
||||
cmd->function = function;
|
||||
cmd->completion = NULL;
|
||||
cmd->next = cmd_functions;
|
||||
cmd_functions = cmd;
|
||||
}
|
||||
|
||||
|
||||
void Cmd_RemoveCommand( const char *cmd_name )
|
||||
void Cmd_RemoveCommand( const char* cmd_name )
|
||||
{
|
||||
cmd_function_t** back = &cmd_functions;
|
||||
|
||||
|
@ -443,7 +488,32 @@ void Cmd_RemoveCommand( const char *cmd_name )
|
|||
}
|
||||
|
||||
|
||||
void Cmd_CommandCompletion( void(*callback)(const char *s) )
|
||||
void Cmd_SetAutoCompletion( const char* cmd_name, xcommandCompletion_t completion )
|
||||
{
|
||||
cmd_function_t* cmd;
|
||||
for ( cmd = cmd_functions; cmd; cmd = cmd->next ) {
|
||||
if ( !strcmp( cmd_name, cmd->name ) ) {
|
||||
cmd->completion = completion;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Cmd_AutoCompleteArgument( const char* cmd_name, int startArg, int compArg )
|
||||
{
|
||||
const cmd_function_t* cmd;
|
||||
for ( cmd = cmd_functions; cmd; cmd = cmd->next ) {
|
||||
if ( !strcmp( cmd_name, cmd->name ) ) {
|
||||
if ( cmd->completion )
|
||||
cmd->completion( startArg, compArg );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Cmd_CommandCompletion( void(*callback)(const char* s) )
|
||||
{
|
||||
const cmd_function_t* cmd;
|
||||
for ( cmd = cmd_functions; cmd; cmd = cmd->next ) {
|
||||
|
@ -533,7 +603,9 @@ void Cmd_Init()
|
|||
{
|
||||
Cmd_AddCommand( "cmdlist", Cmd_List_f );
|
||||
Cmd_AddCommand( "exec", Cmd_Exec_f );
|
||||
Cmd_SetAutoCompletion( "exec", Cmd_CompleteExec_f );
|
||||
Cmd_AddCommand( "vstr", Cmd_Vstr_f );
|
||||
Cmd_SetAutoCompletion( "vstr", Cmd_CompleteVstr_f );
|
||||
Cmd_AddCommand( "echo", Cmd_Echo_f );
|
||||
Cmd_AddCommand( "wait", Cmd_Wait_f );
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ qbool com_fullyInitialized;
|
|||
static char com_errorMessage[MAXPRINTMSG];
|
||||
|
||||
static void Com_WriteConfig_f();
|
||||
static void Com_CompleteWriteConfig_f( int startArg, int compArg );
|
||||
extern void CIN_CloseAllVideos( void );
|
||||
|
||||
//============================================================================
|
||||
|
@ -2219,6 +2220,7 @@ void Com_Init( char *commandLine )
|
|||
|
||||
Cmd_AddCommand( "quit", Com_Quit_f );
|
||||
Cmd_AddCommand( "writeconfig", Com_WriteConfig_f );
|
||||
Cmd_SetAutoCompletion( "writeconfig", Com_CompleteWriteConfig_f );
|
||||
|
||||
const char* s = Q3_VERSION" "PLATFORM_STRING" "__DATE__;
|
||||
com_version = Cvar_Get( "version", s, CVAR_ROM | CVAR_SERVERINFO );
|
||||
|
@ -2311,6 +2313,13 @@ static void Com_WriteConfig_f()
|
|||
}
|
||||
|
||||
|
||||
static void Com_CompleteWriteConfig_f( int startArg, int compArg )
|
||||
{
|
||||
if ( startArg + 1 == compArg )
|
||||
Field_AutoCompleteConfigName( startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
static int Com_ModifyMsec( int msec )
|
||||
{
|
||||
// modify time for debugging values
|
||||
|
@ -2542,6 +2551,51 @@ float Q_acos(float c)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
crc32 routines
|
||||
==================
|
||||
*/
|
||||
|
||||
static unsigned int crc32_table[256];
|
||||
static qboolean crc32_inited = qfalse;
|
||||
|
||||
void crc32_init( unsigned int *crc )
|
||||
{
|
||||
unsigned int c;
|
||||
int i, j;
|
||||
|
||||
if ( !crc32_inited )
|
||||
{
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
c = i;
|
||||
for ( j = 0; j < 8; j++ )
|
||||
c = c & 1 ? (c >> 1) ^ 0xEDB88320UL : c >> 1;
|
||||
crc32_table[i] = c;
|
||||
}
|
||||
crc32_inited = qtrue;
|
||||
}
|
||||
|
||||
*crc = 0xFFFFFFFFUL;
|
||||
}
|
||||
|
||||
|
||||
void crc32_update( unsigned int *crc, unsigned char *buf, unsigned int len )
|
||||
{
|
||||
while ( len-- )
|
||||
{
|
||||
*crc = crc32_table[(*crc ^ *buf++) & 0xFF] ^ (*crc >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void crc32_final( unsigned int *crc )
|
||||
{
|
||||
*crc = *crc ^ 0xFFFFFFFFUL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========================================
|
||||
command line completion
|
||||
|
@ -2605,459 +2659,223 @@ static void PrintCvarMatches( const char *s )
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
crc32 routines
|
||||
==================
|
||||
*/
|
||||
|
||||
static unsigned int crc32_table[256];
|
||||
static qboolean crc32_inited = qfalse;
|
||||
|
||||
void crc32_init( unsigned int *crc )
|
||||
static void Field_AppendArgString( field_t *field, int arg, const char *s )
|
||||
{
|
||||
unsigned int c;
|
||||
int i, j;
|
||||
|
||||
if ( !crc32_inited )
|
||||
{
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
c = i;
|
||||
for ( j = 0; j < 8; j++ )
|
||||
c = c & 1 ? (c >> 1) ^ 0xEDB88320UL : c >> 1;
|
||||
crc32_table[i] = c;
|
||||
}
|
||||
crc32_inited = qtrue;
|
||||
}
|
||||
|
||||
*crc = 0xFFFFFFFFUL;
|
||||
const qbool quoted = Cmd_ArgQuoted( arg );
|
||||
if ( quoted )
|
||||
Q_strcat( field->buffer, sizeof( field->buffer ), "\"" );
|
||||
Q_strcat( field->buffer, sizeof( field->buffer ), s );
|
||||
if ( quoted )
|
||||
Q_strcat( field->buffer, sizeof( field->buffer ), "\"" );
|
||||
}
|
||||
|
||||
|
||||
void crc32_update( unsigned int *crc, unsigned char *buf, unsigned int len )
|
||||
static void Field_AppendArg( field_t *field, int arg )
|
||||
{
|
||||
while ( len-- )
|
||||
{
|
||||
*crc = crc32_table[(*crc ^ *buf++) & 0xFF] ^ (*crc >> 8);
|
||||
Field_AppendArgString( field, arg, Cmd_Argv( arg ) );
|
||||
}
|
||||
|
||||
|
||||
static void Field_AppendLastArgs( field_t *field, int startArg )
|
||||
{
|
||||
const int argc = Cmd_Argc();
|
||||
for ( int i = startArg; i < argc; ++i ) {
|
||||
Q_strcat( field->buffer, sizeof( field->buffer ), " " );
|
||||
Field_AppendArg( field, i );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void crc32_final( unsigned int *crc )
|
||||
static void Field_AppendFirstArgs( field_t *field, int count )
|
||||
{
|
||||
*crc = *crc ^ 0xFFFFFFFFUL;
|
||||
}
|
||||
if ( count <= 0 )
|
||||
return;
|
||||
|
||||
|
||||
#if I_EVER_NAG_TIMBO_INTO_FIXING_THIS
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Com_CharIsOneOfCharset
|
||||
==================
|
||||
*/
|
||||
static qbool Com_CharIsOneOfCharset( char c, char *set )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < strlen( set ); i++ )
|
||||
{
|
||||
if( set[ i ] == c )
|
||||
return qtrue;
|
||||
Field_AppendArg( field, 0 );
|
||||
for ( int i = 1; i < count; ++i ) {
|
||||
Q_strcat( field->buffer, sizeof( field->buffer ), " " );
|
||||
Field_AppendArg( field, i );
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Com_SkipCharset
|
||||
==================
|
||||
*/
|
||||
char *Com_SkipCharset( char *s, char *sep )
|
||||
|
||||
static qbool String_HasLeadingSlash( const char *arg )
|
||||
{
|
||||
char *p = s;
|
||||
|
||||
while( p )
|
||||
{
|
||||
if( Com_CharIsOneOfCharset( *p, sep ) )
|
||||
p++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return p;
|
||||
return ((*arg == '\\') || (*arg == '/'));
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Com_SkipTokens
|
||||
==================
|
||||
*/
|
||||
char *Com_SkipTokens( char *s, int numTokens, char *sep )
|
||||
{
|
||||
int sepCount = 0;
|
||||
char *p = s;
|
||||
|
||||
while( sepCount < numTokens )
|
||||
{
|
||||
if( Com_CharIsOneOfCharset( *p++, sep ) )
|
||||
{
|
||||
sepCount++;
|
||||
while( Com_CharIsOneOfCharset( *p, sep ) )
|
||||
p++;
|
||||
}
|
||||
else if( *p == '\0' )
|
||||
break;
|
||||
}
|
||||
// returns qtrue if the match list should be printed
|
||||
static qboolean Field_CompleteShortestMatch( int startArg, int compArg )
|
||||
{
|
||||
if ( matchCount == 0 )
|
||||
return qfalse;
|
||||
|
||||
field_t *const field = completionField;
|
||||
|
||||
// write the first part of the field
|
||||
*field->buffer = '\0';
|
||||
if ( compArg > 0 ) {
|
||||
Field_AppendFirstArgs( field, compArg );
|
||||
Q_strcat( field->buffer, sizeof( field->buffer ), " " );
|
||||
}
|
||||
Field_AppendArgString( field, compArg, shortestMatch );
|
||||
|
||||
if ( matchCount == 1 ) {
|
||||
// finish the field with the only match
|
||||
if ( compArg == Cmd_Argc() - 1 )
|
||||
Q_strcat( field->buffer, sizeof( field->buffer ), " " );
|
||||
field->cursor = strlen( field->buffer );
|
||||
Field_AppendLastArgs( field, compArg + 1 );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if( sepCount == numTokens )
|
||||
return p;
|
||||
else
|
||||
return s;
|
||||
// finish the field with the shortest match and echo the command
|
||||
field->cursor = strlen( field->buffer );
|
||||
if ( Cmd_ArgQuoted( compArg ) )
|
||||
field->cursor--;
|
||||
Field_AppendLastArgs( field, compArg + 1 );
|
||||
Com_Printf( "]%s\n", Cmd_Cmd() );
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Field_FindFirstSeparator
|
||||
===============
|
||||
*/
|
||||
static char *Field_FindFirstSeparator( char *s )
|
||||
|
||||
static void Field_AutoCompleteCmdOrVarName( int startArg, int compArg, qbool searchCmds, qbool searchVars )
|
||||
{
|
||||
int i;
|
||||
if ( !searchCmds && !searchVars )
|
||||
return;
|
||||
|
||||
for( i = 0; i < strlen( s ); i++ )
|
||||
{
|
||||
if( s[ i ] == ';' )
|
||||
return &s[ i ];
|
||||
}
|
||||
if ( searchCmds )
|
||||
Cmd_CommandCompletion( FindMatches );
|
||||
if ( searchVars )
|
||||
Cvar_CommandCompletion( FindMatches );
|
||||
|
||||
return NULL;
|
||||
if ( !Field_CompleteShortestMatch( startArg, compArg ) )
|
||||
return;
|
||||
|
||||
if ( searchCmds )
|
||||
Cmd_CommandCompletion( PrintMatches );
|
||||
if ( searchVars )
|
||||
Cvar_CommandCompletion( PrintCvarMatches );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Field_CompleteFilename
|
||||
===============
|
||||
*/
|
||||
static void Field_CompleteFilename( const char *dir,
|
||||
const char *ext, qbool stripExt )
|
||||
|
||||
static void Field_AutoCompleteCommandArgument( int startArg, int compArg )
|
||||
{
|
||||
const char* cmdName = Cmd_Argv( startArg );
|
||||
if ( String_HasLeadingSlash( cmdName ) )
|
||||
cmdName++;
|
||||
if ( *cmdName == '\0' )
|
||||
return;
|
||||
|
||||
Cmd_AutoCompleteArgument( cmdName, startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
void Field_AutoCompleteFrom( int startArg, int compArg, qbool searchCmds, qbool searchVars )
|
||||
{
|
||||
// clear results
|
||||
matchCount = 0;
|
||||
shortestMatch[ 0 ] = 0;
|
||||
*shortestMatch = '\0';
|
||||
|
||||
FS_FilenameCompletion( dir, ext, stripExt, FindMatches );
|
||||
|
||||
if( matchCount == 0 )
|
||||
return;
|
||||
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ),
|
||||
shortestMatch + strlen( completionString ) );
|
||||
completionField->cursor = strlen( completionField->buffer );
|
||||
|
||||
if( matchCount == 1 )
|
||||
{
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
|
||||
completionField->cursor++;
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf( "]%s\n", completionField->buffer );
|
||||
|
||||
FS_FilenameCompletion( dir, ext, stripExt, PrintMatches );
|
||||
// For the first argument, we always check both variables and commands.
|
||||
// For other arguments, we run a custom auto-completion handler
|
||||
// registered by the command if one was provided.
|
||||
if ( compArg == startArg )
|
||||
Field_AutoCompleteCmdOrVarName( startArg, compArg, searchCmds, searchVars );
|
||||
else
|
||||
Field_AutoCompleteCommandArgument( startArg, compArg );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Field_CompleteCommand
|
||||
===============
|
||||
*/
|
||||
static void Field_CompleteCommand( char *cmd,
|
||||
qbool doCommands, qbool doCvars )
|
||||
{
|
||||
int completionArgument = 0;
|
||||
char *p;
|
||||
|
||||
// Skip leading whitespace and quotes
|
||||
cmd = Com_SkipCharset( cmd, " \"" );
|
||||
|
||||
Cmd_TokenizeStringIgnoreQuotes( cmd );
|
||||
completionArgument = Cmd_Argc( );
|
||||
|
||||
// If there is trailing whitespace on the cmd
|
||||
if( *( cmd + strlen( cmd ) - 1 ) == ' ' )
|
||||
{
|
||||
completionString = "";
|
||||
completionArgument++;
|
||||
}
|
||||
else
|
||||
completionString = Cmd_Argv( completionArgument - 1 );
|
||||
|
||||
if( completionArgument > 1 )
|
||||
{
|
||||
const char *baseCmd = Cmd_Argv( 0 );
|
||||
|
||||
#ifndef DEDICATED
|
||||
// If the very first token does not have a leading \ or /,
|
||||
// refuse to autocomplete
|
||||
if( cmd == completionField->buffer )
|
||||
{
|
||||
if( baseCmd[ 0 ] != '\\' && baseCmd[ 0 ] != '/' )
|
||||
return;
|
||||
baseCmd++;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( ( p = Field_FindFirstSeparator( cmd ) ) )
|
||||
{
|
||||
// Compound command
|
||||
Field_CompleteCommand( p + 1, qtrue, qtrue );
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: all this junk should really be associated with the respective
|
||||
// commands, instead of being hard coded here
|
||||
if( ( !Q_stricmp( baseCmd, "map" ) ||
|
||||
!Q_stricmp( baseCmd, "devmap" ) ||
|
||||
!Q_stricmp( baseCmd, "spmap" ) ||
|
||||
!Q_stricmp( baseCmd, "spdevmap" ) ) &&
|
||||
completionArgument == 2 )
|
||||
{
|
||||
Field_CompleteFilename( "maps", "bsp", qtrue );
|
||||
}
|
||||
else if( ( !Q_stricmp( baseCmd, "exec" ) ||
|
||||
!Q_stricmp( baseCmd, "writeconfig" ) ) &&
|
||||
completionArgument == 2 )
|
||||
{
|
||||
Field_CompleteFilename( "", "cfg", qfalse );
|
||||
}
|
||||
else if( !Q_stricmp( baseCmd, "condump" ) &&
|
||||
completionArgument == 2 )
|
||||
{
|
||||
Field_CompleteFilename( "", "txt", qfalse );
|
||||
}
|
||||
else if( !Q_stricmp( baseCmd, "demo" ) && completionArgument == 2 )
|
||||
{
|
||||
char demoExt[ 16 ];
|
||||
|
||||
Com_sprintf( demoExt, sizeof( demoExt ), ".dm_%d", PROTOCOL_VERSION );
|
||||
Field_CompleteFilename( "demos", demoExt, qtrue );
|
||||
}
|
||||
else if( ( !Q_stricmp( baseCmd, "toggle" ) ||
|
||||
!Q_stricmp( baseCmd, "vstr" ) ||
|
||||
!Q_stricmp( baseCmd, "set" ) ||
|
||||
!Q_stricmp( baseCmd, "seta" ) ||
|
||||
!Q_stricmp( baseCmd, "setu" ) ||
|
||||
!Q_stricmp( baseCmd, "sets" ) ) &&
|
||||
completionArgument == 2 )
|
||||
{
|
||||
// Skip "<cmd> "
|
||||
p = Com_SkipTokens( cmd, 1, " " );
|
||||
|
||||
if( p > cmd )
|
||||
Field_CompleteCommand( p, qfalse, qtrue );
|
||||
}
|
||||
else if( !Q_stricmp( baseCmd, "rcon" ) && completionArgument == 2 )
|
||||
{
|
||||
// Skip "rcon "
|
||||
p = Com_SkipTokens( cmd, 1, " " );
|
||||
|
||||
if( p > cmd )
|
||||
Field_CompleteCommand( p, qtrue, qtrue );
|
||||
}
|
||||
else if( !Q_stricmp( baseCmd, "bind" ) && completionArgument >= 3 )
|
||||
{
|
||||
// Skip "bind <key> "
|
||||
p = Com_SkipTokens( cmd, 2, " " );
|
||||
|
||||
if( p > cmd )
|
||||
Field_CompleteCommand( p, qtrue, qtrue );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( completionString[0] == '\\' || completionString[0] == '/' )
|
||||
completionString++;
|
||||
|
||||
matchCount = 0;
|
||||
shortestMatch[ 0 ] = 0;
|
||||
|
||||
if( strlen( completionString ) == 0 )
|
||||
return;
|
||||
|
||||
if( doCommands )
|
||||
Cmd_CommandCompletion( FindMatches );
|
||||
|
||||
if( doCvars )
|
||||
Cvar_CommandCompletion( FindMatches );
|
||||
|
||||
if( matchCount == 0 )
|
||||
return; // no matches
|
||||
|
||||
if( cmd == completionField->buffer )
|
||||
{
|
||||
#ifndef DEDICATED
|
||||
Com_sprintf( completionField->buffer,
|
||||
sizeof( completionField->buffer ), "\\%s", shortestMatch );
|
||||
#else
|
||||
Com_sprintf( completionField->buffer,
|
||||
sizeof( completionField->buffer ), "%s", shortestMatch );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ),
|
||||
shortestMatch + strlen( completionString ) );
|
||||
}
|
||||
|
||||
completionField->cursor = strlen( completionField->buffer );
|
||||
|
||||
if( matchCount == 1 )
|
||||
{
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
|
||||
completionField->cursor++;
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf( "]%s\n", completionField->buffer );
|
||||
|
||||
// run through again, printing matches
|
||||
if( doCommands )
|
||||
Cmd_CommandCompletion( PrintMatches );
|
||||
|
||||
if( doCvars )
|
||||
Cvar_CommandCompletion( PrintCvarMatches );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Field_AutoComplete
|
||||
|
||||
Perform Tab expansion
|
||||
===============
|
||||
*/
|
||||
void Field_AutoComplete( field_t *field )
|
||||
{
|
||||
completionField = field;
|
||||
|
||||
Field_CompleteCommand( completionField->buffer, qtrue, qtrue );
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
// use the id tab-completion code, which doesn't have all the nice stuff timbo did
|
||||
// but has a "familiar" set of bugs rather than a new and thus even-more-hated set
|
||||
|
||||
static void keyConcatArgs()
|
||||
{
|
||||
int i;
|
||||
const char* arg;
|
||||
|
||||
for ( i = 1 ; i < Cmd_Argc() ; i++ ) {
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
|
||||
arg = Cmd_Argv( i );
|
||||
while (*arg) {
|
||||
if (*arg == ' ') {
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), "\"");
|
||||
break;
|
||||
}
|
||||
arg++;
|
||||
}
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), Cmd_Argv( i ) );
|
||||
if (*arg == ' ') {
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConcatRemaining( const char *src, const char *start )
|
||||
{
|
||||
const char* str = strstr( src, start );
|
||||
|
||||
if (!str) {
|
||||
keyConcatArgs();
|
||||
// first, decide which argument we're going to run completion on
|
||||
Cmd_TokenizeString( field->buffer );
|
||||
const int compArg = Cmd_Argc() == 1 ? 0 : Cmd_ArgIndexFromOffset( field->cursor );
|
||||
if ( compArg < 0 || compArg >= Cmd_Argc() )
|
||||
return;
|
||||
}
|
||||
|
||||
str += strlen( start );
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), str );
|
||||
}
|
||||
|
||||
/*
|
||||
perform Tab expansion
|
||||
NOTE TTimo this was originally client code only
|
||||
moved to common code when writing tty console for *nix dedicated server
|
||||
*/
|
||||
static void Field_CompleteCommand( field_t *field )
|
||||
{
|
||||
completionField = field;
|
||||
|
||||
// only look at the first token for completion purposes
|
||||
Cmd_TokenizeString( completionField->buffer );
|
||||
|
||||
completionString = Cmd_Argv(0);
|
||||
// now select the actual string that needs completing
|
||||
completionString = Cmd_Argv( compArg );
|
||||
#ifndef DEDICATED
|
||||
if ( completionString[0] == '\\' || completionString[0] == '/' ) {
|
||||
if ( compArg == 0 && String_HasLeadingSlash( completionString ) )
|
||||
completionString++;
|
||||
}
|
||||
#endif
|
||||
matchCount = 0;
|
||||
shortestMatch[0] = 0;
|
||||
|
||||
if ( *completionString == '\0' ) {
|
||||
if ( *completionString == '\0' )
|
||||
return;
|
||||
}
|
||||
|
||||
Cmd_CommandCompletion( FindMatches );
|
||||
Cvar_CommandCompletion( FindMatches );
|
||||
Field_AutoCompleteFrom( 0, compArg, qtrue, qtrue );
|
||||
|
||||
// get rid of any superfluous space between arguments
|
||||
if ( matchCount == 0 ) {
|
||||
return; // no matches
|
||||
*field->buffer = '\0';
|
||||
Field_AppendFirstArgs( field, Cmd_Argc() );
|
||||
field->cursor = strlen( field->buffer );
|
||||
}
|
||||
|
||||
field_t temp;
|
||||
Com_Memcpy( &temp, completionField, sizeof(field_t) );
|
||||
|
||||
if ( matchCount == 1 ) {
|
||||
Com_sprintf( completionField->buffer, sizeof( completionField->buffer ),
|
||||
#ifndef DEDICATED
|
||||
"\\%s", shortestMatch );
|
||||
#else
|
||||
"%s", shortestMatch );
|
||||
#endif
|
||||
if ( Cmd_Argc() == 1 ) {
|
||||
Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " );
|
||||
} else {
|
||||
ConcatRemaining( temp.buffer, completionString );
|
||||
// make sure we have a leading backslash
|
||||
if ( !String_HasLeadingSlash( field->buffer ) ) {
|
||||
const size_t length = strlen( field->buffer );
|
||||
if ( length + 1 < sizeof( field->buffer ) ) {
|
||||
memmove( field->buffer + 1, field->buffer, length + 1 );
|
||||
*field->buffer = '\\';
|
||||
field->cursor++;
|
||||
}
|
||||
completionField->cursor = strlen( completionField->buffer );
|
||||
return;
|
||||
}
|
||||
|
||||
// multiple matches, complete to shortest
|
||||
Com_sprintf( completionField->buffer, sizeof( completionField->buffer ),
|
||||
#ifndef DEDICATED
|
||||
"\\%s", shortestMatch );
|
||||
#else
|
||||
"%s", shortestMatch );
|
||||
#endif
|
||||
completionField->cursor = strlen( completionField->buffer );
|
||||
ConcatRemaining( temp.buffer, completionString );
|
||||
|
||||
Com_Printf( "]%s\n", completionField->buffer );
|
||||
|
||||
// run through again, printing matches
|
||||
Cmd_CommandCompletion( PrintMatches );
|
||||
Cvar_CommandCompletion( PrintCvarMatches );
|
||||
}
|
||||
|
||||
void Field_AutoComplete( field_t *field )
|
||||
|
||||
void Field_AutoCompleteMapName( int startArg, int compArg )
|
||||
{
|
||||
Field_CompleteCommand( field );
|
||||
FS_FilenameCompletion( "maps", "bsp", qtrue, FindMatches, 0 );
|
||||
if ( Field_CompleteShortestMatch( startArg, compArg ) )
|
||||
FS_FilenameCompletion( "maps", "bsp", qtrue, PrintMatches, 0 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Field_AutoCompleteConfigName( int startArg, int compArg )
|
||||
{
|
||||
FS_FilenameCompletion( "", "cfg", qtrue, FindMatches, FS_FILTER_INPAK );
|
||||
if ( Field_CompleteShortestMatch( startArg, compArg ) )
|
||||
FS_FilenameCompletion( "", "cfg", qtrue, PrintMatches, FS_FILTER_INPAK );
|
||||
}
|
||||
|
||||
|
||||
#define DEMO_EXT "dm_"STRINGIZE(PROTOCOL_VERSION)
|
||||
|
||||
|
||||
void Field_AutoCompleteDemoNameRead( int startArg, int compArg )
|
||||
{
|
||||
FS_FilenameCompletion( "demos", "dm_66", qtrue, FindMatches, 0 );
|
||||
FS_FilenameCompletion( "demos", "dm_67", qtrue, FindMatches, 0 );
|
||||
FS_FilenameCompletion( "demos", DEMO_EXT, qtrue, FindMatches, 0 );
|
||||
if ( Field_CompleteShortestMatch( startArg, compArg ) )
|
||||
{
|
||||
FS_FilenameCompletion( "demos", "dm_66", qtrue, PrintMatches, 0 );
|
||||
FS_FilenameCompletion( "demos", "dm_67", qtrue, PrintMatches, 0 );
|
||||
FS_FilenameCompletion( "demos", DEMO_EXT, qtrue, PrintMatches, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Field_AutoCompleteDemoNameWrite( int startArg, int compArg )
|
||||
{
|
||||
FS_FilenameCompletion( "demos", DEMO_EXT, qtrue, FindMatches, FS_FILTER_INPAK );
|
||||
if ( Field_CompleteShortestMatch( startArg, compArg ) )
|
||||
FS_FilenameCompletion( "demos", DEMO_EXT, qtrue, PrintMatches, FS_FILTER_INPAK );
|
||||
}
|
||||
|
||||
|
||||
#undef DEMO_EXT
|
||||
|
||||
|
||||
void Field_AutoCompleteKeyName( int startArg, int compArg )
|
||||
{
|
||||
Key_KeyNameCompletion( FindMatches );
|
||||
if ( Field_CompleteShortestMatch( startArg, compArg ) )
|
||||
Key_KeyNameCompletion( PrintMatches );
|
||||
}
|
||||
|
|
|
@ -398,6 +398,13 @@ qbool Cvar_Command()
|
|||
}
|
||||
|
||||
|
||||
static void Cvar_CompleteName( int startArg, int compArg )
|
||||
{
|
||||
if ( startArg + 1 == compArg )
|
||||
Field_AutoCompleteFrom( compArg, compArg, qfalse, qtrue );
|
||||
}
|
||||
|
||||
|
||||
// toggles a cvar for easy single key binding
|
||||
|
||||
static void Cvar_Toggle_f( void )
|
||||
|
@ -676,4 +683,10 @@ void Cvar_Init()
|
|||
Cmd_AddCommand( "reset", Cvar_Reset_f );
|
||||
Cmd_AddCommand( "cvarlist", Cvar_List_f );
|
||||
Cmd_AddCommand( "cvar_restart", Cvar_Restart_f );
|
||||
Cmd_SetAutoCompletion( "toggle", Cvar_CompleteName );
|
||||
Cmd_SetAutoCompletion( "set", Cvar_CompleteName );
|
||||
Cmd_SetAutoCompletion( "sets", Cvar_CompleteName );
|
||||
Cmd_SetAutoCompletion( "setu", Cvar_CompleteName );
|
||||
Cmd_SetAutoCompletion( "seta", Cvar_CompleteName );
|
||||
Cmd_SetAutoCompletion( "reset", Cvar_CompleteName );
|
||||
}
|
||||
|
|
|
@ -1668,7 +1668,7 @@ static int FS_AddFileToList( const char *name, char *list[MAX_FOUND_FILES], int
|
|||
Returns a uniqued list of files that match the given criteria
|
||||
from all search paths
|
||||
*/
|
||||
static char** FS_ListFilteredFiles( const char *path, const char *extension, const char* filter, int *numfiles )
|
||||
static char** FS_ListFilteredFiles( const char *path, const char *extension, const char* filter, int *numfiles, int filters )
|
||||
{
|
||||
int nfiles;
|
||||
char *list[MAX_FOUND_FILES];
|
||||
|
@ -1706,7 +1706,7 @@ static char** FS_ListFilteredFiles( const char *path, const char *extension, con
|
|||
//
|
||||
for (search = fs_searchpaths ; search ; search = search->next) {
|
||||
// is the element a pak file?
|
||||
if (search->pack) {
|
||||
if (search->pack && !(filters & FS_FILTER_INPAK)) {
|
||||
|
||||
//ZOID: If we are pure, don't search for files on paks that
|
||||
// aren't on the pure list
|
||||
|
@ -1757,7 +1757,7 @@ static char** FS_ListFilteredFiles( const char *path, const char *extension, con
|
|||
nfiles = FS_AddFileToList( name + temp, list, nfiles );
|
||||
}
|
||||
}
|
||||
} else if (search->dir) { // scan for files in the filesystem
|
||||
} else if (search->dir && !(filters & FS_FILTER_NOTINPAK)) { // scan for files in the filesystem
|
||||
char *netpath;
|
||||
int numSysFiles;
|
||||
char **sysFiles;
|
||||
|
@ -1800,7 +1800,7 @@ FS_ListFiles
|
|||
=================
|
||||
*/
|
||||
char **FS_ListFiles( const char *path, const char *extension, int *numfiles ) {
|
||||
return FS_ListFilteredFiles( path, extension, NULL, numfiles );
|
||||
return FS_ListFilteredFiles( path, extension, NULL, numfiles, 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2151,7 +2151,7 @@ static void FS_NewDir_f()
|
|||
|
||||
Com_Printf( "---------------\n" );
|
||||
|
||||
dirnames = FS_ListFilteredFiles( "", "", Cmd_Argv(1), &ndirs );
|
||||
dirnames = FS_ListFilteredFiles( "", "", Cmd_Argv(1), &ndirs, 0 );
|
||||
|
||||
FS_SortFileList(dirnames, ndirs);
|
||||
|
||||
|
@ -3051,7 +3051,7 @@ Handle based file calls for virtual machines
|
|||
========================================================================================
|
||||
*/
|
||||
|
||||
int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
|
||||
int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
|
||||
int r;
|
||||
qbool sync;
|
||||
|
||||
|
@ -3099,7 +3099,7 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int FS_FTell( fileHandle_t f ) {
|
||||
int FS_FTell( fileHandle_t f ) {
|
||||
int pos;
|
||||
if (fsh[f].zipFile == qtrue) {
|
||||
pos = unztell(fsh[f].handleFiles.file.z);
|
||||
|
@ -3109,18 +3109,18 @@ int FS_FTell( fileHandle_t f ) {
|
|||
return pos;
|
||||
}
|
||||
|
||||
void FS_Flush( fileHandle_t f ) {
|
||||
void FS_Flush( fileHandle_t f ) {
|
||||
fflush(fsh[f].handleFiles.file.o);
|
||||
}
|
||||
|
||||
void FS_FilenameCompletion( const char *dir, const char *ext,
|
||||
qbool stripExt, void(*callback)(const char *s) ) {
|
||||
void FS_FilenameCompletion( const char *dir, const char *ext, qbool stripExt,
|
||||
void(*callback)(const char *s), int filters ) {
|
||||
char **filenames;
|
||||
int nfiles;
|
||||
int i;
|
||||
char filename[ MAX_STRING_CHARS ];
|
||||
|
||||
filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles );
|
||||
filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles, filters );
|
||||
|
||||
FS_SortFileList( filenames, nfiles );
|
||||
|
||||
|
|
|
@ -175,6 +175,12 @@ typedef int clipHandle_t;
|
|||
|
||||
#define ARRAY_LEN(x) (sizeof(x) / sizeof(*(x)))
|
||||
|
||||
// #define VALUE 42
|
||||
// STRINGIZE_NE(VALUE) -> "VALUE"
|
||||
// STRINGIZE(VALUE) -> "42"
|
||||
#define STRINGIZE_NE(x) #x // no expansion
|
||||
#define STRINGIZE(x) STRINGIZE_NE(x) // with expansion
|
||||
|
||||
// angle indexes
|
||||
#define PITCH 0 // up / down
|
||||
#define YAW 1 // left / right
|
||||
|
|
|
@ -344,20 +344,26 @@ then searches for a command or variable that matches the first token.
|
|||
*/
|
||||
|
||||
typedef void (*xcommand_t) (void);
|
||||
typedef void (*xcommandCompletion_t) (int startArg, int compArg);
|
||||
|
||||
void Cmd_Init();
|
||||
|
||||
void Cmd_AddCommand( const char *cmd_name, xcommand_t function );
|
||||
// called by the init functions of other parts of the program to
|
||||
// register commands and functions to call for them.
|
||||
// The cmd_name is referenced later, so it should not be in temp memory
|
||||
// if function is NULL, the command will be forwarded to the server
|
||||
// as a clc_clientCommand instead of executed locally
|
||||
void Cmd_AddCommand( const char* cmd_name, xcommand_t function );
|
||||
|
||||
void Cmd_RemoveCommand( const char *cmd_name );
|
||||
void Cmd_RemoveCommand( const char* cmd_name );
|
||||
|
||||
void Cmd_CommandCompletion( void(*callback)(const char *s) );
|
||||
// auto-completion of command arguments
|
||||
void Cmd_SetAutoCompletion( const char* cmd_name, xcommandCompletion_t complete );
|
||||
void Cmd_AutoCompleteArgument( const char* cmd_name, int startArg, int compArg );
|
||||
|
||||
// auto-completion of the command's name
|
||||
// callback with each valid string
|
||||
void Cmd_CommandCompletion( void(*callback)(const char* s) );
|
||||
|
||||
// the functions that execute commands get their parameters with these
|
||||
// if arg > argc, Cmd_Argv() will return "", not NULL, so string ops are always safe
|
||||
|
@ -365,6 +371,8 @@ int Cmd_Argc();
|
|||
const char* Cmd_Argv(int arg);
|
||||
const char* Cmd_Args();
|
||||
const char* Cmd_ArgsFrom( int arg );
|
||||
qbool Cmd_ArgQuoted( int arg );
|
||||
int Cmd_ArgIndexFromOffset( int offset ); // offset into the Cmd_TokenizeString argument
|
||||
void Cmd_ArgvBuffer( int arg, char *buffer, int bufferLength );
|
||||
void Cmd_ArgsBuffer( char *buffer, int bufferLength );
|
||||
const char* Cmd_Cmd(); // note: this is NOT argv[0], it's the entire cmd as a raw string
|
||||
|
@ -626,8 +634,11 @@ void FS_Rename( const char *from, const char *to );
|
|||
void FS_Remove( const char *osPath );
|
||||
void FS_HomeRemove( const char *homePath );
|
||||
|
||||
void FS_FilenameCompletion( const char *dir, const char *ext,
|
||||
qbool stripExt, void(*callback)(const char *s) );
|
||||
#define FS_FILTER_INPAK (1 << 0)
|
||||
#define FS_FILTER_NOTINPAK (1 << 1)
|
||||
|
||||
void FS_FilenameCompletion( const char *dir, const char *ext, qbool stripExt,
|
||||
void (*callback)(const char *s), int filters );
|
||||
|
||||
|
||||
/*
|
||||
|
@ -647,7 +658,15 @@ typedef struct {
|
|||
} field_t;
|
||||
|
||||
void Field_Clear( field_t *edit );
|
||||
void Field_AutoComplete( field_t *edit );
|
||||
void Field_AutoComplete( field_t *edit ); // should only be called by Console_Key
|
||||
|
||||
// these are the functions you can use from your own command argument auto-completion callbacks
|
||||
void Field_AutoCompleteFrom( int startArg, int compArg, qbool searchCmds, qbool searchVars );
|
||||
void Field_AutoCompleteMapName( int startArg, int compArg );
|
||||
void Field_AutoCompleteConfigName( int startArg, int compArg );
|
||||
void Field_AutoCompleteDemoNameRead( int startArg, int compArg );
|
||||
void Field_AutoCompleteDemoNameWrite( int startArg, int compArg );
|
||||
void Field_AutoCompleteKeyName( int startArg, int compArg );
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
@ -853,6 +872,9 @@ void CL_FlushMemory();
|
|||
void CL_StartHunkUsers( void );
|
||||
// start all the client stuff using the hunk
|
||||
|
||||
void Key_KeyNameCompletion( void (*callback)(const char *s) );
|
||||
// for /bind and /unbind auto-completion
|
||||
|
||||
void Key_WriteBindings( fileHandle_t f );
|
||||
// for writing the config files
|
||||
|
||||
|
|
|
@ -178,6 +178,13 @@ static void SV_DevMap_f( )
|
|||
}
|
||||
|
||||
|
||||
static void SV_CompleteMap_f( int startArg, int compArg )
|
||||
{
|
||||
if ( startArg + 1 == compArg )
|
||||
Field_AutoCompleteMapName( startArg, compArg );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Completely restarts a level, but doesn't send a new gamestate to the clients.
|
||||
This allows fair starts with variable load times.
|
||||
|
@ -690,6 +697,8 @@ void SV_AddOperatorCommands()
|
|||
Cmd_AddCommand ("sectorlist", SV_SectorList_f);
|
||||
Cmd_AddCommand ("map", SV_Map_f);
|
||||
Cmd_AddCommand ("devmap", SV_DevMap_f);
|
||||
Cmd_SetAutoCompletion ("map", SV_CompleteMap_f);
|
||||
Cmd_SetAutoCompletion ("devmap", SV_CompleteMap_f);
|
||||
Cmd_AddCommand ("killserver", SV_KillServer_f);
|
||||
Cmd_AddCommand ("sv_restart", SV_ServerRestart_f );
|
||||
if( com_dedicated->integer ) {
|
||||
|
|
Loading…
Reference in a new issue