diff options
author | Tim Angus <tim@ngus.net> | 2006-01-24 05:04:21 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2006-01-24 05:04:21 +0000 |
commit | 608a95f42c08146d7e85fa876476d98365339a32 (patch) | |
tree | bb413c295ce51aa6648090e9856c399989a5e2f4 /src | |
parent | 470f5cc7203a148289d6ad6f0f5c7b4d80a48d50 (diff) |
* Merged ioq3-r522
- i586 is now default -march
- Couple of OpenAL "bug" fixes
- Fancy autocompletion
- Delete key on *nix fixed
- Client now sleeps when inactive
- Persistent console history
Diffstat (limited to 'src')
-rw-r--r-- | src/client/cl_console.c | 1 | ||||
-rw-r--r-- | src/client/cl_keys.c | 119 | ||||
-rw-r--r-- | src/client/client.h | 2 | ||||
-rw-r--r-- | src/client/snd_codec.c | 2 | ||||
-rw-r--r-- | src/client/snd_codec_ogg.c | 2 | ||||
-rw-r--r-- | src/client/snd_openal.c | 43 | ||||
-rw-r--r-- | src/qcommon/cmd.c | 23 | ||||
-rw-r--r-- | src/qcommon/common.c | 275 | ||||
-rw-r--r-- | src/qcommon/cvar.c | 25 | ||||
-rw-r--r-- | src/qcommon/files.c | 23 | ||||
-rw-r--r-- | src/qcommon/q_math.c | 22 | ||||
-rw-r--r-- | src/qcommon/q_shared.c | 99 | ||||
-rw-r--r-- | src/qcommon/q_shared.h | 6 | ||||
-rw-r--r-- | src/qcommon/qcommon.h | 5 | ||||
-rw-r--r-- | src/unix/unix_main.c | 44 |
15 files changed, 587 insertions, 104 deletions
diff --git a/src/client/cl_console.c b/src/client/cl_console.c index efbf2d17..22a148a1 100644 --- a/src/client/cl_console.c +++ b/src/client/cl_console.c @@ -312,6 +312,7 @@ void Con_Init (void) { Field_Clear( &historyEditLines[i] ); historyEditLines[i].widthInChars = g_console_field_width; } + CL_LoadConsoleHistory( ); Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); Cmd_AddCommand ("messagemode", Con_MessageMode_f); diff --git a/src/client/cl_keys.c b/src/client/cl_keys.c index f80c24c3..232f04a4 100644 --- a/src/client/cl_keys.c +++ b/src/client/cl_keys.c @@ -484,10 +484,10 @@ void Console_Key (int key) { // enter finishes the line if ( key == K_ENTER || key == K_KP_ENTER ) { - // if not in the game explicitly prepent a slash if needed + // if not in the game explicitly prepend a slash if needed if ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\' && g_consoleField.buffer[0] != '/' ) { - char temp[MAX_STRING_CHARS]; + char temp[MAX_EDIT_LINE-1]; Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) ); Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp ); @@ -520,6 +520,8 @@ void Console_Key (int key) { g_consoleField.widthInChars = g_console_field_width; + CL_SaveConsoleHistory( ); + if ( cls.state == CA_DISCONNECTED ) { SCR_UpdateScreen (); // force an update, because the command } // may take some time @@ -529,7 +531,7 @@ void Console_Key (int key) { // command completion if (key == K_TAB) { - Field_CompleteCommand(&g_consoleField); + Field_AutoComplete(&g_consoleField); return; } @@ -1210,6 +1212,12 @@ void CL_CharEvent( int key ) { return; } + // delete is not a printable character and is + // otherwise handled by Field_KeyDownEvent + if ( key == 127 ) { + return; + } + // distribute the key down event to the apropriate handler if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { @@ -1294,3 +1302,108 @@ Ket_SetCatcher void Key_SetCatcher( int catcher ) { cls.keyCatchers = catcher; } + +// This must not exceed MAX_CMD_LINE +#define MAX_CONSOLE_SAVE_BUFFER 1024 +static char consoleSaveBuffer[ MAX_CONSOLE_SAVE_BUFFER ]; + +/* +================ +CL_LoadConsoleHistory + +Load the console history from cl_consoleHistory +================ +*/ +void CL_LoadConsoleHistory( void ) +{ + char *token, *text_p; + int i, numChars, numLines = 0; + cvar_t *cv; + + cv = Cvar_Get( "cl_consoleHistory", "", CVAR_ARCHIVE|CVAR_ROM ); + Q_strncpyz( consoleSaveBuffer, cv->string, MAX_CONSOLE_SAVE_BUFFER ); + + text_p = consoleSaveBuffer; + + for( i = COMMAND_HISTORY - 1; i >= 0; i-- ) + { + if( !*( token = COM_Parse( &text_p ) ) ) + break; + + historyEditLines[ i ].cursor = atoi( token ); + + if( !*( token = COM_Parse( &text_p ) ) ) + break; + + historyEditLines[ i ].scroll = atoi( token ); + + if( !*( token = COM_Parse( &text_p ) ) ) + break; + + numChars = atoi( token ); + text_p++; + if( numChars > ( strlen( consoleSaveBuffer ) - ( text_p - consoleSaveBuffer ) ) ) + { + Com_DPrintf( S_COLOR_YELLOW "WARNING: probable corrupt history\n" ); + break; + } + Com_Memcpy( historyEditLines[ i ].buffer, + text_p, numChars ); + historyEditLines[ i ].buffer[ numChars ] = '\0'; + text_p += numChars; + + numLines++; + } + + memmove( &historyEditLines[ 0 ], &historyEditLines[ i + 1 ], + numLines * sizeof( field_t ) ); + for( i = numLines; i < COMMAND_HISTORY; i++ ) + Field_Clear( &historyEditLines[ i ] ); + + historyLine = nextHistoryLine = numLines; +} + +/* +================ +CL_SaveConsoleHistory + +Save the console history into the cvar cl_consoleHistory +so that it persists across invocations of q3 +================ +*/ +void CL_SaveConsoleHistory( void ) +{ + int i; + int lineLength, saveBufferLength, additionalLength; + + consoleSaveBuffer[ 0 ] = '\0'; + + i = ( nextHistoryLine - 1 ) % COMMAND_HISTORY; + do + { + if( historyEditLines[ i ].buffer[ 0 ] ) + { + lineLength = strlen( historyEditLines[ i ].buffer ); + saveBufferLength = strlen( consoleSaveBuffer ); + + //ICK "seta cl_consoleHistory " + "%d %d %d " = 23 + 13 = 36 + additionalLength = lineLength + 36; + + if( saveBufferLength + additionalLength < MAX_CONSOLE_SAVE_BUFFER ) + { + Q_strcat( consoleSaveBuffer, MAX_CONSOLE_SAVE_BUFFER, + va( "%d %d %d %s ", + historyEditLines[ i ].cursor, + historyEditLines[ i ].scroll, + lineLength, + historyEditLines[ i ].buffer ) ); + } + else + break; + } + i = ( i - 1 + COMMAND_HISTORY ) % COMMAND_HISTORY; + } + while( i != ( nextHistoryLine - 1 ) % COMMAND_HISTORY ); + + Cvar_Set( "cl_consoleHistory", consoleSaveBuffer ); +} diff --git a/src/client/client.h b/src/client/client.h index fb1ecea1..f0aa6e8e 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -454,6 +454,8 @@ void Con_Top( void ); void Con_Bottom( void ); void Con_Close( void ); +void CL_LoadConsoleHistory( void ); +void CL_SaveConsoleHistory( void ); // // cl_scrn.c diff --git a/src/client/snd_codec.c b/src/client/snd_codec.c index e1c6bb47..98fae65f 100644 --- a/src/client/snd_codec.c +++ b/src/client/snd_codec.c @@ -98,7 +98,7 @@ void S_CodecInit() { codecs = NULL; S_CodecRegister(&wav_codec); -#ifdef USE_CODEC_VORBIS +#if USE_CODEC_VORBIS S_CodecRegister(&ogg_codec); #endif } diff --git a/src/client/snd_codec_ogg.c b/src/client/snd_codec_ogg.c index 20462fcb..464d8d38 100644 --- a/src/client/snd_codec_ogg.c +++ b/src/client/snd_codec_ogg.c @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // OGG support is enabled by this define -#ifdef USE_CODEC_VORBIS +#if USE_CODEC_VORBIS // includes for the Q3 sound system #include "client.h" diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c index e8b0915d..01b965ae 100644 --- a/src/client/snd_openal.c +++ b/src/client/snd_openal.c @@ -39,6 +39,7 @@ cvar_t *s_alDopplerSpeed; cvar_t *s_alMinDistance; cvar_t *s_alRolloff; cvar_t *s_alDriver; +cvar_t *s_alMaxSpeakerDistance; /* ================= @@ -469,6 +470,7 @@ typedef struct src_s static src_t srcList[MAX_SRC]; static int srcCount = 0; static qboolean alSourcesInitialised = qfalse; +static vec3_t lastListenerOrigin = { 0.0f, 0.0f, 0.0f }; typedef struct sentity_s { @@ -487,6 +489,22 @@ static sentity_t entityList[MAX_GENTITIES]; /* ================= +S_AL_SanitiseVector +================= +*/ +#define S_AL_SanitiseVector(v) _S_AL_SanitiseVector(v,__LINE__) +static void _S_AL_SanitiseVector( vec3_t v, int line ) +{ + if( Q_isnan( v[ 0 ] ) || Q_isnan( v[ 1 ] ) || Q_isnan( v[ 2 ] ) ) + { + Com_DPrintf( S_COLOR_YELLOW "WARNING: vector with one or more NaN components " + "being passed to OpenAL at %s:%d -- zeroing\n", __FILE__, line ); + VectorClear( v ); + } +} + +/* +================= S_AL_SrcInit ================= */ @@ -762,6 +780,7 @@ S_AL_UpdateEntityPosition static void S_AL_UpdateEntityPosition( int entityNum, const vec3_t origin ) { + S_AL_SanitiseVector( (vec_t *)origin ); if ( entityNum < 0 || entityNum > MAX_GENTITIES ) Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum ); VectorCopy( origin, entityList[entityNum].origin ); @@ -816,6 +835,7 @@ void S_AL_StartSound( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx } else VectorCopy( origin, sorigin ); + S_AL_SanitiseVector( sorigin ); qalSourcefv(srcList[src].alSource, AL_POSITION, sorigin); // Start it playing @@ -896,7 +916,9 @@ S_AL_AddLoopingSound static void S_AL_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) { - S_AL_SrcLoop(SRCPRI_AMBIENT, sfx, origin, velocity, entityNum); + S_AL_SanitiseVector( (vec_t *)origin ); + S_AL_SanitiseVector( (vec_t *)velocity ); + S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum); } /* @@ -907,7 +929,17 @@ S_AL_AddRealLoopingSound static void S_AL_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) { - S_AL_SrcLoop(SRCPRI_ENTITY, sfx, origin, velocity, entityNum); + S_AL_SanitiseVector( (vec_t *)origin ); + S_AL_SanitiseVector( (vec_t *)velocity ); + + // There are certain maps (*cough* Q3:TA mpterra*) that have large quantities + // of ET_SPEAKERS in the PVS at any given time. OpenAL can't cope with mixing + // large numbers of sounds, so this culls them by distance + if( DistanceSquared( origin, lastListenerOrigin ) > + s_alMaxSpeakerDistance->value * s_alMaxSpeakerDistance->value ) + return; + + S_AL_SrcLoop(SRCPRI_AMBIENT, sfx, origin, velocity, entityNum); } /* @@ -1429,12 +1461,18 @@ S_AL_Respatialize static void S_AL_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) { + S_AL_SanitiseVector( (vec_t *)origin ); + S_AL_SanitiseVector( axis[ 0 ] ); + S_AL_SanitiseVector( axis[ 1 ] ); + S_AL_SanitiseVector( axis[ 2 ] ); // Axis[0] = Forward // Axis[2] = Up float velocity[] = {0.0f, 0.0f, 0.0f}; float orientation[] = {axis[0][0], axis[0][1], axis[0][2], axis[2][0], axis[2][1], axis[2][2]}; + VectorCopy( origin, lastListenerOrigin ); + // Set OpenAL listener paramaters qalListenerfv(AL_POSITION, (ALfloat *)origin); qalListenerfv(AL_VELOCITY, velocity); @@ -1592,6 +1630,7 @@ qboolean S_AL_Init( soundInterface_t *si ) s_alDopplerSpeed = Cvar_Get( "s_alDopplerSpeed", "2200", CVAR_ARCHIVE ); s_alMinDistance = Cvar_Get( "s_alMinDistance", "120", CVAR_CHEAT ); s_alRolloff = Cvar_Get( "s_alRolloff", "0.8", CVAR_CHEAT ); + s_alMaxSpeakerDistance = Cvar_Get( "s_alMaxSpeakerDistance", "1024", CVAR_ARCHIVE ); s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE ); diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c index a3053c89..7495bf1c 100644 --- a/src/qcommon/cmd.c +++ b/src/qcommon/cmd.c @@ -477,7 +477,7 @@ will point into this temporary buffer. */ // NOTE TTimo define that to track tokenization issues //#define TKN_DBG -void Cmd_TokenizeString( const char *text_in ) { +static void Cmd_TokenizeString2( const char *text_in, qboolean ignoreQuotes ) { const char *text; char *textOut; @@ -534,7 +534,7 @@ void Cmd_TokenizeString( const char *text_in ) { // handle quoted strings // NOTE TTimo this doesn't handle \" escaping - if ( *text == '"' ) { + if ( !ignoreQuotes && *text == '"' ) { cmd.argv[cmd.argc] = textOut; cmd.argc++; text++; @@ -555,7 +555,7 @@ void Cmd_TokenizeString( const char *text_in ) { // skip until whitespace, quote, or command while ( *text > ' ' ) { - if ( text[0] == '"' ) { + if ( !ignoreQuotes && text[0] == '"' ) { break; } @@ -580,6 +580,23 @@ void Cmd_TokenizeString( const char *text_in ) { } +/* +============ +Cmd_TokenizeString +============ +*/ +void Cmd_TokenizeString( const char *text_in ) { + Cmd_TokenizeString2( text_in, qfalse ); +} + +/* +============ +Cmd_TokenizeStringIgnoreQuotes +============ +*/ +void Cmd_TokenizeStringIgnoreQuotes( const char *text_in ) { + Cmd_TokenizeString2( text_in, qtrue ); +} /* ============ diff --git a/src/qcommon/common.c b/src/qcommon/common.c index a0a66ae7..85cef699 100644 --- a/src/qcommon/common.c +++ b/src/qcommon/common.c @@ -2774,7 +2774,7 @@ void Field_Clear( field_t *edit ) { static const char *completionString; static char shortestMatch[MAX_TOKEN_CHARS]; static int matchCount; -// field we are working on, passed to Field_CompleteCommand (&g_consoleCommand for instance) +// field we are working on, passed to Field_AutoComplete(&g_consoleCommand for instance) static field_t *completionField; /* @@ -2796,7 +2796,12 @@ static void FindMatches( const char *s ) { } // cut shortestMatch to the amount common with s - for ( i = 0 ; s[i] ; i++ ) { + for ( i = 0 ; shortestMatch[i] ; i++ ) { + if ( i >= strlen( s ) ) { + shortestMatch[i] = 0; + break; + } + if ( tolower(shortestMatch[i]) != tolower(s[i]) ) { shortestMatch[i] = 0; } @@ -2805,11 +2810,11 @@ static void FindMatches( const char *s ) { /* =============== -PrintCmdMatches +PrintMatches =============== */ -static void PrintCmdMatches( const char *s ) { +static void PrintMatches( const char *s ) { if ( !Q_stricmpn( s, shortestMatch, strlen( shortestMatch ) ) ) { Com_Printf( " %s\n", s ); } @@ -2822,101 +2827,239 @@ PrintCvarMatches =============== */ static void PrintCvarMatches( const char *s ) { + char value[ TRUNCATE_LENGTH ]; + if ( !Q_stricmpn( s, shortestMatch, strlen( shortestMatch ) ) ) { - Com_Printf( " %s = \"%s\"\n", s, Cvar_VariableString( s ) ); + Com_TruncateLongString( value, Cvar_VariableString( s ) ); + Com_Printf( " %s = \"%s\"\n", s, value ); } } -static void keyConcatArgs( void ) { - int i; - char *arg; +/* +=============== +Field_FindFirstSeparator +=============== +*/ +static char *Field_FindFirstSeparator( char *s ) +{ + int i; - 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 ), "\""); - } + for( i = 0; i < strlen( s ); i++ ) + { + if( s[ i ] == ';' ) + return &s[ i ]; } + + return NULL; } -static void ConcatRemaining( const char *src, const char *start ) { - char *str; +/* +=============== +Field_CompleteFilename +=============== +*/ +static void Field_CompleteFilename( const char *dir, + const char *ext, qboolean stripExt ) +{ + matchCount = 0; + shortestMatch[ 0 ] = 0; - str = strstr(src, start); - if (!str) { - keyConcatArgs(); + 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; } - str += strlen(start); - Q_strcat( completionField->buffer, sizeof( completionField->buffer ), str); + Com_Printf( "]%s\n", completionField->buffer ); + + FS_FilenameCompletion( dir, ext, stripExt, PrintMatches ); } /* =============== Field_CompleteCommand - -perform Tab expansion -NOTE TTimo this was originally client code only - moved to common code when writing tty console for *nix dedicated server =============== */ -void Field_CompleteCommand( field_t *field ) { - field_t temp; +static void Field_CompleteCommand( char *cmd, + qboolean doCommands, qboolean doCvars ) +{ + int completionArgument = 0; + char *p; - completionField = field; + // Skip leading whitespace and quotes + cmd = Com_SkipCharset( cmd, " \"" ); - // only look at the first token for completion purposes - Cmd_TokenizeString( completionField->buffer ); + Cmd_TokenizeStringIgnoreQuotes( cmd ); + completionArgument = Cmd_Argc( ); - completionString = Cmd_Argv(0); - if ( completionString[0] == '\\' || completionString[0] == '/' ) { - completionString++; + // If there is trailing whitespace on the cmd + if( *( cmd + strlen( cmd ) - 1 ) == ' ' ) + { + completionString = ""; + completionArgument++; } - matchCount = 0; - shortestMatch[0] = 0; + else + completionString = Cmd_Argv( completionArgument - 1 ); - if ( strlen( completionString ) == 0 ) { - return; - } + 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; - Cmd_CommandCompletion( FindMatches ); - Cvar_CommandCompletion( FindMatches ); + baseCmd++; + } +#endif - if ( matchCount == 0 ) { - return; // no matches + 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++; - Com_Memcpy(&temp, completionField, sizeof(field_t)); + matchCount = 0; + shortestMatch[ 0 ] = 0; - if ( matchCount == 1 ) { - Com_sprintf( completionField->buffer, sizeof( completionField->buffer ), "\\%s", shortestMatch ); - if ( Cmd_Argc() == 1 ) { - Q_strcat( completionField->buffer, sizeof( completionField->buffer ), " " ); - } else { - ConcatRemaining( temp.buffer, completionString ); + 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 ); - return; + + 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 ); } +} - // multiple matches, complete to shortest - Com_sprintf( completionField->buffer, sizeof( completionField->buffer ), "\\%s", shortestMatch ); - completionField->cursor = strlen( completionField->buffer ); - ConcatRemaining( temp.buffer, completionString ); +/* +=============== +Field_AutoComplete - Com_Printf( "]%s\n", completionField->buffer ); +Perform Tab expansion +=============== +*/ +void Field_AutoComplete( field_t *field ) +{ + completionField = field; - // run through again, printing matches - Cmd_CommandCompletion( PrintCmdMatches ); - Cvar_CommandCompletion( PrintCvarMatches ); + Field_CompleteCommand( completionField->buffer, qtrue, qtrue ); } diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c index 839f41ce..a306d887 100644 --- a/src/qcommon/cvar.c +++ b/src/qcommon/cvar.c @@ -470,7 +470,10 @@ Handles variable inspection and changing from the console ============ */ qboolean Cvar_Command( void ) { - cvar_t *v; + cvar_t *v; + char string[ TRUNCATE_LENGTH ]; + char resetString[ TRUNCATE_LENGTH ]; + char latchedString[ TRUNCATE_LENGTH ]; // check variables v = Cvar_FindVar (Cmd_Argv(0)); @@ -480,9 +483,13 @@ qboolean Cvar_Command( void ) { // perform a variable print or set if ( Cmd_Argc() == 1 ) { - Com_Printf ("\"%s\" is:\"%s" S_COLOR_WHITE "\" default:\"%s" S_COLOR_WHITE "\"\n", v->name, v->string, v->resetString ); + Com_TruncateLongString( string, v->string ); + Com_TruncateLongString( resetString, v->resetString ); + Com_Printf ("\"%s\" is:\"%s" S_COLOR_WHITE "\" default:\"%s" S_COLOR_WHITE "\"\n", + v->name, string, resetString ); if ( v->latchedString ) { - Com_Printf( "latched: \"%s\"\n", v->latchedString ); + Com_TruncateLongString( latchedString, v->latchedString ); + Com_Printf( "latched: \"%s\"\n", latchedString ); } return qtrue; } @@ -643,11 +650,21 @@ void Cvar_WriteVariables( fileHandle_t f ) { if( var->flags & CVAR_ARCHIVE ) { // write the latched value, even if it hasn't taken effect yet if ( var->latchedString ) { + if( strlen( var->name ) + strlen( var->latchedString ) + 10 > sizeof( buffer ) ) { + Com_Printf( S_COLOR_YELLOW "WARNING: value of variable " + "\"%s\" too long to write to file\n", var->name ); + continue; + } Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->latchedString); } else { + if( strlen( var->name ) + strlen( var->string ) + 10 > sizeof( buffer ) ) { + Com_Printf( S_COLOR_YELLOW "WARNING: value of variable " + "\"%s\" too long to write to file\n", var->name ); + continue; + } Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->string); } - FS_Printf (f, "%s", buffer); + FS_Write( buffer, strlen( buffer ), f ); } } } diff --git a/src/qcommon/files.c b/src/qcommon/files.c index 14db75c7..b24b36fd 100644 --- a/src/qcommon/files.c +++ b/src/qcommon/files.c @@ -3361,3 +3361,26 @@ void FS_Flush( fileHandle_t f ) { fflush(fsh[f].handleFiles.file.o); } +void FS_FilenameCompletion( const char *dir, const char *ext, + qboolean stripExt, void(*callback)(const char *s) ) { + char **filenames; + int nfiles; + int i; + char filename[ MAX_STRING_CHARS ]; + + filenames = FS_ListFilteredFiles( dir, ext, NULL, &nfiles ); + + FS_SortFileList( filenames, nfiles ); + + for( i = 0; i < nfiles; i++ ) { + FS_ConvertPath( filenames[ i ] ); + Q_strncpyz( filename, filenames[ i ], MAX_STRING_CHARS ); + + if( stripExt ) { + COM_StripExtension( filename, filename ); + } + + callback( filename ); + } + FS_FreeFileList( filenames ); +} diff --git a/src/qcommon/q_math.c b/src/qcommon/q_math.c index bf209562..196d2f55 100644 --- a/src/qcommon/q_math.c +++ b/src/qcommon/q_math.c @@ -1538,3 +1538,25 @@ vec_t DistanceBetweenLineSegments( return (vec_t)sqrt( DistanceBetweenLineSegmentsSquared( sP0, sP1, tP0, tP1, s, t ) ); } + +/* +================= +Q_isnan + +Don't pass doubles to this +================ +*/ +int Q_isnan( float x ) +{ + union + { + float f; + unsigned int i; + } t; + + t.f = x; + t.i &= 0x7FFFFFFF; + t.i = 0x7F800000 - t.i; + + return (int)( (unsigned int)t.i >> 31 ); +} diff --git a/src/qcommon/q_shared.c b/src/qcommon/q_shared.c index 091847ca..9f152d62 100644 --- a/src/qcommon/q_shared.c +++ b/src/qcommon/q_shared.c @@ -60,10 +60,19 @@ COM_StripExtension ============ */ void COM_StripExtension( const char *in, char *out ) { - while ( *in && *in != '.' ) { - *out++ = *in++; + int length; + + strcpy( out, in ); + + length = strlen(out)-1; + while (length > 0 && out[length] != '.') + { + length--; + if (out[length] == '/') + return; // no extension } - *out = 0; + if (length) + out[length] = 0; } @@ -910,6 +919,26 @@ char * QDECL va( char *format, ... ) { return buf; } +/* +============ +Com_TruncateLongString + +Assumes buffer is atleast TRUNCATE_LENGTH big +============ +*/ +void Com_TruncateLongString( char *buffer, const char *s ) +{ + int length = strlen( s ); + + if( length <= TRUNCATE_LENGTH ) + Q_strncpyz( buffer, s, TRUNCATE_LENGTH ); + else + { + Q_strncpyz( buffer, s, ( TRUNCATE_LENGTH / 2 ) - 3 ); + Q_strcat( buffer, TRUNCATE_LENGTH, " ... " ); + Q_strcat( buffer, TRUNCATE_LENGTH, s + length - ( TRUNCATE_LENGTH / 2 ) + 3 ); + } +} /* ===================================================================== @@ -1250,4 +1279,68 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) { //==================================================================== +/* +================== +Com_CharIsOneOfCharset +================== +*/ +static qboolean Com_CharIsOneOfCharset( char c, char *set ) +{ + int i; + + for( i = 0; i < strlen( set ); i++ ) + { + if( set[ i ] == c ) + return qtrue; + } + + return qfalse; +} + +/* +================== +Com_SkipCharset +================== +*/ +char *Com_SkipCharset( char *s, char *sep ) +{ + char *p = s; + + while( p ) + { + if( Com_CharIsOneOfCharset( *p, sep ) ) + p++; + else + break; + } + + return p; +} + +/* +================== +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; + } + + if( sepCount == numTokens ) + return p; + else + return s; +} diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index 3955e2c4..a55689e7 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -585,6 +585,7 @@ void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]); void VectorMatrixMultiply( const vec3_t p, vec3_t m[ 3 ], vec3_t out ); void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); void PerpendicularVector( vec3_t dst, const vec3_t src ); +int Q_isnan( float x ); void GetPerpendicularViewVector( const vec3_t point, const vec3_t p1, const vec3_t p2, vec3_t up ); @@ -663,6 +664,8 @@ void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m); void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...); +char *Com_SkipTokens( char *s, int numTokens, char *sep ); +char *Com_SkipCharset( char *s, char *sep ); // mode parm for FS_FOpenFile typedef enum { @@ -733,6 +736,9 @@ void Swap_Init (void); */ char * QDECL va(char *format, ...); +#define TRUNCATE_LENGTH 64 +void Com_TruncateLongString( char *buffer, const char *s ); + //============================================= // diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index 7e14ad11..e2382cc6 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -410,6 +410,7 @@ char *Cmd_Cmd (void); // if arg > argc, so string operations are allways safe. void Cmd_TokenizeString( const char *text ); +void Cmd_TokenizeStringIgnoreQuotes( const char *text_in ); // Takes a null terminated string. Does not need to be /n terminated. // breaks the string up into arg tokens. @@ -654,6 +655,8 @@ 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, + qboolean stripExt, void(*callback)(const char *s) ); /* ============================================================== @@ -671,7 +674,7 @@ typedef struct { } field_t; void Field_Clear( field_t *edit ); -void Field_CompleteCommand( field_t *edit ); +void Field_AutoComplete( field_t *edit ); /* ============================================================== diff --git a/src/unix/unix_main.c b/src/unix/unix_main.c index d5b69ffb..156407e0 100644 --- a/src/unix/unix_main.c +++ b/src/unix/unix_main.c @@ -550,7 +550,6 @@ char *Sys_ConsoleInput(void) { // we use this when sending back commands static char text[256]; - int i; int avail; char key; field_t *history; @@ -589,22 +588,7 @@ char *Sys_ConsoleInput(void) if (key == '\t') { tty_Hide(); - Field_CompleteCommand( &tty_con ); - // Field_CompleteCommand does weird things to the string, do a cleanup - // it adds a '\' at the beginning of the string - // cursor doesn't reflect actual length of the string that's sent back - tty_con.cursor = strlen(tty_con.buffer); - if (tty_con.cursor>0) - { - if (tty_con.buffer[0] == '\\') - { - for (i=0; i<=tty_con.cursor; i++) - { - tty_con.buffer[i] = tty_con.buffer[i+1]; - } - tty_con.cursor--; - } - } + Field_AutoComplete( &tty_con ); tty_Show(); return NULL; } @@ -1238,6 +1222,7 @@ void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize ) int msgLength, pos; int i, j; char *escapeCode; + char tempBuffer[ 7 ]; if( !msg || !buffer ) return; @@ -1251,7 +1236,8 @@ void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize ) { if( msg[ i ] == '\n' ) { - strncat( buffer, va( "%c[0m\n", 0x1B ), bufferSize ); + Com_sprintf( tempBuffer, 7, "%c[0m\n", 0x1B ); + strncat( buffer, tempBuffer, bufferSize ); i++; } else if( msg[ i ] == Q_COLOR_ESCAPE ) @@ -1271,13 +1257,19 @@ void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize ) } if( escapeCode ) - strncat( buffer, va( "%c[%sm", 0x1B, escapeCode ), bufferSize ); + { + Com_sprintf( tempBuffer, 7, "%c[%sm", 0x1B, escapeCode ); + strncat( buffer, tempBuffer, bufferSize ); + } i++; } } else - strncat( buffer, va( "%c", msg[ i++ ] ), bufferSize ); + { + Com_sprintf( tempBuffer, 7, "%c", msg[ i++ ] ); + strncat( buffer, tempBuffer, bufferSize ); + } } } @@ -1409,6 +1401,18 @@ int main ( int argc, char* argv[] ) while (1) { +#if !defined( DEDICATED ) && USE_SDL_VIDEO + int appState = SDL_GetAppState( ); + + // If we have no input focus at all, sleep a bit + if( !( appState & ( SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS ) ) ) + usleep( 16000 ); + + // If we're minimised, sleep a bit more + if( !( appState & SDL_APPACTIVE ) ) + usleep( 32000 ); +#endif + #ifdef __linux__ Sys_ConfigureFPU(); #endif |