1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2005 - 2015, ioquake3 contributors
7 Copyright (C) 2013 - 2015, OpenJK contributors
8 
9 This file is part of the OpenJK source code.
10 
11 OpenJK is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License version 2 as
13 published by the Free Software Foundation.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 ===========================================================================
23 */
24 
25 // cvar.c -- dynamic variable tracking
26 
27 #include "qcommon/qcommon.h"
28 
29 cvar_t		*cvar_vars = NULL;
30 cvar_t		*cvar_cheats;
31 uint32_t	cvar_modifiedFlags;
32 
33 #define	MAX_CVARS	8192
34 cvar_t		cvar_indexes[MAX_CVARS];
35 int			cvar_numIndexes;
36 
37 #define FILE_HASH_SIZE		512
38 static	cvar_t*		hashTable[FILE_HASH_SIZE];
39 static	qboolean cvar_sort = qfalse;
40 
41 static char *lastMemPool = NULL;
42 static int memPoolSize;
43 
44 //If the string came from the memory pool, don't really free it.  The entire
45 //memory pool will be wiped during the next level load.
Cvar_FreeString(char * string)46 static void Cvar_FreeString(char *string)
47 {
48 	if(!lastMemPool || string < lastMemPool ||
49 			string >= lastMemPool + memPoolSize) {
50 		Z_Free(string);
51 	}
52 }
53 
54 /*
55 ================
56 return a hash value for the filename
57 ================
58 */
generateHashValue(const char * fname)59 static long generateHashValue( const char *fname ) {
60 	int		i;
61 	long	hash;
62 	char	letter;
63 
64 	hash = 0;
65 	i = 0;
66 	while (fname[i] != '\0') {
67 		letter = tolower((unsigned char)fname[i]);
68 		hash+=(long)(letter)*(i+119);
69 		i++;
70 	}
71 	hash &= (FILE_HASH_SIZE-1);
72 	return hash;
73 }
74 
75 /*
76 ============
77 Cvar_ValidateString
78 ============
79 */
Cvar_ValidateString(const char * s)80 static qboolean Cvar_ValidateString( const char *s ) {
81 	if ( !s ) {
82 		return qfalse;
83 	}
84 	if ( strchr( s, '\\' ) ) {
85 		return qfalse;
86 	}
87 	if ( strchr( s, '\"' ) ) {
88 		return qfalse;
89 	}
90 	if ( strchr( s, ';' ) ) {
91 		return qfalse;
92 	}
93 	return qtrue;
94 }
95 
96 /*
97 ============
98 Cvar_FindVar
99 ============
100 */
Cvar_FindVar(const char * var_name)101 static cvar_t *Cvar_FindVar( const char *var_name ) {
102 	cvar_t	*var;
103 	long hash;
104 
105 	hash = generateHashValue(var_name);
106 
107 	for (var=hashTable[hash] ; var ; var=var->hashNext) {
108 		if (!Q_stricmp(var_name, var->name)) {
109 			return var;
110 		}
111 	}
112 
113 	return NULL;
114 }
115 
116 /*
117 ============
118 Cvar_VariableValue
119 ============
120 */
Cvar_VariableValue(const char * var_name)121 float Cvar_VariableValue( const char *var_name ) {
122 	cvar_t	*var;
123 
124 	var = Cvar_FindVar (var_name);
125 	if (!var)
126 		return 0;
127 	return var->value;
128 }
129 
130 
131 /*
132 ============
133 Cvar_VariableIntegerValue
134 ============
135 */
Cvar_VariableIntegerValue(const char * var_name)136 int Cvar_VariableIntegerValue( const char *var_name ) {
137 	cvar_t	*var;
138 
139 	var = Cvar_FindVar (var_name);
140 	if (!var)
141 		return 0;
142 	return var->integer;
143 }
144 
145 /*
146 ============
147 Cvar_VariableString
148 ============
149 */
Cvar_VariableString(const char * var_name)150 char *Cvar_VariableString( const char *var_name ) {
151 	cvar_t *var;
152 
153 	var = Cvar_FindVar (var_name);
154 	if (!var)
155 		return "";
156 	return var->string;
157 }
158 
159 /*
160 ============
161 Cvar_VariableStringBuffer
162 ============
163 */
Cvar_VariableStringBuffer(const char * var_name,char * buffer,int bufsize)164 void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
165 	cvar_t *var;
166 
167 	var = Cvar_FindVar (var_name);
168 	if (!var) {
169 		*buffer = 0;
170 	}
171 	else {
172 		Q_strncpyz( buffer, var->string, bufsize );
173 	}
174 }
175 
176 /*
177 ============
178 Cvar_DescriptionString
179 ============
180 */
Cvar_DescriptionString(const char * var_name)181 char *Cvar_DescriptionString( const char *var_name )
182 {
183 	cvar_t *var;
184 
185 	var = Cvar_FindVar( var_name );
186 	if ( !var || !VALIDSTRING( var->description ) )
187 		return "";
188 	return var->description;
189 }
190 
191 /*
192 ============
193 Cvar_Flags
194 ============
195 */
Cvar_Flags(const char * var_name)196 uint32_t Cvar_Flags( const char *var_name ) {
197 	cvar_t *var;
198 
199 	if ( !(var = Cvar_FindVar( var_name )) )
200 		return CVAR_NONEXISTENT;
201 	else {
202 		if ( var->modified )
203 			return var->flags | CVAR_MODIFIED;
204 		else
205 			return var->flags;
206 	}
207 }
208 
209 /*
210 ============
211 Cvar_CommandCompletion
212 ============
213 */
Cvar_CommandCompletion(callbackFunc_t callback)214 void	Cvar_CommandCompletion( callbackFunc_t callback ) {
215 	cvar_t		*cvar;
216 
217 	for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) {
218 		// Don't show internal cvars
219 		if ( cvar->flags & CVAR_INTERNAL )
220 		{
221 			continue;
222 		}
223 		callback( cvar->name );
224 	}
225 }
226 
227 /*
228 ============
229 Cvar_Validate
230 ============
231 */
Cvar_Validate(cvar_t * var,const char * value,qboolean warn)232 static const char *Cvar_Validate( cvar_t *var, const char *value, qboolean warn )
233 {
234 	static char s[MAX_CVAR_VALUE_STRING];
235 	float valuef;
236 	qboolean changed = qfalse;
237 
238 	if( !var->validate )
239 		return value;
240 
241 	if( !value )
242 		return value;
243 
244 	if( Q_isanumber( value ) )
245 	{
246 		valuef = atof( value );
247 
248 		if( var->integral )
249 		{
250 			if( !Q_isintegral( valuef ) )
251 			{
252 				if( warn )
253 					Com_Printf( "WARNING: cvar '%s' must be integral", var->name );
254 
255 				valuef = (int)valuef;
256 				changed = qtrue;
257 			}
258 		}
259 	}
260 	else
261 	{
262 		if( warn )
263 			Com_Printf( "WARNING: cvar '%s' must be numeric", var->name );
264 
265 		valuef = atof( var->resetString );
266 		changed = qtrue;
267 	}
268 
269 	if( valuef < var->min )
270 	{
271 		if( warn )
272 		{
273 			if( changed )
274 				Com_Printf( " and is" );
275 			else
276 				Com_Printf( "WARNING: cvar '%s'", var->name );
277 
278 			if( Q_isintegral( var->min ) )
279 				Com_Printf( " out of range (min %d)", (int)var->min );
280 			else
281 				Com_Printf( " out of range (min %f)", var->min );
282 		}
283 
284 		valuef = var->min;
285 		changed = qtrue;
286 	}
287 	else if( valuef > var->max )
288 	{
289 		if( warn )
290 		{
291 			if( changed )
292 				Com_Printf( " and is" );
293 			else
294 				Com_Printf( "WARNING: cvar '%s'", var->name );
295 
296 			if( Q_isintegral( var->max ) )
297 				Com_Printf( " out of range (max %d)", (int)var->max );
298 			else
299 				Com_Printf( " out of range (max %f)", var->max );
300 		}
301 
302 		valuef = var->max;
303 		changed = qtrue;
304 	}
305 
306 	if( changed )
307 	{
308 		if( Q_isintegral( valuef ) )
309 		{
310 			Com_sprintf( s, sizeof( s ), "%d", (int)valuef );
311 
312 			if( warn )
313 				Com_Printf( ", setting to %d\n", (int)valuef );
314 		}
315 		else
316 		{
317 			Com_sprintf( s, sizeof( s ), "%f", valuef );
318 
319 			if( warn )
320 				Com_Printf( ", setting to %f\n", valuef );
321 		}
322 
323 		return s;
324 	}
325 	else
326 		return value;
327 }
328 
329 /*
330 ============
331 Cvar_Get
332 
333 If the variable already exists, the value will not be set unless CVAR_ROM
334 The flags will be or'ed in if the variable exists.
335 ============
336 */
Cvar_Get(const char * var_name,const char * var_value,uint32_t flags,const char * var_desc)337 cvar_t *Cvar_Get( const char *var_name, const char *var_value, uint32_t flags, const char *var_desc ) {
338 	cvar_t	*var;
339 	long	hash;
340 	int		index;
341 
342     if ( !var_name || ! var_value ) {
343 		Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" );
344     }
345 
346 	if ( !Cvar_ValidateString( var_name ) ) {
347 		Com_Printf("invalid cvar name string: %s\n", var_name );
348 		var_name = "BADNAME";
349 	}
350 
351 #if 0		// FIXME: values with backslash happen
352 	if ( !Cvar_ValidateString( var_value ) ) {
353 		Com_Printf("invalid cvar value string: %s\n", var_value );
354 		var_value = "BADVALUE";
355 	}
356 #endif
357 
358 	var = Cvar_FindVar (var_name);
359 	if ( var ) {
360 		var_value = Cvar_Validate(var, var_value, qfalse);
361 
362 		// Make sure the game code cannot mark engine-added variables as gamecode vars
363 		if(var->flags & CVAR_VM_CREATED)
364 		{
365 			if(!(flags & CVAR_VM_CREATED))
366 				var->flags &= ~CVAR_VM_CREATED;
367 		}
368 		else if (!(var->flags & CVAR_USER_CREATED))
369 		{
370 			if(flags & CVAR_VM_CREATED)
371 				flags &= ~CVAR_VM_CREATED;
372 		}
373 
374 		// if the C code is now specifying a variable that the user already
375 		// set a value for, take the new value as the reset value
376 		if ( var->flags & CVAR_USER_CREATED )
377 		{
378 			var->flags &= ~CVAR_USER_CREATED;
379 			Cvar_FreeString( var->resetString );
380 			var->resetString = CopyString( var_value );
381 
382 			if(flags & CVAR_ROM)
383 			{
384 				// this variable was set by the user,
385 				// so force it to value given by the engine.
386 
387 				if(var->latchedString)
388 					Cvar_FreeString(var->latchedString);
389 
390 				var->latchedString = CopyString(var_value);
391 			}
392 		}
393 
394 		// Make sure servers cannot mark engine-added variables as SERVER_CREATED
395 		if(var->flags & CVAR_SERVER_CREATED)
396 		{
397 			if(!(flags & CVAR_SERVER_CREATED))
398 				var->flags &= ~CVAR_SERVER_CREATED;
399 		}
400 		else
401 		{
402 			if(flags & CVAR_SERVER_CREATED)
403 				flags &= ~CVAR_SERVER_CREATED;
404 		}
405 
406 		var->flags |= flags;
407 
408 		// only allow one non-empty reset string without a warning
409 		if ( !var->resetString[0] ) {
410 			// we don't have a reset string yet
411 			Cvar_FreeString( var->resetString );
412 			var->resetString = CopyString( var_value );
413 		} else if ( var_value[0] && strcmp( var->resetString, var_value ) ) {
414 			Com_DPrintf( S_COLOR_YELLOW "Warning: cvar \"%s\" given initial values: \"%s\" and \"%s\"\n",
415 				var_name, var->resetString, var_value );
416 		}
417 		// if we have a latched string, take that value now
418 		if ( var->latchedString ) {
419 			char *s;
420 
421 			s = var->latchedString;
422 			var->latchedString = NULL;	// otherwise cvar_set2 would free it
423 			Cvar_Set2( var_name, s, 0, qtrue );
424 			Cvar_FreeString( s );
425 		}
426 
427 		if ( var_desc && var_desc[0] != '\0' )
428 		{
429 			if(var->description )
430 				Cvar_FreeString( var->description );
431 			var->description = CopyString( var_desc );
432 		}
433 
434 		// ZOID--needs to be set so that cvars the game sets as
435 		// SERVERINFO get sent to clients
436 		cvar_modifiedFlags |= flags;
437 
438 		return var;
439 	}
440 
441 	//
442 	// allocate a new cvar
443 	//
444 
445 	// find a free cvar
446 	for(index = 0; index < MAX_CVARS; index++)
447 	{
448 		if(!cvar_indexes[index].name)
449 			break;
450 	}
451 
452 	if(index >= MAX_CVARS)
453 	{
454 		if(!com_errorEntered)
455 			Com_Error(ERR_FATAL, "Error: Too many cvars, cannot create a new one!");
456 
457 		return NULL;
458 	}
459 
460 	var = &cvar_indexes[index];
461 
462 	if(index >= cvar_numIndexes)
463 		cvar_numIndexes = index + 1;
464 
465 	var->name = CopyString (var_name);
466 	var->string = CopyString (var_value);
467 	if ( var_desc && var_desc[0] != '\0' )
468 		var->description = CopyString( var_desc );
469 	else
470 		var->description = NULL;
471 	var->modified = qtrue;
472 	var->modificationCount = 1;
473 	var->value = atof (var->string);
474 	var->integer = atoi(var->string);
475 	var->resetString = CopyString( var_value );
476 	var->validate = qfalse;
477 
478 	// link the variable in
479 	var->next = cvar_vars;
480 	if(cvar_vars)
481 		cvar_vars->prev = var;
482 
483 	var->prev = NULL;
484 	cvar_vars = var;
485 
486 	var->flags = flags;
487 	// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
488 	cvar_modifiedFlags |= var->flags;
489 
490 	hash = generateHashValue(var_name);
491 	var->hashIndex = hash;
492 
493 	var->hashNext = hashTable[hash];
494 	if(hashTable[hash])
495 		hashTable[hash]->hashPrev = var;
496 
497 	var->hashPrev = NULL;
498 	hashTable[hash] = var;
499 
500 	// sort on write
501 	cvar_sort = qtrue;
502 
503 	return var;
504 }
505 
Cvar_QSortByName(cvar_t ** a,int n)506 static void Cvar_QSortByName( cvar_t **a, int n )
507 {
508 	cvar_t *temp;
509 	cvar_t *m;
510 	int	i, j;
511 
512 	i = 0;
513 	j = n;
514 	m = a[ n>>1 ];
515 
516 	do {
517 		// sort in descending order
518 		while ( strcmp( a[i]->name, m->name ) > 0 ) i++;
519 		while ( strcmp( a[j]->name, m->name ) < 0 ) j--;
520 
521 		if ( i <= j ) {
522 			temp = a[i];
523 			a[i] = a[j];
524 			a[j] = temp;
525 			i++;
526 			j--;
527 		}
528 	} while ( i <= j );
529 
530 	if ( j > 0 ) Cvar_QSortByName( a, j );
531 	if ( n > i ) Cvar_QSortByName( a+i, n-i );
532 }
533 
534 
Cvar_Sort(void)535 static void Cvar_Sort( void )
536 {
537 	cvar_t *list[ MAX_CVARS ], *var;
538 	int count;
539 	int i;
540 
541 	for ( count = 0, var = cvar_vars; var; var = var->next ) {
542 		if ( var->name ) {
543 			list[ count++ ] = var;
544 		} else {
545 			Com_Error( ERR_FATAL, "Cvar_Sort: NULL cvar name" );
546 		}
547 	}
548 
549 	if ( count < 2 ) {
550 		return; // nothing to sort
551 	}
552 
553 	Cvar_QSortByName( &list[0], count-1 );
554 
555 	cvar_vars = NULL;
556 
557 	// relink cvars
558 	for ( i = 0; i < count; i++ ) {
559 		var = list[ i ];
560 		// link the variable in
561 		var->next = cvar_vars;
562 		if ( cvar_vars )
563 			cvar_vars->prev = var;
564 		var->prev = NULL;
565 		cvar_vars = var;
566 	}
567 }
568 
569 /*
570 ============
571 Cvar_Print
572 
573 Prints the value, default, and latched string of the given variable
574 ============
575 */
Cvar_Print(cvar_t * v)576 void Cvar_Print( cvar_t *v ) {
577 	Com_Printf( S_COLOR_GREY "Cvar " S_COLOR_WHITE "%s = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"" S_COLOR_WHITE, v->name, v->string );
578 
579 	if ( !(v->flags & CVAR_ROM) ) {
580 		if ( !Q_stricmp( v->string, v->resetString ) )
581 			Com_Printf( ", " S_COLOR_WHITE "the default" );
582 		else
583 			Com_Printf( ", " S_COLOR_WHITE "default = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"" S_COLOR_WHITE, v->resetString );
584 	}
585 
586 	Com_Printf( "\n" );
587 
588 	if ( v->latchedString )
589 		Com_Printf( "     latched = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"\n", v->latchedString );
590 
591 	if ( v->description )
592 		Com_Printf( "%s\n", v->description );
593 }
594 
595 /*
596 ============
597 Cvar_Set2
598 ============
599 */
Cvar_Set2(const char * var_name,const char * value,uint32_t defaultFlags,qboolean force)600 cvar_t *Cvar_Set2( const char *var_name, const char *value, uint32_t defaultFlags, qboolean force ) {
601 	cvar_t	*var;
602 
603 	if ( !Cvar_ValidateString( var_name ) ) {
604 		Com_Printf("invalid cvar name string: %s\n", var_name );
605 		var_name = "BADNAME";
606 	}
607 
608 #if 0	// FIXME
609 	if ( value && !Cvar_ValidateString( value ) ) {
610 		Com_Printf("invalid cvar value string: %s\n", value );
611 		var_value = "BADVALUE";
612 	}
613 #endif
614 
615 	var = Cvar_FindVar (var_name);
616 	if (!var) {
617 		if ( !value ) {
618 			return NULL;
619 		}
620 		// create it
621 		return Cvar_Get( var_name, value, defaultFlags );
622 	}
623 
624 	if (!value ) {
625 		value = var->resetString;
626 	}
627 
628 	value = Cvar_Validate(var, value, qtrue);
629 
630 	if((var->flags & CVAR_LATCH) && var->latchedString)
631 	{
632 		if(!strcmp(value, var->string))
633 		{
634 			Cvar_FreeString(var->latchedString);
635 			var->latchedString = NULL;
636 			return var;
637 		}
638 
639 		if(!strcmp(value, var->latchedString))
640 			return var;
641 	}
642 	else if(!strcmp(value, var->string))
643 		return var;
644 
645 	// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
646 	cvar_modifiedFlags |= var->flags;
647 
648 	if (!force)
649 	{
650 		if ( (var->flags & (CVAR_SYSTEMINFO|CVAR_SERVER_CREATED)) && CL_ConnectedToRemoteServer() )
651 		{
652 			Com_Printf ("%s can only be set by server.\n", var_name);
653 			return var;
654 		}
655 
656 		if (var->flags & CVAR_ROM)
657 		{
658 			Com_Printf ("%s is read only.\n", var_name);
659 			return var;
660 		}
661 
662 		if (var->flags & CVAR_INIT)
663 		{
664 			Com_Printf ("%s is write protected.\n", var_name);
665 			return var;
666 		}
667 
668 		if (var->flags & CVAR_LATCH)
669 		{
670 			if (var->latchedString)
671 			{
672 				if (strcmp(value, var->latchedString) == 0)
673 					return var;
674 				Cvar_FreeString (var->latchedString);
675 			}
676 			else
677 			{
678 				if (strcmp(value, var->string) == 0)
679 					return var;
680 			}
681 
682 			Com_Printf ("%s will be changed upon restarting.\n", var_name);
683 			var->latchedString = CopyString(value);
684 			var->modified = qtrue;
685 			var->modificationCount++;
686 			return var;
687 		}
688 
689 		if ( (var->flags & CVAR_CHEAT) && !cvar_cheats->integer )
690 		{
691 			Com_Printf ("%s is cheat protected.\n", var_name);
692 			return var;
693 		}
694 	}
695 	else
696 	{
697 		if (var->latchedString)
698 		{
699 			Cvar_FreeString (var->latchedString);
700 			var->latchedString = NULL;
701 		}
702 	}
703 
704 	if (!strcmp(value, var->string))
705 		return var;		// not changed
706 
707 	var->modified = qtrue;
708 	var->modificationCount++;
709 
710 	Cvar_FreeString (var->string);	// free the old value string
711 
712 	var->string = CopyString(value);
713 	var->value = atof (var->string);
714 	var->integer = atoi (var->string);
715 
716 	return var;
717 }
718 
719 /*
720 ============
721 Cvar_Set
722 
723 Force cvar to a value
724 ============
725 */
Cvar_Set(const char * var_name,const char * value)726 cvar_t *Cvar_Set( const char *var_name, const char *value) {
727 	return Cvar_Set2 (var_name, value, 0, qtrue);
728 }
729 
730 /*
731 ============
732 Cvar_SetSafe
733 
734 Try to set cvar to a value. respects CVAR_ROM, etc.
735 ============
736 */
Cvar_SetSafe(const char * var_name,const char * value)737 cvar_t *Cvar_SetSafe( const char *var_name, const char *value) {
738 	return Cvar_Set2 (var_name, value, 0, qfalse);
739 }
740 
741 /*
742 ============
743 Cvar_User_Set
744 
745 Same as Cvar_SetSafe, but have new cvars have user created flag.
746 ============
747 */
Cvar_User_Set(const char * var_name,const char * value)748 cvar_t *Cvar_User_Set( const char *var_name, const char *value) {
749 	return Cvar_Set2 (var_name, value, CVAR_USER_CREATED, qfalse);
750 }
751 
752 static const char *legacyCvars[] = {
753 	"bg_fighterAltControl",
754 	"g_dlURL",
755 	"g_synchronousClients",
756 	"jp_DlBaseURL",
757 	"pmove_fixed",
758 	"pmove_float",
759 	"pmove_msec",
760 	"vm_cgame",
761 	"vm_game",
762 	"vm_ui"
763 };
764 
765 static const size_t numLegacyCvars = ARRAY_LEN( legacyCvars );
766 
FindLegacyCvar(const char * var_name)767 static bool FindLegacyCvar( const char *var_name ) {
768 	for ( size_t i=0; i<numLegacyCvars; i++ ) {
769 		if ( !Q_stricmp( legacyCvars[i], var_name ) )
770 			return true;
771 	}
772 	return false;
773 }
774 
775 /*
776 ============
777 Cvar_Server_Set
778 
779 Set cvars from network server.
780 ============
781 */
Cvar_Server_Set(const char * var_name,const char * value)782 void Cvar_Server_Set( const char *var_name, const char *value )
783 {
784 	uint32_t flags = Cvar_Flags( var_name );
785 
786 	if ( flags != CVAR_NONEXISTENT ) {
787 		// If this cvar may not be modified by a server discard the value.
788 		// But check for ones where the legacy gamecode might still need to be allowed
789 		if(!(flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED | CVAR_USER_CREATED)))
790 		{
791 			if ( !FindLegacyCvar( var_name ) ) {
792 				Com_Printf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", var_name, value);
793 				return;
794 			}
795 		}
796 
797 		if((flags & CVAR_PROTECTED))
798 		{
799 			if( value )
800 				Com_Error( ERR_DROP, "Server tried to set \"%s\" to \"%s\"", var_name, value );
801 			else
802 				Com_Error( ERR_DROP, "Server tried to modify \"%s\"", var_name );
803 			return;
804 		}
805 	}
806 
807 	Cvar_Set2( var_name, value, CVAR_SERVER_CREATED, qtrue );
808 }
809 
810 /*
811 ============
812 Cvar_VM_Set
813 
814 Set cvar for game, cgame, or ui vm.
815 ============
816 */
Cvar_VM_Set(const char * var_name,const char * value,vmSlots_t vmslot)817 void Cvar_VM_Set( const char *var_name, const char *value, vmSlots_t vmslot )
818 {
819 	uint32_t flags = Cvar_Flags( var_name );
820 
821 	if ( vmslot != VM_GAME && (flags & CVAR_SYSTEMINFO) && CL_ConnectedToRemoteServer() )
822 	{
823 		Com_Printf ("%s can only be set by server.\n", var_name);
824 		return;
825 	}
826 
827 	if( flags != CVAR_NONEXISTENT && (flags & CVAR_PROTECTED) ) {
828 		if( value )
829 			Com_Error( ERR_DROP, "%s tried to set \"%s\" to \"%s\"", vmStrs[vmslot], var_name, value );
830 		else
831 			Com_Error( ERR_DROP, "%s tried to modify \"%s\"", vmStrs[vmslot], var_name );
832 		return;
833 	}
834 
835 	Cvar_Set2( var_name, value, CVAR_VM_CREATED, qtrue );
836 }
837 
838 /*
839 ============
840 Cvar_SetValue
841 ============
842 */
Cvar_SetValue(const char * var_name,float value)843 cvar_t *Cvar_SetValue( const char *var_name, float value) {
844 	char	val[32];
845 
846 	if( Q_isintegral( value ) )
847 		Com_sprintf (val, sizeof(val), "%i", (int)value);
848 	else
849 		Com_sprintf (val, sizeof(val), "%f", value);
850 
851 	return Cvar_Set (var_name, val);
852 }
853 
854 /*
855 ============
856 Cvar_User_SetValue
857 ============
858 */
Cvar_User_SetValue(const char * var_name,float value)859 void Cvar_User_SetValue( const char *var_name, float value) {
860 	char	val[32];
861 
862 	if( Q_isintegral( value ) )
863 		Com_sprintf (val, sizeof(val), "%i", (int)value);
864 	else
865 		Com_sprintf (val, sizeof(val), "%f", value);
866 
867 	Cvar_User_Set (var_name, val);
868 }
869 
870 /*
871 ============
872 Cvar_VM_SetValue
873 ============
874 */
Cvar_VM_SetValue(const char * var_name,float value,vmSlots_t vmslot)875 void Cvar_VM_SetValue( const char *var_name, float value, vmSlots_t vmslot ) {
876 	char	val[32];
877 
878 	if( Q_isintegral( value ) )
879 		Com_sprintf (val, sizeof(val), "%i", (int)value);
880 	else
881 		Com_sprintf (val, sizeof(val), "%f", value);
882 
883 	Cvar_VM_Set (var_name, val, vmslot);
884 }
885 
886 /*
887 ============
888 Cvar_Reset
889 ============
890 */
Cvar_Reset(const char * var_name)891 void Cvar_Reset( const char *var_name ) {
892 	Cvar_SetSafe( var_name, NULL );
893 }
894 
895 /*
896 ============
897 Cvar_ForceReset
898 ============
899 */
Cvar_ForceReset(const char * var_name)900 void Cvar_ForceReset(const char *var_name)
901 {
902 	Cvar_Set(var_name, NULL);
903 }
904 
905 /*
906 ============
907 Cvar_SetCheatState
908 
909 Any testing variables will be reset to the safe values
910 ============
911 */
Cvar_SetCheatState(void)912 void Cvar_SetCheatState( void ) {
913 	cvar_t	*var;
914 
915 	// set all default vars to the safe value
916 	for ( var = cvar_vars ; var ; var = var->next ) {
917 		if ( var->flags & CVAR_CHEAT ) {
918 			// the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
919 			// because of a different var->latchedString
920 			if (var->latchedString)
921 			{
922 				Cvar_FreeString(var->latchedString);
923 				var->latchedString = NULL;
924 			}
925 			if (strcmp(var->resetString,var->string)) {
926 				Cvar_Set( var->name, var->resetString );
927 			}
928 		}
929 	}
930 }
931 
932 /*
933 ============
934 Cvar_Command
935 
936 Handles variable inspection and changing from the console
937 ============
938 */
Cvar_Command(void)939 qboolean Cvar_Command( void ) {
940 	cvar_t			*v;
941 
942 	// check variables
943 	v = Cvar_FindVar (Cmd_Argv(0));
944 	if (!v) {
945 		return qfalse;
946 	}
947 
948 	// perform a variable print or set
949 	if ( Cmd_Argc() == 1 )
950 	{
951 		Cvar_Print( v );
952 		return qtrue;
953 	}
954 
955 	// toggle
956 	if( !strcmp( Cmd_Argv(1), "!" ) )
957 	{
958 		// Swap the value if our command has ! in it (bind p "cg_thirdPeson !")
959 		Cvar_User_SetValue( v->name, !v->value );
960 		return qtrue;
961 	}
962 
963 	// set the value if forcing isn't required
964 	Cvar_User_Set (v->name, Cmd_Args());
965 	return qtrue;
966 }
967 
968 /*
969 ============
970 Cvar_Print_f
971 
972 Prints the contents of a cvar
973 (preferred over Cvar_Command where cvar names and commands conflict)
974 ============
975 */
Cvar_Print_f(void)976 void Cvar_Print_f(void)
977 {
978 	char *name;
979 	cvar_t *cv;
980 
981 	if(Cmd_Argc() != 2)
982 	{
983 		Com_Printf ("usage: print <variable>\n");
984 		return;
985 	}
986 
987 	name = Cmd_Argv(1);
988 
989 	cv = Cvar_FindVar(name);
990 
991 	if(cv)
992 		Cvar_Print(cv);
993 	else
994 		Com_Printf ("Cvar %s does not exist.\n", name);
995 }
996 
997 /*
998 ============
999 Cvar_Toggle_f
1000 
1001 Toggles a cvar for easy single key binding, optionally through a list of
1002 given values
1003 ============
1004 */
Cvar_Toggle_f(void)1005 void Cvar_Toggle_f( void ) {
1006 	int		i, c = Cmd_Argc();
1007 	char		*curval;
1008 
1009 	if(c < 2) {
1010 		Com_Printf("usage: toggle <variable> [value1, value2, ...]\n");
1011 		return;
1012 	}
1013 
1014 	if(c == 2) {
1015 		Cvar_User_SetValue(Cmd_Argv(1), !Cvar_VariableValue(Cmd_Argv(1)));
1016 		return;
1017 	}
1018 
1019 	if(c == 3) {
1020 		Com_Printf("toggle: nothing to toggle to\n");
1021 		return;
1022 	}
1023 
1024 	curval = Cvar_VariableString(Cmd_Argv(1));
1025 
1026 	// don't bother checking the last arg for a match since the desired
1027 	// behaviour is the same as no match (set to the first argument)
1028 	for(i = 2; i + 1 < c; i++) {
1029 		if(strcmp(curval, Cmd_Argv(i)) == 0) {
1030 			Cvar_User_Set(Cmd_Argv(1), Cmd_Argv(i + 1));
1031 			return;
1032 		}
1033 	}
1034 
1035 	// fallback
1036 	Cvar_User_Set(Cmd_Argv(1), Cmd_Argv(2));
1037 }
1038 
1039 /*
1040 ============
1041 Cvar_Set_f
1042 
1043 Allows setting and defining of arbitrary cvars from console, even if they
1044 weren't declared in C code.
1045 ============
1046 */
Cvar_Set_f(void)1047 void Cvar_Set_f( void ) {
1048 	int		c;
1049 	char	*cmd;
1050 	cvar_t	*v;
1051 
1052 	c = Cmd_Argc();
1053 	cmd = Cmd_Argv(0);
1054 
1055 	if ( c < 2 ) {
1056 		Com_Printf ("usage: %s <variable> <value>\n", cmd);
1057 		return;
1058 	}
1059 	if ( c == 2 ) {
1060 		Cvar_Print_f();
1061 		return;
1062 	}
1063 
1064 	v = Cvar_User_Set (Cmd_Argv(1), Cmd_ArgsFrom(2));
1065 	if( !v ) {
1066 		return;
1067 	}
1068 	switch( cmd[3] ) {
1069 		case 'a':
1070 			if( !( v->flags & CVAR_ARCHIVE ) ) {
1071 				v->flags |= CVAR_ARCHIVE;
1072 				cvar_modifiedFlags |= CVAR_ARCHIVE;
1073 			}
1074 			break;
1075 		case 'u':
1076 			if( !( v->flags & CVAR_USERINFO ) ) {
1077 				v->flags |= CVAR_USERINFO;
1078 				cvar_modifiedFlags |= CVAR_USERINFO;
1079 			}
1080 			break;
1081 		case 's':
1082 			if( !( v->flags & CVAR_SERVERINFO ) ) {
1083 				v->flags |= CVAR_SERVERINFO;
1084 				cvar_modifiedFlags |= CVAR_SERVERINFO;
1085 			}
1086 			break;
1087 	}
1088 }
1089 
1090 /*
1091 ============
1092 Cvar_Math_f
1093 ============
1094 */
Cvar_Math_f(void)1095 void Cvar_Math_f( void )
1096 {
1097 	int		c;
1098 	char	*cmd;
1099 
1100 	c = Cmd_Argc();
1101 	cmd = Cmd_Argv( 0 );
1102 
1103 	if ( c != 3 )
1104 	{
1105 		Com_Printf( "usage: %s <variable> <value>\n", cmd );
1106 		return;
1107 	}
1108 
1109 	if ( !Q_stricmp( cmd, "cvarAdd" ) )
1110 	{
1111 		Cvar_User_SetValue( Cmd_Argv( 1 ), Cvar_VariableValue( Cmd_Argv( 1 ) ) + atof( Cmd_Argv( 2 ) ) );
1112 	}
1113 	else if ( !Q_stricmp( cmd, "cvarSub" ) )
1114 	{
1115 		Cvar_User_SetValue( Cmd_Argv( 1 ), Cvar_VariableValue( Cmd_Argv( 1 ) ) - atof( Cmd_Argv( 2 ) ) );
1116 	}
1117 	else if ( !Q_stricmp( cmd, "cvarMult" ) )
1118 	{
1119 		Cvar_User_SetValue( Cmd_Argv( 1 ), Cvar_VariableValue( Cmd_Argv( 1 ) ) * atof( Cmd_Argv( 2 ) ) );
1120 	}
1121 	else if ( !Q_stricmp( cmd, "cvarDiv" ) )
1122 	{
1123 		float value = atof( Cmd_Argv( 2 ) );
1124 		if ( value != 0 )
1125 			Cvar_User_SetValue( Cmd_Argv( 1 ), Cvar_VariableValue( Cmd_Argv( 1 ) ) / value );
1126 		else
1127 			Com_Printf( "Cannot divide by zero!\n" );
1128 	}
1129 	else if ( !Q_stricmp( cmd, "cvarMod" ) )
1130 	{
1131 		Cvar_User_SetValue( Cmd_Argv( 1 ), Cvar_VariableIntegerValue( Cmd_Argv( 1 ) ) % atoi( Cmd_Argv( 2 ) ) );
1132 	}
1133 }
1134 
1135 /*
1136 ============
1137 Cvar_Reset_f
1138 ============
1139 */
Cvar_Reset_f(void)1140 void Cvar_Reset_f( void ) {
1141 	if ( Cmd_Argc() != 2 ) {
1142 		Com_Printf ("usage: reset <variable>\n");
1143 		return;
1144 	}
1145 	Cvar_Reset( Cmd_Argv( 1 ) );
1146 }
1147 
1148 /*
1149 ============
1150 Cvar_WriteVariables
1151 
1152 Appends lines containing "set variable value" for all variables
1153 with the archive flag set to qtrue.
1154 ============
1155 */
Cvar_WriteVariables(fileHandle_t f)1156 void Cvar_WriteVariables( fileHandle_t f ) {
1157 	cvar_t	*var;
1158 	char buffer[1024];
1159 
1160 	if ( cvar_sort ) {
1161 		Com_DPrintf( "Cvar_Sort: sort cvars\n" );
1162 		cvar_sort = qfalse;
1163 		Cvar_Sort();
1164 	}
1165 
1166 	for ( var = cvar_vars; var; var = var->next )
1167 	{
1168 		if ( !var->name || Q_stricmp( var->name, "cl_cdkey" ) == 0 )
1169 			continue;
1170 
1171 		if ( var->flags & CVAR_ARCHIVE ) {
1172 			// write the latched value, even if it hasn't taken effect yet
1173 			if ( var->latchedString ) {
1174 				if( strlen( var->name ) + strlen( var->latchedString ) + 10 > sizeof( buffer ) ) {
1175 					Com_Printf( S_COLOR_YELLOW "WARNING: value of variable "
1176 							"\"%s\" too long to write to file\n", var->name );
1177 					continue;
1178 				}
1179 				if ( (var->flags & CVAR_NODEFAULT) && !strcmp( var->latchedString, var->resetString ) ) {
1180 					continue;
1181 				}
1182 				Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->latchedString);
1183 			} else {
1184 				if( strlen( var->name ) + strlen( var->string ) + 10 > sizeof( buffer ) ) {
1185 					Com_Printf( S_COLOR_YELLOW "WARNING: value of variable "
1186 							"\"%s\" too long to write to file\n", var->name );
1187 					continue;
1188 				}
1189 				if ( (var->flags & CVAR_NODEFAULT) && !strcmp( var->string, var->resetString ) ) {
1190 					continue;
1191 				}
1192 				Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->string);
1193 			}
1194 			FS_Write( buffer, strlen( buffer ), f );
1195 		}
1196 	}
1197 }
1198 
1199 /*
1200 ============
1201 Cvar_List_f
1202 ============
1203 */
Cvar_List_f(void)1204 void Cvar_List_f( void ) {
1205 	cvar_t *var = NULL;
1206 	int i = 0;
1207 	char *match = NULL;
1208 
1209 	if ( Cmd_Argc() > 1 )
1210 		match = Cmd_Argv( 1 );
1211 
1212 	for ( var=cvar_vars, i=0;
1213 		var;
1214 		var=var->next, i++ )
1215 	{
1216 		if ( !var->name || (match && !Com_Filter( match, var->name, qfalse )) )
1217 			continue;
1218 
1219 		if (var->flags & CVAR_SERVERINFO)	Com_Printf( "S" );	else Com_Printf( " " );
1220 		if (var->flags & CVAR_SYSTEMINFO)	Com_Printf( "s" );	else Com_Printf( " " );
1221 		if (var->flags & CVAR_USERINFO)		Com_Printf( "U" );	else Com_Printf( " " );
1222 		if (var->flags & CVAR_ROM)			Com_Printf( "R" );	else Com_Printf( " " );
1223 		if (var->flags & CVAR_INIT)			Com_Printf( "I" );	else Com_Printf( " " );
1224 		if (var->flags & CVAR_ARCHIVE)		Com_Printf( "A" );	else Com_Printf( " " );
1225 		if (var->flags & CVAR_LATCH)		Com_Printf( "L" );	else Com_Printf( " " );
1226 		if (var->flags & CVAR_CHEAT)		Com_Printf( "C" );	else Com_Printf( " " );
1227 		if (var->flags & CVAR_USER_CREATED)	Com_Printf( "?" );	else Com_Printf( " " );
1228 
1229 		Com_Printf( S_COLOR_WHITE " %s = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"" S_COLOR_WHITE, var->name, var->string );
1230 		if ( var->latchedString )
1231 			Com_Printf( ", latched = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"" S_COLOR_WHITE, var->latchedString );
1232 		Com_Printf( "\n" );
1233 	}
1234 
1235 	Com_Printf( "\n%i total cvars\n", i );
1236 	if ( i != cvar_numIndexes )
1237 		Com_Printf( "%i cvar indexes\n", cvar_numIndexes );
1238 }
1239 
Cvar_ListModified_f(void)1240 void Cvar_ListModified_f( void ) {
1241 	cvar_t *var = NULL;
1242 
1243 	// build a list of cvars that are modified
1244 	for ( var=cvar_vars;
1245 		var;
1246 		var=var->next )
1247 	{
1248 		char *value = var->latchedString ? var->latchedString : var->string;
1249 		if ( !var->name || !var->modificationCount || !strcmp( value, var->resetString ) )
1250 			continue;
1251 
1252 		Com_Printf( S_COLOR_GREY "Cvar "
1253 			S_COLOR_WHITE "%s = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"" S_COLOR_WHITE ", "
1254 			S_COLOR_WHITE "default = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"" S_COLOR_WHITE "\n",
1255 			var->name, value, var->resetString );
1256 	}
1257 }
1258 
Cvar_ListUserCreated_f(void)1259 void Cvar_ListUserCreated_f( void ) {
1260 	cvar_t *var = NULL;
1261 	uint32_t count = 0;
1262 
1263 	// build a list of cvars that are modified
1264 	for ( var=cvar_vars;
1265 		var;
1266 		var=var->next )
1267 	{
1268 		char *value = var->latchedString ? var->latchedString : var->string;
1269 		if ( !(var->flags & CVAR_USER_CREATED) )
1270 			continue;
1271 
1272 		Com_Printf( S_COLOR_GREY "Cvar "
1273 			S_COLOR_WHITE "%s = " S_COLOR_GREY "\"" S_COLOR_WHITE "%s" S_COLOR_GREY "\"" S_COLOR_WHITE "\n",
1274 			var->name, value );
1275 		count++;
1276 	}
1277 
1278 	if ( count > 0 )
1279 		Com_Printf( S_COLOR_GREY "Showing " S_COLOR_WHITE "%u" S_COLOR_GREY " user created cvars" S_COLOR_WHITE "\n", count );
1280 	else
1281 		Com_Printf( S_COLOR_GREY "No user created cvars" S_COLOR_WHITE "\n" );
1282 }
1283 
1284 /*
1285 ============
1286 Cvar_Unset
1287 
1288 Unsets a cvar
1289 ============
1290 */
1291 
Cvar_Unset(cvar_t * cv)1292 cvar_t *Cvar_Unset(cvar_t *cv)
1293 {
1294 	cvar_t *next = cv->next;
1295 
1296 	// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
1297 	cvar_modifiedFlags |= cv->flags;
1298 
1299 	if(cv->name)
1300 		Cvar_FreeString(cv->name);
1301 	if(cv->description)
1302 		Cvar_FreeString(cv->description);
1303 	if(cv->string)
1304 		Cvar_FreeString(cv->string);
1305 	if(cv->latchedString)
1306 		Cvar_FreeString(cv->latchedString);
1307 	if(cv->resetString)
1308 		Cvar_FreeString(cv->resetString);
1309 
1310 	if(cv->prev)
1311 		cv->prev->next = cv->next;
1312 	else
1313 		cvar_vars = cv->next;
1314 	if(cv->next)
1315 		cv->next->prev = cv->prev;
1316 
1317 	if(cv->hashPrev)
1318 		cv->hashPrev->hashNext = cv->hashNext;
1319 	else
1320 		hashTable[cv->hashIndex] = cv->hashNext;
1321 	if(cv->hashNext)
1322 		cv->hashNext->hashPrev = cv->hashPrev;
1323 
1324 	memset(cv, 0, sizeof(*cv));
1325 
1326 	return next;
1327 }
1328 
1329 /*
1330 ============
1331 Cvar_Unset_f
1332 
1333 Unsets a userdefined cvar
1334 ============
1335 */
1336 
Cvar_Unset_f(void)1337 void Cvar_Unset_f(void)
1338 {
1339 	cvar_t *cv;
1340 
1341 	if(Cmd_Argc() != 2)
1342 	{
1343 		Com_Printf("Usage: %s <varname>\n", Cmd_Argv(0));
1344 		return;
1345 	}
1346 
1347 	cv = Cvar_FindVar(Cmd_Argv(1));
1348 
1349 	if(!cv)
1350 		return;
1351 
1352 	if(cv->flags & CVAR_USER_CREATED)
1353 		Cvar_Unset(cv);
1354 	else
1355 		Com_Printf("Error: %s: Variable %s is not user created.\n", Cmd_Argv(0), cv->name);
1356 }
1357 
Cvar_UnsetUserCreated_f(void)1358 void Cvar_UnsetUserCreated_f(void)
1359 {
1360 	cvar_t	*curvar = cvar_vars;
1361 	uint32_t count = 0;
1362 
1363 	while ( curvar )
1364 	{
1365 		if ( ( curvar->flags & CVAR_USER_CREATED ) )
1366 		{
1367 			// throw out any variables the user created
1368 			curvar = Cvar_Unset( curvar );
1369 			count++;
1370 			continue;
1371 		}
1372 		curvar = curvar->next;
1373 	}
1374 
1375 	if ( count > 0 )
1376 		Com_Printf( S_COLOR_GREY "Removed " S_COLOR_WHITE "%u" S_COLOR_GREY " user created cvars" S_COLOR_WHITE "\n", count );
1377 	else
1378 		Com_Printf( S_COLOR_GREY "No user created cvars to remove" S_COLOR_WHITE "\n" );
1379 }
1380 
1381 /*
1382 ============
1383 Cvar_Restart
1384 
1385 Resets all cvars to their hardcoded values and removes userdefined variables
1386 and variables added via the VMs if requested.
1387 ============
1388 */
1389 
Cvar_Restart(qboolean unsetVM)1390 void Cvar_Restart(qboolean unsetVM)
1391 {
1392 	cvar_t	*curvar;
1393 
1394 	curvar = cvar_vars;
1395 
1396 	while(curvar)
1397 	{
1398 		if((curvar->flags & CVAR_USER_CREATED) ||
1399 			(unsetVM && (curvar->flags & CVAR_VM_CREATED)))
1400 		{
1401 			// throw out any variables the user/vm created
1402 			curvar = Cvar_Unset(curvar);
1403 			continue;
1404 		}
1405 
1406 		if(!(curvar->flags & (CVAR_ROM | CVAR_INIT | CVAR_NORESTART)))
1407 		{
1408 			// Just reset the rest to their default values.
1409 			Cvar_SetSafe(curvar->name, curvar->resetString);
1410 		}
1411 
1412 		curvar = curvar->next;
1413 	}
1414 }
1415 
1416 /*
1417 ============
1418 Cvar_Restart_f
1419 
1420 Resets all cvars to their hardcoded values
1421 ============
1422 */
Cvar_Restart_f(void)1423 void Cvar_Restart_f( void ) {
1424 	Cvar_Restart(qfalse);
1425 }
1426 
1427 /*
1428 =====================
1429 Cvar_InfoString
1430 =====================
1431 */
Cvar_InfoString(int bit)1432 char	*Cvar_InfoString( int bit ) {
1433 	static char	info[MAX_INFO_STRING];
1434 	cvar_t	*var;
1435 
1436 	info[0] = 0;
1437 
1438 	for (var = cvar_vars ; var ; var = var->next)
1439 	{
1440 		if (!(var->flags & CVAR_INTERNAL) && var->name &&
1441 			(var->flags & bit))
1442 		{
1443 			Info_SetValueForKey (info, var->name, var->string);
1444 		}
1445 	}
1446 
1447 	return info;
1448 }
1449 
1450 /*
1451 =====================
1452 Cvar_InfoString_Big
1453 
1454   handles large info strings ( CS_SYSTEMINFO )
1455 =====================
1456 */
Cvar_InfoString_Big(int bit)1457 char	*Cvar_InfoString_Big( int bit ) {
1458 	static char	info[BIG_INFO_STRING];
1459 	cvar_t	*var;
1460 
1461 	info[0] = 0;
1462 
1463 	for (var = cvar_vars ; var ; var = var->next)
1464 	{
1465 		if (!(var->flags & CVAR_INTERNAL) && var->name &&
1466 			(var->flags & bit))
1467 		{
1468 			Info_SetValueForKey_Big (info, var->name, var->string);
1469 		}
1470 	}
1471 	return info;
1472 }
1473 
1474 /*
1475 =====================
1476 Cvar_InfoStringBuffer
1477 =====================
1478 */
Cvar_InfoStringBuffer(int bit,char * buff,int buffsize)1479 void Cvar_InfoStringBuffer( int bit, char* buff, int buffsize ) {
1480 	Q_strncpyz(buff,Cvar_InfoString(bit),buffsize);
1481 }
1482 
1483 /*
1484 =====================
1485 Cvar_CheckRange
1486 =====================
1487 */
Cvar_CheckRange(cvar_t * var,float min,float max,qboolean integral)1488 void Cvar_CheckRange( cvar_t *var, float min, float max, qboolean integral )
1489 {
1490 	var->validate = qtrue;
1491 	var->min = min;
1492 	var->max = max;
1493 	var->integral = integral;
1494 
1495 	// Force an initial range check
1496 	Cvar_Set( var->name, var->string );
1497 }
1498 
1499 /*
1500 =====================
1501 Cvar_Register
1502 
1503 basically a slightly modified Cvar_Get for the interpreted modules
1504 =====================
1505 */
Cvar_Register(vmCvar_t * vmCvar,const char * varName,const char * defaultValue,uint32_t flags)1506 void	Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, uint32_t flags ) {
1507 	cvar_t	*cv;
1508 
1509 	// There is code in Cvar_Get to prevent CVAR_ROM cvars being changed by the user. In other words CVAR_ARCHIVE and
1510 	//	CVAR_ROM are mutually exclusive flags. Unfortunately some historical game code (including single player baseq3)
1511 	//	sets both flags. We unset CVAR_ROM for such cvars.
1512 	if ((flags & (CVAR_ARCHIVE | CVAR_ROM)) == (CVAR_ARCHIVE | CVAR_ROM)) {
1513 		Com_DPrintf( S_COLOR_YELLOW "WARNING: Unsetting CVAR_ROM cvar '%s', since it is also CVAR_ARCHIVE\n", varName );
1514 		flags &= ~CVAR_ROM;
1515 	}
1516 
1517 	cv = Cvar_Get( varName, defaultValue, flags | CVAR_VM_CREATED );
1518 	if ( !vmCvar ) {
1519 		return;
1520 	}
1521 	vmCvar->handle = cv - cvar_indexes;
1522 	vmCvar->modificationCount = -1;
1523 	Cvar_Update( vmCvar );
1524 }
1525 
1526 
1527 /*
1528 =====================
1529 Cvar_Update
1530 
1531 updates an interpreted modules' version of a cvar
1532 =====================
1533 */
Cvar_Update(vmCvar_t * vmCvar)1534 void	Cvar_Update( vmCvar_t *vmCvar ) {
1535 	cvar_t	*cv = NULL;
1536 	assert(vmCvar);
1537 
1538 	if ( (unsigned)vmCvar->handle >= (unsigned)cvar_numIndexes ) {
1539 		Com_Error( ERR_DROP, "Cvar_Update: handle %u out of range", (unsigned)vmCvar->handle );
1540 	}
1541 
1542 	cv = cvar_indexes + vmCvar->handle;
1543 
1544 	if ( cv->modificationCount == vmCvar->modificationCount ) {
1545 		return;
1546 	}
1547 	if ( !cv->string ) {
1548 		return;		// variable might have been cleared by a cvar_restart
1549 	}
1550 	vmCvar->modificationCount = cv->modificationCount;
1551 	if ( strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING )
1552 		Com_Error( ERR_DROP, "Cvar_Update: src %s length %u exceeds MAX_CVAR_VALUE_STRING", cv->string, (unsigned int) strlen(cv->string));
1553 	Q_strncpyz( vmCvar->string, cv->string, MAX_CVAR_VALUE_STRING );
1554 
1555 	vmCvar->value = cv->value;
1556 	vmCvar->integer = cv->integer;
1557 }
1558 
1559 /*
1560 ==================
1561 Cvar_CompleteCvarName
1562 ==================
1563 */
Cvar_CompleteCvarName(char * args,int argNum)1564 void Cvar_CompleteCvarName( char *args, int argNum )
1565 {
1566 	if( argNum == 2 )
1567 	{
1568 		// Skip "<cmd> "
1569 		char *p = Com_SkipTokens( args, 1, " " );
1570 
1571 		if( p > args )
1572 			Field_CompleteCommand( p, qfalse, qtrue );
1573 	}
1574 }
1575 
1576 /*
1577 ============
1578 Cvar_Init
1579 
1580 Reads in all archived cvars
1581 ============
1582 */
Cvar_Init(void)1583 void Cvar_Init (void) {
1584 	memset( cvar_indexes, 0, sizeof( cvar_indexes ) );
1585 	memset( hashTable, 0, sizeof( hashTable ) );
1586 
1587 	cvar_cheats = Cvar_Get( "sv_cheats", "1", CVAR_ROM|CVAR_SYSTEMINFO, "Allow cheats on server if set to 1" );
1588 
1589 	Cmd_AddCommand( "print", Cvar_Print_f, "Print cvar help" );
1590 	Cmd_SetCommandCompletionFunc( "print", Cvar_CompleteCvarName );
1591 	Cmd_AddCommand( "toggle", Cvar_Toggle_f, "Toggle a cvar between values" );
1592 	Cmd_SetCommandCompletionFunc( "toggle", Cvar_CompleteCvarName );
1593 	Cmd_AddCommand( "set", Cvar_Set_f, "Set a cvar" );
1594 	Cmd_SetCommandCompletionFunc( "set", Cvar_CompleteCvarName );
1595 	Cmd_AddCommand( "sets", Cvar_Set_f, "Set a cvar and apply serverinfo flag" );
1596 	Cmd_SetCommandCompletionFunc( "sets", Cvar_CompleteCvarName );
1597 	Cmd_AddCommand( "setu", Cvar_Set_f, "Set a cvar and apply userinfo flag" );
1598 	Cmd_SetCommandCompletionFunc( "setu", Cvar_CompleteCvarName );
1599 	Cmd_AddCommand( "seta", Cvar_Set_f, "Set a cvar and apply archive flag" );
1600 	Cmd_SetCommandCompletionFunc( "seta", Cvar_CompleteCvarName );
1601 	Cmd_AddCommand( "cvarAdd", Cvar_Math_f, "Add a value to a cvar" );
1602 	Cmd_SetCommandCompletionFunc( "cvarAdd", Cvar_CompleteCvarName );
1603 	Cmd_AddCommand( "cvarSub", Cvar_Math_f, "Subtract a value from a cvar" );
1604 	Cmd_SetCommandCompletionFunc( "cvarSub", Cvar_CompleteCvarName );
1605 	Cmd_AddCommand( "cvarMult", Cvar_Math_f, "Multiply a value to a cvar" );
1606 	Cmd_SetCommandCompletionFunc( "cvarMult", Cvar_CompleteCvarName );
1607 	Cmd_AddCommand( "cvarDiv", Cvar_Math_f, "Divide a value from a cvar" );
1608 	Cmd_SetCommandCompletionFunc( "cvarDiv", Cvar_CompleteCvarName );
1609 	Cmd_AddCommand( "cvarMod", Cvar_Math_f, "Apply a modulo on a cvar" );
1610 	Cmd_SetCommandCompletionFunc( "cvarMod", Cvar_CompleteCvarName );
1611 	Cmd_AddCommand( "reset", Cvar_Reset_f, "Reset a cvar to default" );
1612 	Cmd_SetCommandCompletionFunc( "reset", Cvar_CompleteCvarName );
1613 	Cmd_AddCommand( "unset", Cvar_Unset_f, "Unset a user generated cvar" );
1614 	Cmd_SetCommandCompletionFunc( "unset", Cvar_CompleteCvarName );
1615 	Cmd_AddCommand( "unset_usercreated", Cvar_UnsetUserCreated_f, "Unset all user generated cvars " S_COLOR_RED "Use with caution!" S_COLOR_WHITE );
1616 	Cmd_AddCommand( "cvarlist", Cvar_List_f, "Show all cvars" );
1617 	Cmd_AddCommand( "cvar_usercreated", Cvar_ListUserCreated_f, "Show all user created cvars" );
1618 	Cmd_AddCommand( "cvar_modified", Cvar_ListModified_f, "Show all modified cvars" );
1619 	Cmd_AddCommand( "cvar_restart", Cvar_Restart_f, "Resetart the cvar sub-system" );
1620 }
1621 
Cvar_Realloc(char ** string,char * memPool,int & memPoolUsed)1622 static void Cvar_Realloc(char **string, char *memPool, int &memPoolUsed)
1623 {
1624 	if(string && *string)
1625 	{
1626 		char *temp = memPool + memPoolUsed;
1627 		strcpy(temp, *string);
1628 		memPoolUsed += strlen(*string) + 1;
1629 		Cvar_FreeString(*string);
1630 		*string = temp;
1631 	}
1632 }
1633 
1634 
1635 //Turns many small allocation blocks into one big one.
Cvar_Defrag(void)1636 void Cvar_Defrag(void)
1637 {
1638 	cvar_t	*var;
1639 	int totalMem = 0;
1640 	int nextMemPoolSize;
1641 
1642 	for (var = cvar_vars; var; var = var->next)
1643 	{
1644 		if (var->name) {
1645 			totalMem += strlen(var->name) + 1;
1646 		}
1647 		if (var->description) {
1648 			totalMem += strlen(var->description) + 1;
1649 		}
1650 		if (var->string) {
1651 			totalMem += strlen(var->string) + 1;
1652 		}
1653 		if (var->resetString) {
1654 			totalMem += strlen(var->resetString) + 1;
1655 		}
1656 		if (var->latchedString) {
1657 			totalMem += strlen(var->latchedString) + 1;
1658 		}
1659 	}
1660 
1661 	char *mem = (char*)Z_Malloc(totalMem, TAG_SMALL, qfalse);
1662 	nextMemPoolSize = totalMem;
1663 	totalMem = 0;
1664 
1665 	for (var = cvar_vars; var; var = var->next)
1666 	{
1667 		Cvar_Realloc(&var->name, mem, totalMem);
1668 		Cvar_Realloc(&var->string, mem, totalMem);
1669 		Cvar_Realloc(&var->resetString, mem, totalMem);
1670 		Cvar_Realloc(&var->latchedString, mem, totalMem);
1671 		Cvar_Realloc(&var->description, mem, totalMem);
1672 	}
1673 
1674 	if(lastMemPool) {
1675 		Z_Free(lastMemPool);
1676 	}
1677 	lastMemPool = mem;
1678 	memPoolSize = nextMemPoolSize;
1679 }
1680 
1681