You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
417 lines
6.5 KiB
417 lines
6.5 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $Header: $
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include "quakedef.h"
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include "filesystem.h"
|
|
#include "filesystem_engine.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
#define MAX_KV_LEN 127
|
|
/*
|
|
===============
|
|
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[512];
|
|
static char value[4][512]; // use two buffers so compares
|
|
// work without stomping on each other
|
|
static int valueindex;
|
|
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;
|
|
|
|
if (!Q_strcmp (key, pkey) )
|
|
return value[valueindex];
|
|
|
|
if (!*s)
|
|
return "";
|
|
s++;
|
|
}
|
|
}
|
|
|
|
void Info_RemoveKey ( char *s, const char *key )
|
|
{
|
|
char *start;
|
|
char pkey[512];
|
|
char value[512];
|
|
char *o;
|
|
|
|
if (Q_strstr (key, "\\"))
|
|
{
|
|
ConMsg ("Can't use a key with a \\\n");
|
|
return;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
start = s;
|
|
if (*s == '\\')
|
|
s++;
|
|
o = pkey;
|
|
while (*s != '\\')
|
|
{
|
|
if (!*s)
|
|
return;
|
|
*o++ = *s++;
|
|
}
|
|
*o = 0;
|
|
s++;
|
|
|
|
o = value;
|
|
while (*s != '\\' && *s)
|
|
{
|
|
if (!*s)
|
|
return;
|
|
*o++ = *s++;
|
|
}
|
|
*o = 0;
|
|
|
|
if (!Q_strcmp (key, pkey) )
|
|
{
|
|
// Copies onto self, so okay to not use Q_strncpy???
|
|
Q_strcpy (start, s); // remove this part
|
|
return;
|
|
}
|
|
|
|
if (!*s)
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void Info_RemovePrefixedKeys (char *start, char prefix)
|
|
{
|
|
char *s;
|
|
char pkey[512];
|
|
char value[512];
|
|
char *o;
|
|
|
|
s = start;
|
|
|
|
while (1)
|
|
{
|
|
if (*s == '\\')
|
|
s++;
|
|
o = pkey;
|
|
while (*s != '\\')
|
|
{
|
|
if (!*s)
|
|
return;
|
|
*o++ = *s++;
|
|
}
|
|
*o = 0;
|
|
s++;
|
|
|
|
o = value;
|
|
while (*s != '\\' && *s)
|
|
{
|
|
if (!*s)
|
|
return;
|
|
*o++ = *s++;
|
|
}
|
|
*o = 0;
|
|
|
|
if (pkey[0] == prefix)
|
|
{
|
|
Info_RemoveKey (start, pkey);
|
|
s = start;
|
|
}
|
|
|
|
if (!*s)
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool 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, "cl_updaterate" ) )
|
|
return true;
|
|
if ( !Q_strcmp( key, "cl_lw" ) )
|
|
return true;
|
|
if ( !Q_strcmp( key, "cl_lc" ) )
|
|
return true;
|
|
if ( !Q_strcmp( key, "tracker" ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
char *Info_FindLargestKey( char *s, int maxsize )
|
|
{
|
|
char key[256];
|
|
char value[256];
|
|
char *o;
|
|
int l;
|
|
static char largest_key[256];
|
|
int largest_size = 0;
|
|
|
|
*largest_key = 0;
|
|
|
|
if (*s == '\\')
|
|
s++;
|
|
while (*s)
|
|
{
|
|
int size = 0;
|
|
|
|
o = key;
|
|
while (*s && *s != '\\')
|
|
*o++ = *s++;
|
|
|
|
l = o - key;
|
|
*o = 0;
|
|
size = Q_strlen( key );
|
|
|
|
if (!*s)
|
|
{
|
|
return largest_key;
|
|
}
|
|
|
|
o = value;
|
|
s++;
|
|
while (*s && *s != '\\')
|
|
*o++ = *s++;
|
|
*o = 0;
|
|
|
|
if (*s)
|
|
s++;
|
|
|
|
size += Q_strlen( value );
|
|
|
|
if ( (size > largest_size) && !Info_IsKeyImportant(key) )
|
|
{
|
|
largest_size = size;
|
|
Q_strncpy( largest_key, key, sizeof( largest_key ) );
|
|
}
|
|
}
|
|
|
|
return largest_key;
|
|
}
|
|
|
|
void Info_SetValueForStarKey ( char *s, const char *key, const char *value, int maxsize )
|
|
{
|
|
char newArray[1024], *v;
|
|
int c;
|
|
|
|
if (Q_strstr (key, "\\") || Q_strstr (value, "\\") )
|
|
{
|
|
ConMsg ("Can't use keys or values with a \\\n");
|
|
return;
|
|
}
|
|
|
|
if (Q_strstr (key, "\"") || Q_strstr (value, "\"") )
|
|
{
|
|
ConMsg ("Can't use keys or values with a \"\n");
|
|
return;
|
|
}
|
|
|
|
if (Q_strlen(key) > MAX_KV_LEN || Q_strlen(value) > MAX_KV_LEN)
|
|
{
|
|
ConMsg ("Keys and values must be < %i characters.\n", MAX_KV_LEN + 1 );
|
|
return;
|
|
}
|
|
Info_RemoveKey (s, key);
|
|
if (!value || !Q_strlen(value))
|
|
return;
|
|
|
|
Q_snprintf (newArray, sizeof( newArray ), "\\%s\\%s", key, value);
|
|
|
|
if ( (int)(Q_strlen(newArray) + 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, maxsize );
|
|
Info_RemoveKey( s, largekey );
|
|
} while ( ((int)(Q_strlen(newArray) + Q_strlen(s)) >= maxsize) && *largekey != 0 );
|
|
|
|
if ( largekey[0] == 0 )
|
|
{
|
|
// no room to add setting
|
|
ConMsg ("Info string length exceeded\n");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no room to add setting
|
|
ConMsg ("Info string length exceeded\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// only copy ascii values
|
|
s += Q_strlen(s);
|
|
v = newArray;
|
|
while (*v)
|
|
{
|
|
c = (unsigned char)*v++;
|
|
// client only allows highbits on name
|
|
if (stricmp(key, "name") != 0) {
|
|
c &= 127;
|
|
if (c < 32 || c > 127)
|
|
continue;
|
|
// auto lowercase team
|
|
if (stricmp(key, "team") == 0)
|
|
c = tolower(c);
|
|
}
|
|
if (c > 13)
|
|
*s++ = c;
|
|
}
|
|
*s = 0;
|
|
}
|
|
|
|
void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsize)
|
|
{
|
|
if (key[0] == '*')
|
|
{
|
|
ConMsg ("Can't set * keys\n");
|
|
return;
|
|
}
|
|
|
|
Info_SetValueForStarKey (s, key, value, maxsize);
|
|
}
|
|
|
|
void Info_Print ( const char *s )
|
|
{
|
|
char key[512];
|
|
char value[512];
|
|
char *o;
|
|
int l;
|
|
|
|
if (*s == '\\')
|
|
s++;
|
|
while (*s)
|
|
{
|
|
o = key;
|
|
while (*s && *s != '\\')
|
|
*o++ = *s++;
|
|
|
|
l = o - key;
|
|
if (l < 20)
|
|
{
|
|
Q_memset (o, ' ', 20-l);
|
|
key[20] = 0;
|
|
}
|
|
else
|
|
*o = 0;
|
|
ConMsg ("%s", key);
|
|
|
|
if (!*s)
|
|
{
|
|
ConMsg ("MISSING VALUE\n");
|
|
return;
|
|
}
|
|
|
|
o = value;
|
|
s++;
|
|
while (*s && *s != '\\')
|
|
*o++ = *s++;
|
|
*o = 0;
|
|
|
|
if (*s)
|
|
s++;
|
|
ConMsg ("%s\n", value);
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Info_WriteVars
|
|
|
|
==============
|
|
*/
|
|
void Info_WriteVars( char *s, FileHandle_t fp )
|
|
{
|
|
const ConVar *pcvar;
|
|
|
|
char pkey[512];
|
|
static char value[4][512]; // use two buffers so compares
|
|
// work without stomping on each other
|
|
static int valueindex;
|
|
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 = g_pCVar->FindVar( pkey );
|
|
if ( !pcvar && pkey[0] != '*' ) // Don't store out * keys
|
|
{
|
|
g_pFileSystem->FPrintf( fp, "setinfo \"%s\" \"%s\"\n",
|
|
pkey, value[valueindex] );
|
|
}
|
|
|
|
if (!*s)
|
|
return;
|
|
s++;
|
|
}
|
|
}
|