mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-11-09 03:49:12 +01:00
5e0a0765ce
The `.editorconfig` file in this repo is configured to trim all trailing whitespace regardless of whether the line is modified. Trims all trailing whitespace in the repository to make the codebase easier to work with in editors that respect `.editorconfig`. `git blame` becomes less useful on these lines but it already isn't very useful. Commands: ``` find . -type f -name '*.h' -exec sed --in-place 's/[[:space:]]\+$//' {} \+ find . -type f -name '*.c' -exec sed --in-place 's/[[:space:]]\+$//' {} \+ ```
499 lines
8.3 KiB
C
499 lines
8.3 KiB
C
/*
|
|
infostring.c - network info strings
|
|
Copyright (C) 2008 Uncle Mike
|
|
|
|
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 3 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.
|
|
*/
|
|
|
|
#include "common.h"
|
|
|
|
#define MAX_KV_SIZE 128
|
|
|
|
/*
|
|
=======================================================================
|
|
|
|
INFOSTRING STUFF
|
|
|
|
=======================================================================
|
|
*/
|
|
/*
|
|
===============
|
|
Info_Print
|
|
|
|
printing current key-value pair
|
|
===============
|
|
*/
|
|
void Info_Print( const char *s )
|
|
{
|
|
char key[MAX_KV_SIZE];
|
|
char value[MAX_KV_SIZE];
|
|
int l, count;
|
|
char *o;
|
|
|
|
if( *s == '\\' ) s++;
|
|
|
|
while( *s )
|
|
{
|
|
count = 0;
|
|
o = key;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
|
|
l = o - key;
|
|
if( l < 20 )
|
|
{
|
|
memset( o, ' ', 20 - l );
|
|
key[20] = 0;
|
|
}
|
|
else *o = 0;
|
|
|
|
Con_Printf( "%s", key );
|
|
|
|
if( !*s )
|
|
{
|
|
Con_Printf( "(null)\n" );
|
|
return;
|
|
}
|
|
|
|
count = 0;
|
|
o = value;
|
|
s++;
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
|
|
if( *s ) s++;
|
|
Con_Printf( "%s\n", value );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Info_IsValid
|
|
|
|
check infostring for potential problems
|
|
==============
|
|
*/
|
|
qboolean Info_IsValid( const char *s )
|
|
{
|
|
char key[MAX_KV_SIZE];
|
|
char value[MAX_KV_SIZE];
|
|
int count;
|
|
char *o;
|
|
|
|
if( *s == '\\' ) s++;
|
|
|
|
while( *s )
|
|
{
|
|
count = 0;
|
|
o = key;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
|
|
if( !*s ) return false;
|
|
|
|
count = 0;
|
|
o = value;
|
|
s++;
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
|
|
if( !COM_CheckStringEmpty( value ) )
|
|
return false;
|
|
|
|
if( *s ) s++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if !XASH_DEDICATED
|
|
/*
|
|
==============
|
|
Info_WriteVars
|
|
|
|
==============
|
|
*/
|
|
void Info_WriteVars( file_t *f )
|
|
{
|
|
char *s = CL_Userinfo();
|
|
char pkey[MAX_SERVERINFO_STRING];
|
|
static char value[4][MAX_SERVERINFO_STRING]; // use two buffers so compares work without stomping on each other
|
|
static int valueindex;
|
|
convar_t *pcvar;
|
|
char *o;
|
|
|
|
valueindex = (valueindex + 1) % 4;
|
|
if( *s == '\\' ) s++;
|
|
|
|
while( 1 )
|
|
{
|
|
o = pkey;
|
|
while( *s != '\\' )
|
|
{
|
|
if( !*s ) return;
|
|
*o++ = *s++;
|
|
}
|
|
*o = 0;
|
|
s++;
|
|
|
|
o = value[valueindex];
|
|
|
|
while( *s != '\\' && *s )
|
|
{
|
|
if( !*s ) return;
|
|
*o++ = *s++;
|
|
}
|
|
*o = 0;
|
|
|
|
pcvar = Cvar_FindVar( pkey );
|
|
|
|
if( !pcvar && pkey[0] != '*' ) // don't store out star keys
|
|
FS_Printf( f, "setinfo \"%s\" \"%s\"\n", pkey, value[valueindex] );
|
|
|
|
if( !*s ) return;
|
|
s++;
|
|
}
|
|
}
|
|
#endif // XASH_DEDICATED
|
|
|
|
/*
|
|
===============
|
|
Info_ValueForKey
|
|
|
|
Searches the string for the given
|
|
key and returns the associated value, or an empty string.
|
|
===============
|
|
*/
|
|
const char *Info_ValueForKey( const char *s, const char *key )
|
|
{
|
|
char pkey[MAX_KV_SIZE];
|
|
static char value[4][MAX_KV_SIZE]; // use two buffers so compares work without stomping on each other
|
|
static int valueindex;
|
|
int count;
|
|
char *o;
|
|
|
|
valueindex = (valueindex + 1) % 4;
|
|
if( *s == '\\' ) s++;
|
|
|
|
while( 1 )
|
|
{
|
|
count = 0;
|
|
o = pkey;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s != '\\' )
|
|
{
|
|
if( !*s ) return "";
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
|
|
*o = 0;
|
|
s++;
|
|
|
|
o = value[valueindex];
|
|
count = 0;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
if( !*s ) return "";
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
|
|
if( !Q_strcmp( key, pkey ))
|
|
return value[valueindex];
|
|
if( !*s ) return "";
|
|
s++;
|
|
}
|
|
}
|
|
|
|
qboolean GAME_EXPORT Info_RemoveKey( char *s, const char *key )
|
|
{
|
|
char *start;
|
|
char pkey[MAX_KV_SIZE];
|
|
char value[MAX_KV_SIZE];
|
|
int cmpsize = Q_strlen( key );
|
|
int count;
|
|
char *o;
|
|
|
|
if( cmpsize > ( MAX_KV_SIZE - 1 ))
|
|
cmpsize = MAX_KV_SIZE - 1;
|
|
|
|
if( Q_strchr( key, '\\' ))
|
|
return false;
|
|
|
|
while( 1 )
|
|
{
|
|
start = s;
|
|
if( *s == '\\' ) s++;
|
|
count = 0;
|
|
o = pkey;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s != '\\' )
|
|
{
|
|
if( !*s ) return false;
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
s++;
|
|
|
|
count = 0;
|
|
o = value;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s != '\\' && *s )
|
|
{
|
|
if( !*s ) return false;
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
|
|
if( !Q_strncmp( key, pkey, cmpsize ))
|
|
{
|
|
Q_strcpy( start, s ); // remove this part
|
|
return true;
|
|
}
|
|
|
|
if( !*s ) return false;
|
|
}
|
|
}
|
|
|
|
void Info_RemovePrefixedKeys( char *start, char prefix )
|
|
{
|
|
char *s, *o;
|
|
char pkey[MAX_KV_SIZE];
|
|
char value[MAX_KV_SIZE];
|
|
int count;
|
|
|
|
s = start;
|
|
|
|
while( 1 )
|
|
{
|
|
if( *s == '\\' ) s++;
|
|
|
|
count = 0;
|
|
o = pkey;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s != '\\' )
|
|
{
|
|
if( !*s ) return;
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
s++;
|
|
|
|
count = 0;
|
|
o = value;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
if( !*s ) return;
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
|
|
if( pkey[0] == prefix )
|
|
{
|
|
Info_RemoveKey( start, pkey );
|
|
s = start;
|
|
}
|
|
|
|
if( !*s ) return;
|
|
}
|
|
}
|
|
|
|
qboolean Info_IsKeyImportant( const char *key )
|
|
{
|
|
if( key[0] == '*' )
|
|
return true;
|
|
if( !Q_strcmp( key, "name" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "model" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "rate" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "topcolor" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "bottomcolor" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "cl_updaterate" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "cl_lw" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "cl_lc" ))
|
|
return true;
|
|
if( !Q_strcmp( key, "cl_nopred" ))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
char *Info_FindLargestKey( char *s )
|
|
{
|
|
char key[MAX_KV_SIZE];
|
|
char value[MAX_KV_SIZE];
|
|
static char largest_key[128];
|
|
int largest_size = 0;
|
|
int l, count;
|
|
char *o;
|
|
|
|
*largest_key = 0;
|
|
|
|
if( *s == '\\' ) s++;
|
|
|
|
while( *s )
|
|
{
|
|
int size = 0;
|
|
|
|
count = 0;
|
|
o = key;
|
|
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
|
|
l = o - key;
|
|
*o = 0;
|
|
size = Q_strlen( key );
|
|
|
|
if( !*s ) return largest_key;
|
|
|
|
count = 0;
|
|
o = value;
|
|
s++;
|
|
while( count < (MAX_KV_SIZE - 1) && *s && *s != '\\' )
|
|
{
|
|
*o++ = *s++;
|
|
count++;
|
|
}
|
|
*o = 0;
|
|
|
|
if( *s ) s++;
|
|
|
|
size += Q_strlen( value );
|
|
|
|
if(( size > largest_size ) && !Info_IsKeyImportant( key ))
|
|
{
|
|
Q_strncpy( largest_key, key, sizeof( largest_key ));
|
|
largest_size = size;
|
|
}
|
|
}
|
|
|
|
return largest_key;
|
|
}
|
|
|
|
qboolean Info_SetValueForStarKey( char *s, const char *key, const char *value, int maxsize )
|
|
{
|
|
char new[1024], *v;
|
|
int c, team;
|
|
|
|
if( Q_strchr( key, '\\' ) || Q_strchr( value, '\\' ))
|
|
{
|
|
Con_Printf( S_ERROR "SetValueForKey: can't use keys or values with a \\\n" );
|
|
return false;
|
|
}
|
|
|
|
if( Q_strstr( key, ".." ) || Q_strstr( value, ".." ))
|
|
return false;
|
|
|
|
if( Q_strchr( key, '\"' ) || Q_strchr( value, '\"' ))
|
|
{
|
|
Con_Printf( S_ERROR "SetValueForKey: can't use keys or values with a \"\n" );
|
|
return false;
|
|
}
|
|
|
|
if( Q_strlen( key ) > ( MAX_KV_SIZE - 1 ) || Q_strlen( value ) > ( MAX_KV_SIZE - 1 ))
|
|
return false;
|
|
|
|
Info_RemoveKey( s, key );
|
|
|
|
if( !COM_CheckString( value ) )
|
|
return true; // just clear variable
|
|
|
|
Q_snprintf( new, sizeof( new ), "\\%s\\%s", key, value );
|
|
if( Q_strlen( new ) + Q_strlen( s ) > maxsize )
|
|
{
|
|
// no more room in buffer to add key/value
|
|
if( Info_IsKeyImportant( key ))
|
|
{
|
|
// keep removing the largest key/values until we have room
|
|
char *largekey;
|
|
|
|
do
|
|
{
|
|
largekey = Info_FindLargestKey( s );
|
|
Info_RemoveKey( s, largekey );
|
|
} while((( Q_strlen( new ) + Q_strlen( s )) >= maxsize ) && *largekey != 0 );
|
|
|
|
if( largekey[0] == 0 )
|
|
{
|
|
// no room to add setting
|
|
return true; // info changed, new value can't saved
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no room to add setting
|
|
return true; // info changed, new value can't saved
|
|
}
|
|
}
|
|
|
|
// only copy ascii values
|
|
s += Q_strlen( s );
|
|
v = new;
|
|
|
|
team = ( Q_stricmp( key, "team" ) == 0 ) ? true : false;
|
|
|
|
while( *v )
|
|
{
|
|
c = (byte)*v++;
|
|
if( team ) c = Q_tolower( c );
|
|
if( c > 13 ) *s++ = c;
|
|
}
|
|
*s = 0;
|
|
|
|
// all done
|
|
return true;
|
|
}
|
|
|
|
qboolean Info_SetValueForKey( char *s, const char *key, const char *value, int maxsize )
|
|
{
|
|
if( key[0] == '*' )
|
|
{
|
|
Con_Printf( S_ERROR "Can't set *keys\n" );
|
|
return false;
|
|
}
|
|
|
|
return Info_SetValueForStarKey( s, key, value, maxsize );
|
|
}
|