xash3d-fwgs/engine/common/infostring.c
Gleb Mazovetskiy 5e0a0765ce Trim all trailing whitespace
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:]]\+$//' {} \+
```
2021-01-04 20:55:10 +03:00

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 );
}