q3rally/engine/code/qcommon/cvar.c

1465 lines
29 KiB
C
Raw Normal View History

2011-02-18 14:31:32 +00:00
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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 2 of the License,
or (at your option) any later version.
Quake III Arena source code 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.
You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// cvar.c -- dynamic variable tracking
#include "q_shared.h"
#include "qcommon.h"
cvar_t *cvar_vars = NULL;
cvar_t *cvar_cheats;
int cvar_modifiedFlags;
#define MAX_CVARS 2048
2011-02-18 14:31:32 +00:00
cvar_t cvar_indexes[MAX_CVARS];
int cvar_numIndexes;
#define FILE_HASH_SIZE 256
static cvar_t *hashTable[FILE_HASH_SIZE];
/*
================
return a hash value for the filename
================
*/
static long generateHashValue( const char *fname ) {
int i;
long hash;
char letter;
hash = 0;
i = 0;
while (fname[i] != '\0') {
letter = tolower(fname[i]);
hash+=(long)(letter)*(i+119);
i++;
}
hash &= (FILE_HASH_SIZE-1);
return hash;
}
/*
============
Cvar_ValidateString
============
*/
static qboolean Cvar_ValidateString( const char *s ) {
if ( !s ) {
return qfalse;
}
if ( strchr( s, '\\' ) ) {
return qfalse;
}
if ( strchr( s, '\"' ) ) {
return qfalse;
}
if ( strchr( s, ';' ) ) {
return qfalse;
}
return qtrue;
}
/*
============
Cvar_FindVar
============
*/
static cvar_t *Cvar_FindVar( const char *var_name ) {
cvar_t *var;
long hash;
hash = generateHashValue(var_name);
for (var=hashTable[hash] ; var ; var=var->hashNext) {
if (!Q_stricmp(var_name, var->name)) {
return var;
}
}
return NULL;
}
/*
============
Cvar_VariableValue
============
*/
float Cvar_VariableValue( const char *var_name ) {
cvar_t *var;
var = Cvar_FindVar (var_name);
if (!var)
return 0;
return var->value;
}
/*
============
Cvar_VariableIntegerValue
============
*/
int Cvar_VariableIntegerValue( const char *var_name ) {
cvar_t *var;
var = Cvar_FindVar (var_name);
if (!var)
return 0;
return var->integer;
}
/*
============
Cvar_VariableString
============
*/
char *Cvar_VariableString( const char *var_name ) {
cvar_t *var;
var = Cvar_FindVar (var_name);
if (!var)
return "";
return var->string;
}
/*
============
Cvar_VariableStringBuffer
============
*/
void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
cvar_t *var;
var = Cvar_FindVar (var_name);
if (!var) {
*buffer = 0;
}
else {
Q_strncpyz( buffer, var->string, bufsize );
}
}
/*
============
Cvar_Flags
============
*/
int Cvar_Flags(const char *var_name)
{
cvar_t *var;
if(!(var = Cvar_FindVar(var_name)))
2011-02-18 14:31:32 +00:00
return CVAR_NONEXISTENT;
else
{
if(var->modified)
return var->flags | CVAR_MODIFIED;
else
return var->flags;
}
2011-02-18 14:31:32 +00:00
}
/*
============
Cvar_CommandCompletion
============
*/
void Cvar_CommandCompletion(void (*callback)(const char *s))
{
cvar_t *cvar;
for(cvar = cvar_vars; cvar; cvar = cvar->next)
{
if(cvar->name)
callback(cvar->name);
}
}
/*
============
Cvar_Validate
============
*/
static const char *Cvar_Validate( cvar_t *var,
const char *value, qboolean warn )
{
static char s[ MAX_CVAR_VALUE_STRING ];
float valuef;
qboolean changed = qfalse;
if( !var->validate )
return value;
if( !value )
return value;
if( Q_isanumber( value ) )
{
valuef = atof( value );
if( var->integral )
{
if( !Q_isintegral( valuef ) )
{
if( warn )
Com_Printf( "WARNING: cvar '%s' must be integral", var->name );
valuef = (int)valuef;
changed = qtrue;
}
}
}
else
{
if( warn )
Com_Printf( "WARNING: cvar '%s' must be numeric", var->name );
valuef = atof( var->resetString );
changed = qtrue;
}
if( valuef < var->min )
{
if( warn )
{
if( changed )
Com_Printf( " and is" );
else
Com_Printf( "WARNING: cvar '%s'", var->name );
if( Q_isintegral( var->min ) )
Com_Printf( " out of range (min %d)", (int)var->min );
else
Com_Printf( " out of range (min %f)", var->min );
}
valuef = var->min;
changed = qtrue;
}
else if( valuef > var->max )
{
if( warn )
{
if( changed )
Com_Printf( " and is" );
else
Com_Printf( "WARNING: cvar '%s'", var->name );
if( Q_isintegral( var->max ) )
Com_Printf( " out of range (max %d)", (int)var->max );
else
Com_Printf( " out of range (max %f)", var->max );
}
valuef = var->max;
changed = qtrue;
}
if( changed )
{
if( Q_isintegral( valuef ) )
{
Com_sprintf( s, sizeof( s ), "%d", (int)valuef );
if( warn )
Com_Printf( ", setting to %d\n", (int)valuef );
}
else
{
Com_sprintf( s, sizeof( s ), "%f", valuef );
if( warn )
Com_Printf( ", setting to %f\n", valuef );
}
return s;
}
else
return value;
}
/*
============
Cvar_Get
If the variable already exists, the value will not be set unless CVAR_ROM
The flags will be or'ed in if the variable exists.
============
*/
cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
cvar_t *var;
long hash;
int index;
if ( !var_name || ! var_value ) {
Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" );
}
if ( !Cvar_ValidateString( var_name ) ) {
Com_Printf("invalid cvar name string: %s\n", var_name );
var_name = "BADNAME";
}
#if 0 // FIXME: values with backslash happen
if ( !Cvar_ValidateString( var_value ) ) {
Com_Printf("invalid cvar value string: %s\n", var_value );
var_value = "BADVALUE";
}
#endif
var = Cvar_FindVar (var_name);
if(var)
{
var_value = Cvar_Validate(var, var_value, qfalse);
// Make sure the game code cannot mark engine-added variables as gamecode vars
if(var->flags & CVAR_VM_CREATED)
{
if(!(flags & CVAR_VM_CREATED))
var->flags &= ~CVAR_VM_CREATED;
}
else if (!(var->flags & CVAR_USER_CREATED))
{
if(flags & CVAR_VM_CREATED)
flags &= ~CVAR_VM_CREATED;
}
2011-02-18 14:31:32 +00:00
// if the C code is now specifying a variable that the user already
// set a value for, take the new value as the reset value
if(var->flags & CVAR_USER_CREATED)
{
var->flags &= ~CVAR_USER_CREATED;
Z_Free( var->resetString );
var->resetString = CopyString( var_value );
if(flags & CVAR_ROM)
{
// this variable was set by the user,
// so force it to value given by the engine.
if(var->latchedString)
Z_Free(var->latchedString);
var->latchedString = CopyString(var_value);
}
}
// Make sure servers cannot mark engine-added variables as SERVER_CREATED
if(var->flags & CVAR_SERVER_CREATED)
{
if(!(flags & CVAR_SERVER_CREATED))
var->flags &= ~CVAR_SERVER_CREATED;
}
else
{
if(flags & CVAR_SERVER_CREATED)
flags &= ~CVAR_SERVER_CREATED;
}
2011-02-18 14:31:32 +00:00
var->flags |= flags;
// only allow one non-empty reset string without a warning
if ( !var->resetString[0] ) {
// we don't have a reset string yet
Z_Free( var->resetString );
var->resetString = CopyString( var_value );
} else if ( var_value[0] && strcmp( var->resetString, var_value ) ) {
Com_DPrintf( "Warning: cvar \"%s\" given initial values: \"%s\" and \"%s\"\n",
var_name, var->resetString, var_value );
}
// if we have a latched string, take that value now
if ( var->latchedString ) {
char *s;
s = var->latchedString;
var->latchedString = NULL; // otherwise cvar_set2 would free it
Cvar_Set2( var_name, s, qtrue );
Z_Free( s );
}
// ZOID--needs to be set so that cvars the game sets as
// SERVERINFO get sent to clients
cvar_modifiedFlags |= flags;
return var;
}
//
// allocate a new cvar
//
// find a free cvar
for(index = 0; index < MAX_CVARS; index++)
{
if(!cvar_indexes[index].name)
break;
}
if(index >= MAX_CVARS)
{
if(!com_errorEntered)
Com_Error(ERR_FATAL, "Error: Too many cvars, cannot create a new one!");
return NULL;
}
var = &cvar_indexes[index];
if(index >= cvar_numIndexes)
cvar_numIndexes = index + 1;
var->name = CopyString (var_name);
var->string = CopyString (var_value);
var->modified = qtrue;
var->modificationCount = 1;
var->value = atof (var->string);
var->integer = atoi(var->string);
var->resetString = CopyString( var_value );
var->validate = qfalse;
var->description = NULL;
2011-02-18 14:31:32 +00:00
// link the variable in
var->next = cvar_vars;
if(cvar_vars)
cvar_vars->prev = var;
var->prev = NULL;
cvar_vars = var;
var->flags = flags;
// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
cvar_modifiedFlags |= var->flags;
hash = generateHashValue(var_name);
var->hashIndex = hash;
var->hashNext = hashTable[hash];
if(hashTable[hash])
hashTable[hash]->hashPrev = var;
var->hashPrev = NULL;
hashTable[hash] = var;
return var;
}
/*
============
Cvar_Print
Prints the value, default, and latched string of the given variable
============
*/
void Cvar_Print( cvar_t *v ) {
Com_Printf ("\"%s\" is:\"%s" S_COLOR_WHITE "\"",
v->name, v->string );
if ( !( v->flags & CVAR_ROM ) ) {
if ( !Q_stricmp( v->string, v->resetString ) ) {
Com_Printf (", the default" );
} else {
Com_Printf (" default:\"%s" S_COLOR_WHITE "\"",
v->resetString );
}
}
Com_Printf ("\n");
if ( v->latchedString ) {
Com_Printf( "latched: \"%s\"\n", v->latchedString );
}
if ( v->description ) {
Com_Printf( "%s\n", v->description );
}
2011-02-18 14:31:32 +00:00
}
/*
============
Cvar_Set2
============
*/
cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) {
cvar_t *var;
// Com_DPrintf( "Cvar_Set2: %s %s\n", var_name, value );
if ( !Cvar_ValidateString( var_name ) ) {
Com_Printf("invalid cvar name string: %s\n", var_name );
var_name = "BADNAME";
}
#if 0 // FIXME
if ( value && !Cvar_ValidateString( value ) ) {
Com_Printf("invalid cvar value string: %s\n", value );
var_value = "BADVALUE";
}
#endif
var = Cvar_FindVar (var_name);
if (!var) {
if ( !value ) {
return NULL;
}
// create it
if ( !force ) {
return Cvar_Get( var_name, value, CVAR_USER_CREATED );
} else {
return Cvar_Get (var_name, value, 0);
}
}
if (!value ) {
value = var->resetString;
}
value = Cvar_Validate(var, value, qtrue);
if((var->flags & CVAR_LATCH) && var->latchedString)
{
if(!strcmp(value, var->string))
{
Z_Free(var->latchedString);
var->latchedString = NULL;
return var;
}
if(!strcmp(value, var->latchedString))
return var;
}
else if(!strcmp(value, var->string))
return var;
// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
cvar_modifiedFlags |= var->flags;
if (!force)
{
if (var->flags & CVAR_ROM)
{
Com_Printf ("%s is read only.\n", var_name);
return var;
}
if (var->flags & CVAR_INIT)
{
Com_Printf ("%s is write protected.\n", var_name);
return var;
}
ioquake3 resync to revision 3511 from 3444. This updates from SDL 2.0.4 to SDL 2.0.8. Fix nullptr dereference in front of nullptr check in FS_CheckPak0 Fix undefined behaviour due to shifting signed in snd_mem.c Fix shifting bits out of byte in tr_font.c Fix shift into sign in cl_cin.c Fix signed bit operations in MSG_ReadBits Add missing address operator in cm_polylib.c OpenGL1: Decay float[8] to float * in tr_marks.c Avoid srcList[-1] in snd_openal.c Fix the behaviour of CVAR_LATCH|CVAR_CHEAT cvars Maximize cURL buffer size Fix mouse grab after toggling fullscreen Fix q3history buffer not cleared between mods and OOB-access Revert "Removed "Color Depth" from q3_ui system settings, it didn't control anything." Fix displayed color/depth/stencil bits values Restore setting r_colorbits in q3_ui Make setting r_stencilbits more consistent in Team Arena UI Fix map list in Team Arena start server menu after entering SP menu Support SDL audio devices that require float32 samples. sdl_snd.c should just initialize SDL audio without checking SDL_WasInit(). There's no need to SDL_PauseAudio(1) before calling SDL_CloseAudio(). Added audio capture support to SDL backend. Use the SDL2 audio device interface instead of the legacy 1.2 API. Disable SDL audio capture until prebuilt SDL libraries are updated to 2.0.8. Update SDL2 to 2.0.8 Add SDL 2.0.1 headers for macOS PPC Make macOS Universal Bundle target 10.6 for x86 and x86_64 Fix possible bot goal state NULL pointer dereference Fix uninitialized bot_goal_t fields Remove unnecessary NULL pointer check in Cmd_RemoveCommand Make UI_DrawProportionalString handle NULL string Fix compiling against macOS system OpenAL and SDL2 frameworks Fix array index in CanDamage() function - discovered by MARTY Fix compiling Makefile (broke in macOS frameworks commit) Fix clearing keys for control in Team Arena UI Make s_useOpenAL be CVAR_LATCH Improvements for dedicated camera followers (team follow1/2) Fix not closing description.txt and fix path seperator Fix duplicate bots displayed in Team Arena ingame add bot menu OpenGL2: Fix parsing specularScale in shaders Don't allow SDL audio capture using pulseaudio Isolate the Altivec code so non-Altivec PPC targets can use the same binary. Limit -maltivec to specific source files on OpenBSD too (untested) Use SDL 2.0.1 headers for macOS ppc64 Fix console offset while Team Arena voiceMenu is open OpenGL2: Readd r_deluxeSpecular. Fix client kicked as unpure when missing the latest cgame/ui pk3s Don't create multiple windows when GL context creation fails Require OpenGL 1.2 for GL_CLAMP_TO_EDGE Fix Linux uninstaller requiring Bash Fix Linux uninstaller redirecting stderr to stdout in preuninstall.sh Reported by @illwieckz. Fix in_restart causing fatal error while video is shutdown Allow pkg-config binary to be overridden with PKG_CONFIG Make testgun command without argument disable test gun model Remove unused renderer_buffer variable Don't upload 8 bit grayscale images as 16 bit luminance OpenGL1: Use RE_UploadCinematic() instead of duplicate code Don't load non-core GL functions for OpenGL 3.2 core context Load OpenGL ES 2.0 function procs Don't check fixed function GL extensions when using shader pipeline OpenGL2: Fix world VAO cache drawing when glIndex_t is unsigned short OpenGL2: Misc fixes and cleanup Fix IQM root joint backlerp when joint number is more than 0 Improve IQM loading Improve IQM CPU vertex skinning performance OpenGL2: Add GPU vertex skinning for IQM models
2018-07-30 11:35:12 +00:00
if ((var->flags & CVAR_CHEAT) && !cvar_cheats->integer)
{
Com_Printf ("%s is cheat protected.\n", var_name);
return var;
}
2011-02-18 14:31:32 +00:00
if (var->flags & CVAR_LATCH)
{
if (var->latchedString)
{
if (strcmp(value, var->latchedString) == 0)
return var;
Z_Free (var->latchedString);
}
else
{
if (strcmp(value, var->string) == 0)
return var;
}
Com_Printf ("%s will be changed upon restarting.\n", var_name);
var->latchedString = CopyString(value);
var->modified = qtrue;
var->modificationCount++;
return var;
}
}
else
{
if (var->latchedString)
{
Z_Free (var->latchedString);
var->latchedString = NULL;
}
}
if (!strcmp(value, var->string))
return var; // not changed
var->modified = qtrue;
var->modificationCount++;
Z_Free (var->string); // free the old value string
var->string = CopyString(value);
var->value = atof (var->string);
var->integer = atoi (var->string);
return var;
}
/*
============
Cvar_Set
============
*/
void Cvar_Set( const char *var_name, const char *value) {
Cvar_Set2 (var_name, value, qtrue);
}
/*
============
Cvar_SetSafe
============
*/
void Cvar_SetSafe( const char *var_name, const char *value )
{
int flags = Cvar_Flags( var_name );
if((flags != CVAR_NONEXISTENT) && (flags & CVAR_PROTECTED))
{
if( value )
Com_Error( ERR_DROP, "Restricted source tried to set "
"\"%s\" to \"%s\"", var_name, value );
else
Com_Error( ERR_DROP, "Restricted source tried to "
"modify \"%s\"", var_name );
return;
}
Cvar_Set( var_name, value );
}
2011-02-18 14:31:32 +00:00
/*
============
Cvar_SetLatched
============
*/
void Cvar_SetLatched( const char *var_name, const char *value) {
Cvar_Set2 (var_name, value, qfalse);
}
/*
============
Cvar_SetValue
============
*/
void Cvar_SetValue( const char *var_name, float value) {
char val[32];
if ( value == (int)value ) {
Com_sprintf (val, sizeof(val), "%i",(int)value);
} else {
Com_sprintf (val, sizeof(val), "%f",value);
}
Cvar_Set (var_name, val);
}
/*
============
Cvar_SetValueSafe
============
*/
void Cvar_SetValueSafe( const char *var_name, float value )
{
char val[32];
if( Q_isintegral( value ) )
Com_sprintf( val, sizeof(val), "%i", (int)value );
else
Com_sprintf( val, sizeof(val), "%f", value );
Cvar_SetSafe( var_name, val );
}
2011-02-18 14:31:32 +00:00
/*
============
Cvar_Reset
============
*/
void Cvar_Reset( const char *var_name ) {
Cvar_Set2( var_name, NULL, qfalse );
}
/*
============
Cvar_ForceReset
============
*/
void Cvar_ForceReset(const char *var_name)
{
Cvar_Set2(var_name, NULL, qtrue);
}
/*
============
Cvar_SetCheatState
Any testing variables will be reset to the safe values
============
*/
void Cvar_SetCheatState(void)
{
cvar_t *var;
// set all default vars to the safe value
for(var = cvar_vars; var ; var = var->next)
{
if(var->flags & CVAR_CHEAT)
{
// the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
// because of a different var->latchedString
if (var->latchedString)
{
Z_Free(var->latchedString);
var->latchedString = NULL;
}
if (strcmp(var->resetString,var->string))
Cvar_Set(var->name, var->resetString);
}
}
}
/*
============
Cvar_Command
Handles variable inspection and changing from the console
============
*/
qboolean Cvar_Command( void ) {
cvar_t *v;
// check variables
v = Cvar_FindVar (Cmd_Argv(0));
if (!v) {
return qfalse;
}
// perform a variable print or set
if ( Cmd_Argc() == 1 ) {
Cvar_Print( v );
return qtrue;
}
// set the value if forcing isn't required
Cvar_Set2 (v->name, Cmd_Args(), qfalse);
return qtrue;
}
/*
============
Cvar_Print_f
Prints the contents of a cvar
(preferred over Cvar_Command where cvar names and commands conflict)
============
*/
void Cvar_Print_f(void)
{
char *name;
cvar_t *cv;
if(Cmd_Argc() != 2)
{
Com_Printf ("usage: print <variable>\n");
return;
}
name = Cmd_Argv(1);
cv = Cvar_FindVar(name);
if(cv)
Cvar_Print(cv);
else
Com_Printf ("Cvar %s does not exist.\n", name);
}
/*
============
Cvar_Toggle_f
Toggles a cvar for easy single key binding, optionally through a list of
given values
============
*/
void Cvar_Toggle_f( void ) {
int i, c = Cmd_Argc();
char *curval;
if(c < 2) {
Com_Printf("usage: toggle <variable> [value1, value2, ...]\n");
return;
}
if(c == 2) {
Cvar_Set2(Cmd_Argv(1), va("%d",
!Cvar_VariableValue(Cmd_Argv(1))),
qfalse);
return;
}
if(c == 3) {
Com_Printf("toggle: nothing to toggle to\n");
return;
}
curval = Cvar_VariableString(Cmd_Argv(1));
// don't bother checking the last arg for a match since the desired
// behaviour is the same as no match (set to the first argument)
for(i = 2; i + 1 < c; i++) {
if(strcmp(curval, Cmd_Argv(i)) == 0) {
Cvar_Set2(Cmd_Argv(1), Cmd_Argv(i + 1), qfalse);
return;
}
}
// fallback
Cvar_Set2(Cmd_Argv(1), Cmd_Argv(2), qfalse);
}
/*
============
Cvar_Set_f
Allows setting and defining of arbitrary cvars from console, even if they
weren't declared in C code.
============
*/
void Cvar_Set_f( void ) {
int c;
char *cmd;
cvar_t *v;
c = Cmd_Argc();
cmd = Cmd_Argv(0);
if ( c < 2 ) {
Com_Printf ("usage: %s <variable> <value>\n", cmd);
return;
}
if ( c == 2 ) {
Cvar_Print_f();
return;
}
v = Cvar_Set2 (Cmd_Argv(1), Cmd_ArgsFrom(2), qfalse);
if( !v ) {
return;
}
switch( cmd[3] ) {
case 'a':
if( !( v->flags & CVAR_ARCHIVE ) ) {
v->flags |= CVAR_ARCHIVE;
cvar_modifiedFlags |= CVAR_ARCHIVE;
}
break;
case 'u':
if( !( v->flags & CVAR_USERINFO ) ) {
v->flags |= CVAR_USERINFO;
cvar_modifiedFlags |= CVAR_USERINFO;
}
break;
case 's':
if( !( v->flags & CVAR_SERVERINFO ) ) {
v->flags |= CVAR_SERVERINFO;
cvar_modifiedFlags |= CVAR_SERVERINFO;
}
break;
}
}
/*
============
Cvar_Reset_f
============
*/
void Cvar_Reset_f( void ) {
if ( Cmd_Argc() != 2 ) {
Com_Printf ("usage: reset <variable>\n");
return;
}
Cvar_Reset( Cmd_Argv( 1 ) );
}
/*
============
Cvar_WriteVariables
Appends lines containing "set variable value" for all variables
with the archive flag set to qtrue.
============
*/
void Cvar_WriteVariables(fileHandle_t f)
{
cvar_t *var;
char buffer[1024];
for (var = cvar_vars; var; var = var->next)
{
if(!var->name || Q_stricmp( var->name, "cl_cdkey" ) == 0)
continue;
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_Write( buffer, strlen( buffer ), f );
}
}
}
/*
============
Cvar_List_f
============
*/
void Cvar_List_f( void ) {
cvar_t *var;
int i;
char *match;
if ( Cmd_Argc() > 1 ) {
match = Cmd_Argv( 1 );
} else {
match = NULL;
}
i = 0;
for (var = cvar_vars ; var ; var = var->next, i++)
{
if(!var->name || (match && !Com_Filter(match, var->name, qfalse)))
continue;
if (var->flags & CVAR_SERVERINFO) {
Com_Printf("S");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_SYSTEMINFO) {
Com_Printf("s");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_USERINFO) {
Com_Printf("U");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_ROM) {
Com_Printf("R");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_INIT) {
Com_Printf("I");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_ARCHIVE) {
Com_Printf("A");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_LATCH) {
Com_Printf("L");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_CHEAT) {
Com_Printf("C");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_USER_CREATED) {
Com_Printf("?");
} else {
Com_Printf(" ");
}
Com_Printf (" %s \"%s\"\n", var->name, var->string);
}
Com_Printf ("\n%i total cvars\n", i);
Com_Printf ("%i cvar indexes\n", cvar_numIndexes);
}
/*
============
Cvar_ListModified_f
============
*/
void Cvar_ListModified_f( void ) {
cvar_t *var;
int totalModified;
char *value;
char *match;
if ( Cmd_Argc() > 1 ) {
match = Cmd_Argv( 1 );
} else {
match = NULL;
}
totalModified = 0;
for (var = cvar_vars ; var ; var = var->next)
{
if ( !var->name || !var->modificationCount )
continue;
value = var->latchedString ? var->latchedString : var->string;
if ( !strcmp( value, var->resetString ) )
continue;
totalModified++;
if (match && !Com_Filter(match, var->name, qfalse))
continue;
if (var->flags & CVAR_SERVERINFO) {
Com_Printf("S");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_SYSTEMINFO) {
Com_Printf("s");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_USERINFO) {
Com_Printf("U");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_ROM) {
Com_Printf("R");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_INIT) {
Com_Printf("I");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_ARCHIVE) {
Com_Printf("A");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_LATCH) {
Com_Printf("L");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_CHEAT) {
Com_Printf("C");
} else {
Com_Printf(" ");
}
if (var->flags & CVAR_USER_CREATED) {
Com_Printf("?");
} else {
Com_Printf(" ");
}
Com_Printf (" %s \"%s\", default \"%s\"\n", var->name, value, var->resetString);
}
Com_Printf ("\n%i total modified cvars\n", totalModified);
}
2011-02-18 14:31:32 +00:00
/*
============
Cvar_Unset
Unsets a cvar
============
*/
cvar_t *Cvar_Unset(cvar_t *cv)
{
cvar_t *next = cv->next;
// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
cvar_modifiedFlags |= cv->flags;
2011-02-18 14:31:32 +00:00
if(cv->name)
Z_Free(cv->name);
if(cv->string)
Z_Free(cv->string);
if(cv->latchedString)
Z_Free(cv->latchedString);
if(cv->resetString)
Z_Free(cv->resetString);
if(cv->description)
Z_Free(cv->description);
2011-02-18 14:31:32 +00:00
if(cv->prev)
cv->prev->next = cv->next;
else
cvar_vars = cv->next;
if(cv->next)
cv->next->prev = cv->prev;
if(cv->hashPrev)
cv->hashPrev->hashNext = cv->hashNext;
else
hashTable[cv->hashIndex] = cv->hashNext;
if(cv->hashNext)
cv->hashNext->hashPrev = cv->hashPrev;
Com_Memset(cv, '\0', sizeof(*cv));
return next;
}
/*
============
Cvar_Unset_f
Unsets a userdefined cvar
============
*/
void Cvar_Unset_f(void)
{
cvar_t *cv;
if(Cmd_Argc() != 2)
{
Com_Printf("Usage: %s <varname>\n", Cmd_Argv(0));
return;
}
cv = Cvar_FindVar(Cmd_Argv(1));
if(!cv)
return;
if(cv->flags & CVAR_USER_CREATED)
Cvar_Unset(cv);
else
Com_Printf("Error: %s: Variable %s is not user created.\n", Cmd_Argv(0), cv->name);
}
/*
============
Cvar_Restart
Resets all cvars to their hardcoded values and removes userdefined variables
and variables added via the VMs if requested.
============
*/
void Cvar_Restart(qboolean unsetVM)
{
cvar_t *curvar;
curvar = cvar_vars;
while(curvar)
{
if((curvar->flags & CVAR_USER_CREATED) ||
(unsetVM && (curvar->flags & CVAR_VM_CREATED)))
{
// throw out any variables the user/vm created
curvar = Cvar_Unset(curvar);
continue;
}
if(!(curvar->flags & (CVAR_ROM | CVAR_INIT | CVAR_NORESTART)))
{
// Just reset the rest to their default values.
Cvar_Set2(curvar->name, curvar->resetString, qfalse);
}
curvar = curvar->next;
}
}
/*
============
Cvar_Restart_f
Resets all cvars to their hardcoded values
============
*/
void Cvar_Restart_f(void)
{
Cvar_Restart(qfalse);
}
/*
=====================
Cvar_InfoString
=====================
*/
char *Cvar_InfoString(int bit)
{
static char info[MAX_INFO_STRING];
cvar_t *var;
info[0] = 0;
for(var = cvar_vars; var; var = var->next)
{
if(var->name && (var->flags & bit))
Info_SetValueForKey (info, var->name, var->string);
}
return info;
}
/*
=====================
Cvar_InfoString_Big
handles large info strings ( CS_SYSTEMINFO )
=====================
*/
char *Cvar_InfoString_Big(int bit)
{
static char info[BIG_INFO_STRING];
cvar_t *var;
info[0] = 0;
for (var = cvar_vars; var; var = var->next)
{
if(var->name && (var->flags & bit))
Info_SetValueForKey_Big (info, var->name, var->string);
}
return info;
}
/*
=====================
Cvar_InfoStringBuffer
=====================
*/
void Cvar_InfoStringBuffer( int bit, char* buff, int buffsize ) {
Q_strncpyz(buff,Cvar_InfoString(bit),buffsize);
}
/*
=====================
Cvar_CheckRange
=====================
*/
void Cvar_CheckRange( cvar_t *var, float min, float max, qboolean integral )
{
var->validate = qtrue;
var->min = min;
var->max = max;
var->integral = integral;
// Force an initial range check
Cvar_Set( var->name, var->string );
}
/*
=====================
Cvar_SetDescription
=====================
*/
void Cvar_SetDescription( cvar_t *var, const char *var_description )
{
if( var_description && var_description[0] != '\0' )
{
if( var->description != NULL )
{
Z_Free( var->description );
}
var->description = CopyString( var_description );
}
}
2011-02-18 14:31:32 +00:00
/*
=====================
Cvar_Register
basically a slightly modified Cvar_Get for the interpreted modules
=====================
*/
void Cvar_Register(vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags)
{
cvar_t *cv;
// There is code in Cvar_Get to prevent CVAR_ROM cvars being changed by the
// user. In other words CVAR_ARCHIVE and CVAR_ROM are mutually exclusive
// flags. Unfortunately some historical game code (including single player
// baseq3) sets both flags. We unset CVAR_ROM for such cvars.
if ((flags & (CVAR_ARCHIVE | CVAR_ROM)) == (CVAR_ARCHIVE | CVAR_ROM)) {
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
Com_DPrintf( S_COLOR_YELLOW "WARNING: Unsetting CVAR_ROM from cvar '%s', "
2011-02-18 14:31:32 +00:00
"since it is also CVAR_ARCHIVE\n", varName );
flags &= ~CVAR_ROM;
}
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
// Don't allow VM to specific a different creator or other internal flags.
if ( flags & CVAR_USER_CREATED ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_USER_CREATED on cvar '%s'\n", varName );
flags &= ~CVAR_USER_CREATED;
}
if ( flags & CVAR_SERVER_CREATED ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_SERVER_CREATED on cvar '%s'\n", varName );
flags &= ~CVAR_SERVER_CREATED;
}
if ( flags & CVAR_PROTECTED ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_PROTECTED on cvar '%s'\n", varName );
flags &= ~CVAR_PROTECTED;
}
if ( flags & CVAR_MODIFIED ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_MODIFIED on cvar '%s'\n", varName );
flags &= ~CVAR_MODIFIED;
}
if ( flags & CVAR_NONEXISTENT ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to set CVAR_NONEXISTENT on cvar '%s'\n", varName );
flags &= ~CVAR_NONEXISTENT;
}
cv = Cvar_FindVar(varName);
// Don't modify cvar if it's protected.
if ( cv && ( cv->flags & CVAR_PROTECTED ) ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: VM tried to register protected cvar '%s' with value '%s'%s\n",
varName, defaultValue, ( flags & ~cv->flags ) != 0 ? " and new flags" : "" );
} else {
cv = Cvar_Get(varName, defaultValue, flags | CVAR_VM_CREATED);
}
2011-02-18 14:31:32 +00:00
if (!vmCvar)
return;
vmCvar->handle = cv - cvar_indexes;
vmCvar->modificationCount = -1;
Cvar_Update( vmCvar );
}
/*
=====================
Cvar_Update
updates an interpreted modules' version of a cvar
=====================
*/
void Cvar_Update( vmCvar_t *vmCvar ) {
cvar_t *cv = NULL;
assert(vmCvar);
if ( (unsigned)vmCvar->handle >= cvar_numIndexes ) {
Com_Error( ERR_DROP, "Cvar_Update: handle out of range" );
}
cv = cvar_indexes + vmCvar->handle;
if ( cv->modificationCount == vmCvar->modificationCount ) {
return;
}
if ( !cv->string ) {
return; // variable might have been cleared by a cvar_restart
}
vmCvar->modificationCount = cv->modificationCount;
if ( strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING )
2011-03-08 10:19:47 +00:00
Com_Error( ERR_DROP, "Cvar_Update: src %s length %u exceeds MAX_CVAR_VALUE_STRING",
2011-02-18 14:31:32 +00:00
cv->string,
2011-03-08 10:19:47 +00:00
(unsigned int) strlen(cv->string));
2011-02-18 14:31:32 +00:00
Q_strncpyz( vmCvar->string, cv->string, MAX_CVAR_VALUE_STRING );
vmCvar->value = cv->value;
vmCvar->integer = cv->integer;
}
/*
==================
Cvar_CompleteCvarName
==================
*/
void Cvar_CompleteCvarName( char *args, int argNum )
{
if( argNum == 2 )
{
// Skip "<cmd> "
char *p = Com_SkipTokens( args, 1, " " );
if( p > args )
Field_CompleteCommand( p, qfalse, qtrue );
}
}
/*
============
Cvar_Init
Reads in all archived cvars
============
*/
void Cvar_Init (void)
{
Com_Memset(cvar_indexes, '\0', sizeof(cvar_indexes));
Com_Memset(hashTable, '\0', sizeof(hashTable));
cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO );
Cmd_AddCommand ("print", Cvar_Print_f);
Cmd_AddCommand ("toggle", Cvar_Toggle_f);
Cmd_SetCommandCompletionFunc( "toggle", Cvar_CompleteCvarName );
Cmd_AddCommand ("set", Cvar_Set_f);
Cmd_SetCommandCompletionFunc( "set", Cvar_CompleteCvarName );
Cmd_AddCommand ("sets", Cvar_Set_f);
Cmd_SetCommandCompletionFunc( "sets", Cvar_CompleteCvarName );
Cmd_AddCommand ("setu", Cvar_Set_f);
Cmd_SetCommandCompletionFunc( "setu", Cvar_CompleteCvarName );
Cmd_AddCommand ("seta", Cvar_Set_f);
Cmd_SetCommandCompletionFunc( "seta", Cvar_CompleteCvarName );
Cmd_AddCommand ("reset", Cvar_Reset_f);
Cmd_SetCommandCompletionFunc( "reset", Cvar_CompleteCvarName );
Cmd_AddCommand ("unset", Cvar_Unset_f);
Cmd_SetCommandCompletionFunc("unset", Cvar_CompleteCvarName);
Cmd_AddCommand ("cvarlist", Cvar_List_f);
Cmd_AddCommand ("cvar_modified", Cvar_ListModified_f);
2011-02-18 14:31:32 +00:00
Cmd_AddCommand ("cvar_restart", Cvar_Restart_f);
}