1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 // cvar.c -- dynamic variable tracking
23 
24 #include "q_shared.h"
25 #include "qcommon.h"
26 
27 cvar_t		*cvar_vars;
28 cvar_t		*cvar_cheats;
29 int			cvar_modifiedFlags;
30 
31 #define	MAX_CVARS	1024
32 cvar_t		cvar_indexes[MAX_CVARS];
33 int			cvar_numIndexes;
34 
35 #define FILE_HASH_SIZE		256
36 static	cvar_t*		hashTable[FILE_HASH_SIZE];
37 
38 cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force);
39 
40 /*
41 ================
42 return a hash value for the filename
43 ================
44 */
generateHashValue(const char * fname)45 static long generateHashValue( const char *fname ) {
46 	int		i;
47 	long	hash;
48 	char	letter;
49 
50 	hash = 0;
51 	i = 0;
52 	while (fname[i] != '\0') {
53 		letter = tolower(fname[i]);
54 		hash+=(long)(letter)*(i+119);
55 		i++;
56 	}
57 	hash &= (FILE_HASH_SIZE-1);
58 	return hash;
59 }
60 
61 /*
62 ============
63 Cvar_ValidateString
64 ============
65 */
Cvar_ValidateString(const char * s)66 static qboolean Cvar_ValidateString( const char *s ) {
67 	if ( !s ) {
68 		return qfalse;
69 	}
70 	if ( strchr( s, '\\' ) ) {
71 		return qfalse;
72 	}
73 	if ( strchr( s, '\"' ) ) {
74 		return qfalse;
75 	}
76 	if ( strchr( s, ';' ) ) {
77 		return qfalse;
78 	}
79 	return qtrue;
80 }
81 
82 /*
83 ============
84 Cvar_FindVar
85 ============
86 */
Cvar_FindVar(const char * var_name)87 static cvar_t *Cvar_FindVar( const char *var_name ) {
88 	cvar_t	*var;
89 	long hash;
90 
91 	hash = generateHashValue(var_name);
92 
93 	for (var=hashTable[hash] ; var ; var=var->hashNext) {
94 		if (!Q_stricmp(var_name, var->name)) {
95 			return var;
96 		}
97 	}
98 
99 	return NULL;
100 }
101 
102 /*
103 ============
104 Cvar_VariableValue
105 ============
106 */
Cvar_VariableValue(const char * var_name)107 float Cvar_VariableValue( const char *var_name ) {
108 	cvar_t	*var;
109 
110 	var = Cvar_FindVar (var_name);
111 	if (!var)
112 		return 0;
113 	return var->value;
114 }
115 
116 
117 /*
118 ============
119 Cvar_VariableIntegerValue
120 ============
121 */
Cvar_VariableIntegerValue(const char * var_name)122 int Cvar_VariableIntegerValue( const char *var_name ) {
123 	cvar_t	*var;
124 
125 	var = Cvar_FindVar (var_name);
126 	if (!var)
127 		return 0;
128 	return var->integer;
129 }
130 
131 
132 /*
133 ============
134 Cvar_VariableString
135 ============
136 */
Cvar_VariableString(const char * var_name)137 char *Cvar_VariableString( const char *var_name ) {
138 	cvar_t *var;
139 
140 	var = Cvar_FindVar (var_name);
141 	if (!var)
142 		return "";
143 	return var->string;
144 }
145 
146 
147 /*
148 ============
149 Cvar_VariableStringBuffer
150 ============
151 */
Cvar_VariableStringBuffer(const char * var_name,char * buffer,int bufsize)152 void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
153 	cvar_t *var;
154 
155 	var = Cvar_FindVar (var_name);
156 	if (!var) {
157 		*buffer = 0;
158 	}
159 	else {
160 		Q_strncpyz( buffer, var->string, bufsize );
161 	}
162 }
163 
164 /*
165 ============
166 Cvar_Flags
167 ============
168 */
Cvar_Flags(const char * var_name)169 int Cvar_Flags(const char *var_name)
170 {
171 	cvar_t *var;
172 
173 	if(! (var = Cvar_FindVar(var_name)) )
174 		return CVAR_NONEXISTENT;
175 	else
176 		return var->flags;
177 }
178 
179 /*
180 ============
181 Cvar_CommandCompletion
182 ============
183 */
Cvar_CommandCompletion(void (* callback)(const char * s))184 void	Cvar_CommandCompletion( void(*callback)(const char *s) ) {
185 	cvar_t		*cvar;
186 
187 	for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) {
188 		callback( cvar->name );
189 	}
190 }
191 
192 
193 /*
194 ============
195 Cvar_Get
196 
197 If the variable already exists, the value will not be set unless CVAR_ROM
198 The flags will be or'ed in if the variable exists.
199 ============
200 */
Cvar_Get(const char * var_name,const char * var_value,int flags)201 cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
202 	cvar_t	*var;
203 	long	hash;
204 
205   if ( !var_name || ! var_value ) {
206 		Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" );
207   }
208 
209 	if ( !Cvar_ValidateString( var_name ) ) {
210 		Com_Printf("invalid cvar name string: %s\n", var_name );
211 		var_name = "BADNAME";
212 	}
213 
214 #if 0		// FIXME: values with backslash happen
215 	if ( !Cvar_ValidateString( var_value ) ) {
216 		Com_Printf("invalid cvar value string: %s\n", var_value );
217 		var_value = "BADVALUE";
218 	}
219 #endif
220 
221 	var = Cvar_FindVar (var_name);
222 	if ( var ) {
223 		// if the C code is now specifying a variable that the user already
224 		// set a value for, take the new value as the reset value
225 		if ( ( var->flags & CVAR_USER_CREATED ) && !( flags & CVAR_USER_CREATED )
226 			&& var_value[0] ) {
227 			var->flags &= ~CVAR_USER_CREATED;
228 			Z_Free( var->resetString );
229 			var->resetString = CopyString( var_value );
230 
231 			if(flags & CVAR_ROM)
232 			{
233 				// this variable was set by the user,
234 				// so force it to value given by the engine.
235 
236 				if(var->latchedString)
237 					Z_Free(var->latchedString);
238 
239 				var->latchedString = CopyString(var_value);
240 			}
241 
242 			// ZOID--needs to be set so that cvars the game sets as
243 			// SERVERINFO get sent to clients
244 			cvar_modifiedFlags |= flags;
245 		}
246 
247 		var->flags |= flags;
248 		// only allow one non-empty reset string without a warning
249 		if ( !var->resetString[0] ) {
250 			// we don't have a reset string yet
251 			Z_Free( var->resetString );
252 			var->resetString = CopyString( var_value );
253 		} else if ( var_value[0] && strcmp( var->resetString, var_value ) ) {
254 			Com_DPrintf( "Warning: cvar \"%s\" given initial values: \"%s\" and \"%s\"\n",
255 				var_name, var->resetString, var_value );
256 		}
257 		// if we have a latched string, take that value now
258 		if ( var->latchedString ) {
259 			char *s;
260 
261 			s = var->latchedString;
262 			var->latchedString = NULL;	// otherwise cvar_set2 would free it
263 			Cvar_Set2( var_name, s, qtrue );
264 			Z_Free( s );
265 		}
266 
267 		return var;
268 	}
269 
270 	//
271 	// allocate a new cvar
272 	//
273 	if ( cvar_numIndexes >= MAX_CVARS ) {
274 		Com_Error( ERR_FATAL, "MAX_CVARS" );
275 	}
276 	var = &cvar_indexes[cvar_numIndexes];
277 	cvar_numIndexes++;
278 	var->name = CopyString (var_name);
279 	var->string = CopyString (var_value);
280 	var->modified = qtrue;
281 	var->modificationCount = 1;
282 	var->value = atof (var->string);
283 	var->integer = atoi(var->string);
284 	var->resetString = CopyString( var_value );
285 
286 	// link the variable in
287 	var->next = cvar_vars;
288 	cvar_vars = var;
289 
290 	var->flags = flags;
291 	// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
292 	cvar_modifiedFlags |= var->flags;
293 
294 	hash = generateHashValue(var_name);
295 	var->hashNext = hashTable[hash];
296 	hashTable[hash] = var;
297 
298 	return var;
299 }
300 
301 /*
302 ============
303 Cvar_Print
304 
305 Prints the value, default, and latched string of the given variable
306 ============
307 */
Cvar_Print(cvar_t * v)308 void Cvar_Print( cvar_t *v ) {
309 	Com_Printf ("\"%s\" is:\"%s" S_COLOR_WHITE "\"",
310 			v->name, v->string );
311 
312 	if ( !( v->flags & CVAR_ROM ) ) {
313 		if ( !Q_stricmp( v->string, v->resetString ) ) {
314 			Com_Printf (", the default" );
315 		} else {
316 			Com_Printf (" default:\"%s" S_COLOR_WHITE "\"",
317 					v->resetString );
318 		}
319 	}
320 
321 	Com_Printf ("\n");
322 
323 	if ( v->latchedString ) {
324 		Com_Printf( "latched: \"%s\"\n", v->latchedString );
325 	}
326 }
327 
328 /*
329 ============
330 Cvar_Set2
331 ============
332 */
Cvar_Set2(const char * var_name,const char * value,qboolean force)333 cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) {
334 	cvar_t	*var;
335 
336 //	Com_DPrintf( "Cvar_Set2: %s %s\n", var_name, value );
337 
338 	if ( !Cvar_ValidateString( var_name ) ) {
339 		Com_Printf("invalid cvar name string: %s\n", var_name );
340 		var_name = "BADNAME";
341 	}
342 
343 #if 0	// FIXME
344 	if ( value && !Cvar_ValidateString( value ) ) {
345 		Com_Printf("invalid cvar value string: %s\n", value );
346 		var_value = "BADVALUE";
347 	}
348 #endif
349 
350 	var = Cvar_FindVar (var_name);
351 	if (!var) {
352 		if ( !value ) {
353 			return NULL;
354 		}
355 		// create it
356 		if ( !force ) {
357 			return Cvar_Get( var_name, value, CVAR_USER_CREATED );
358 		} else {
359 			return Cvar_Get (var_name, value, 0);
360 		}
361 	}
362 
363 	if (!value ) {
364 		value = var->resetString;
365 	}
366 
367 	if((var->flags & CVAR_LATCH) && var->latchedString) {
368 		if(!strcmp(value,var->latchedString))
369 			return var;
370 	}
371 	else if (!strcmp(value,var->string)) {
372 		return var;
373 	}
374 	// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
375 	cvar_modifiedFlags |= var->flags;
376 
377 	if (!force)
378 	{
379 		if (var->flags & CVAR_ROM)
380 		{
381 			Com_Printf ("%s is read only.\n", var_name);
382 			return var;
383 		}
384 
385 		if (var->flags & CVAR_INIT)
386 		{
387 			Com_Printf ("%s is write protected.\n", var_name);
388 			return var;
389 		}
390 
391 		if (var->flags & CVAR_LATCH)
392 		{
393 			if (var->latchedString)
394 			{
395 				if (strcmp(value, var->latchedString) == 0)
396 					return var;
397 				Z_Free (var->latchedString);
398 			}
399 			else
400 			{
401 				if (strcmp(value, var->string) == 0)
402 					return var;
403 			}
404 
405 			Com_Printf ("%s will be changed upon restarting.\n", var_name);
406 			var->latchedString = CopyString(value);
407 			var->modified = qtrue;
408 			var->modificationCount++;
409 			return var;
410 		}
411 
412 		if ( (var->flags & CVAR_CHEAT) && !cvar_cheats->integer )
413 		{
414 			Com_Printf ("%s is cheat protected.\n", var_name);
415 			return var;
416 		}
417 
418 	}
419 	else
420 	{
421 		if (var->latchedString)
422 		{
423 			Z_Free (var->latchedString);
424 			var->latchedString = NULL;
425 		}
426 	}
427 
428 	if (!strcmp(value, var->string))
429 		return var;		// not changed
430 
431 	var->modified = qtrue;
432 	var->modificationCount++;
433 
434 	Z_Free (var->string);	// free the old value string
435 
436 	var->string = CopyString(value);
437 	var->value = atof (var->string);
438 	var->integer = atoi (var->string);
439 
440 	return var;
441 }
442 
443 /*
444 ============
445 Cvar_Set
446 ============
447 */
Cvar_Set(const char * var_name,const char * value)448 void Cvar_Set( const char *var_name, const char *value) {
449 	Cvar_Set2 (var_name, value, qtrue);
450 }
451 
452 /*
453 ============
454 Cvar_SetLatched
455 ============
456 */
Cvar_SetLatched(const char * var_name,const char * value)457 void Cvar_SetLatched( const char *var_name, const char *value) {
458 	Cvar_Set2 (var_name, value, qfalse);
459 }
460 
461 /*
462 ============
463 Cvar_SetValue
464 ============
465 */
Cvar_SetValue(const char * var_name,float value)466 void Cvar_SetValue( const char *var_name, float value) {
467 	char	val[32];
468 
469 	if ( value == (int)value ) {
470 		Com_sprintf (val, sizeof(val), "%i",(int)value);
471 	} else {
472 		Com_sprintf (val, sizeof(val), "%f",value);
473 	}
474 	Cvar_Set (var_name, val);
475 }
476 
477 
478 /*
479 ============
480 Cvar_Reset
481 ============
482 */
Cvar_Reset(const char * var_name)483 void Cvar_Reset( const char *var_name ) {
484 	Cvar_Set2( var_name, NULL, qfalse );
485 }
486 
487 /*
488 ============
489 Cvar_ForceReset
490 ============
491 */
Cvar_ForceReset(const char * var_name)492 void Cvar_ForceReset(const char *var_name)
493 {
494 	Cvar_Set2(var_name, NULL, qtrue);
495 }
496 
497 /*
498 ============
499 Cvar_SetCheatState
500 
501 Any testing variables will be reset to the safe values
502 ============
503 */
Cvar_SetCheatState(void)504 void Cvar_SetCheatState( void ) {
505 	cvar_t	*var;
506 
507 	// set all default vars to the safe value
508 	for ( var = cvar_vars ; var ; var = var->next ) {
509 		if ( var->flags & CVAR_CHEAT ) {
510       // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here
511       // because of a different var->latchedString
512       if (var->latchedString)
513       {
514         Z_Free(var->latchedString);
515         var->latchedString = NULL;
516       }
517 			if (strcmp(var->resetString,var->string)) {
518         Cvar_Set( var->name, var->resetString );
519 			}
520 		}
521 	}
522 }
523 
524 /*
525 ============
526 Cvar_Command
527 
528 Handles variable inspection and changing from the console
529 ============
530 */
Cvar_Command(void)531 qboolean Cvar_Command( void ) {
532 	cvar_t	*v;
533 
534 	// check variables
535 	v = Cvar_FindVar (Cmd_Argv(0));
536 	if (!v) {
537 		return qfalse;
538 	}
539 
540 	// perform a variable print or set
541 	if ( Cmd_Argc() == 1 ) {
542 		Cvar_Print( v );
543 		return qtrue;
544 	}
545 
546 	// set the value if forcing isn't required
547 	Cvar_Set2 (v->name, Cmd_Argv(1), qfalse);
548 	return qtrue;
549 }
550 
551 
552 /*
553 ============
554 Cvar_Print_f
555 
556 Prints the contents of a cvar
557 (preferred over Cvar_Command where cvar names and commands conflict)
558 ============
559 */
Cvar_Print_f(void)560 void Cvar_Print_f(void)
561 {
562 	char *name;
563 	cvar_t *cv;
564 
565 	if(Cmd_Argc() != 2)
566 	{
567 		Com_Printf ("usage: print <variable>\n");
568 		return;
569 	}
570 
571 	name = Cmd_Argv(1);
572 
573 	cv = Cvar_FindVar(name);
574 
575 	if(cv)
576 		Cvar_Print(cv);
577 	else
578 		Com_Printf ("Cvar %s does not exist.\n", name);
579 }
580 
581 /*
582 ============
583 Cvar_Toggle_f
584 
585 Toggles a cvar for easy single key binding
586 ============
587 */
Cvar_Toggle_f(void)588 void Cvar_Toggle_f( void ) {
589 	int		v;
590 
591 	if ( Cmd_Argc() != 2 ) {
592 		Com_Printf ("usage: toggle <variable>\n");
593 		return;
594 	}
595 
596 	v = Cvar_VariableValue( Cmd_Argv( 1 ) );
597 	v = !v;
598 
599 	Cvar_Set2 (Cmd_Argv(1), va("%i", v), qfalse);
600 }
601 
602 /*
603 ============
604 Cvar_Set_f
605 
606 Allows setting and defining of arbitrary cvars from console, even if they
607 weren't declared in C code.
608 ============
609 */
Cvar_Set_f(void)610 void Cvar_Set_f( void ) {
611 	int		i, c, l, len;
612 	char	cmd[5], combined[MAX_STRING_TOKENS];
613 	cvar_t *v;
614 
615 	c = Cmd_Argc();
616 	Q_strncpyz( cmd, Cmd_Argv(0), sizeof( cmd ) );
617 
618 	if ( c < 2 ) {
619 		Com_Printf ("usage: %s <variable> <value>\n", cmd);
620 		return;
621 	}
622 	if ( c == 2 ) {
623 		Cvar_Print_f();
624 		return;
625 	}
626 
627 	combined[0] = 0;
628 	l = 0;
629 	for ( i = 2 ; i < c ; i++ ) {
630 		len = strlen ( Cmd_Argv( i ) + 1 );
631 		if ( l + len >= MAX_STRING_TOKENS - 2 ) {
632 			break;
633 		}
634 		strcat( combined, Cmd_Argv( i ) );
635 		if ( i != c-1 ) {
636 			strcat( combined, " " );
637 		}
638 		l += len;
639 	}
640 	v = Cvar_Set2 (Cmd_Argv(1), combined, qfalse);
641 	if( !v ) {
642 		return;
643 	}
644 	switch( cmd[3] ) {
645 		default:
646 		case '\0':
647 			break;
648 		case 'u':
649 			v->flags |= CVAR_USERINFO;
650 			break;
651 		case 's':
652 			v->flags |= CVAR_SERVERINFO;
653 			break;
654 		case 'a':
655 			v->flags |= CVAR_ARCHIVE;
656 			break;
657 	}
658 }
659 
660 /*
661 ============
662 Cvar_Reset_f
663 ============
664 */
Cvar_Reset_f(void)665 void Cvar_Reset_f( void ) {
666 	if ( Cmd_Argc() != 2 ) {
667 		Com_Printf ("usage: reset <variable>\n");
668 		return;
669 	}
670 	Cvar_Reset( Cmd_Argv( 1 ) );
671 }
672 
673 /*
674 ============
675 Cvar_WriteVariables
676 
677 Appends lines containing "set variable value" for all variables
678 with the archive flag set to qtrue.
679 ============
680 */
Cvar_WriteVariables(fileHandle_t f)681 void Cvar_WriteVariables( fileHandle_t f ) {
682 	cvar_t	*var;
683 	char	buffer[1024];
684 
685 	for (var = cvar_vars ; var ; var = var->next) {
686 		if( Q_stricmp( var->name, "cl_cdkey" ) == 0 ) {
687 			continue;
688 		}
689 		if( var->flags & CVAR_ARCHIVE ) {
690 			// write the latched value, even if it hasn't taken effect yet
691 			if ( var->latchedString ) {
692 				if( strlen( var->name ) + strlen( var->latchedString ) + 10 > sizeof( buffer ) ) {
693 					Com_Printf( S_COLOR_YELLOW "WARNING: value of variable "
694 							"\"%s\" too long to write to file\n", var->name );
695 					continue;
696 				}
697 				Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->latchedString);
698 			} else {
699 				if( strlen( var->name ) + strlen( var->string ) + 10 > sizeof( buffer ) ) {
700 					Com_Printf( S_COLOR_YELLOW "WARNING: value of variable "
701 							"\"%s\" too long to write to file\n", var->name );
702 					continue;
703 				}
704 				Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->string);
705 			}
706 			FS_Write( buffer, strlen( buffer ), f );
707 		}
708 	}
709 }
710 
711 /*
712 ============
713 Cvar_List_f
714 ============
715 */
Cvar_List_f(void)716 void Cvar_List_f( void ) {
717 	cvar_t	*var;
718 	int		i;
719 	char	*match;
720 
721 	if ( Cmd_Argc() > 1 ) {
722 		match = Cmd_Argv( 1 );
723 	} else {
724 		match = NULL;
725 	}
726 
727 	i = 0;
728 	for (var = cvar_vars ; var ; var = var->next, i++)
729 	{
730 		if (match && !Com_Filter(match, var->name, qfalse)) continue;
731 
732 		if (var->flags & CVAR_SERVERINFO) {
733 			Com_Printf("S");
734 		} else {
735 			Com_Printf(" ");
736 		}
737 		if (var->flags & CVAR_USERINFO) {
738 			Com_Printf("U");
739 		} else {
740 			Com_Printf(" ");
741 		}
742 		if (var->flags & CVAR_ROM) {
743 			Com_Printf("R");
744 		} else {
745 			Com_Printf(" ");
746 		}
747 		if (var->flags & CVAR_INIT) {
748 			Com_Printf("I");
749 		} else {
750 			Com_Printf(" ");
751 		}
752 		if (var->flags & CVAR_ARCHIVE) {
753 			Com_Printf("A");
754 		} else {
755 			Com_Printf(" ");
756 		}
757 		if (var->flags & CVAR_LATCH) {
758 			Com_Printf("L");
759 		} else {
760 			Com_Printf(" ");
761 		}
762 		if (var->flags & CVAR_CHEAT) {
763 			Com_Printf("C");
764 		} else {
765 			Com_Printf(" ");
766 		}
767 
768 		Com_Printf (" %s \"%s\"\n", var->name, var->string);
769 	}
770 
771 	Com_Printf ("\n%i total cvars\n", i);
772 	Com_Printf ("%i cvar indexes\n", cvar_numIndexes);
773 }
774 
775 /*
776 ============
777 Cvar_Restart_f
778 
779 Resets all cvars to their hardcoded values
780 ============
781 */
Cvar_Restart_f(void)782 void Cvar_Restart_f( void ) {
783 	cvar_t	*var;
784 	cvar_t	**prev;
785 
786 	prev = &cvar_vars;
787 	while ( 1 ) {
788 		var = *prev;
789 		if ( !var ) {
790 			break;
791 		}
792 
793 		// don't mess with rom values, or some inter-module
794 		// communication will get broken (com_cl_running, etc)
795 		if ( var->flags & ( CVAR_ROM | CVAR_INIT | CVAR_NORESTART ) ) {
796 			prev = &var->next;
797 			continue;
798 		}
799 
800 		// throw out any variables the user created
801 		if ( var->flags & CVAR_USER_CREATED ) {
802 			*prev = var->next;
803 			if ( var->name ) {
804 				Z_Free( var->name );
805 			}
806 			if ( var->string ) {
807 				Z_Free( var->string );
808 			}
809 			if ( var->latchedString ) {
810 				Z_Free( var->latchedString );
811 			}
812 			if ( var->resetString ) {
813 				Z_Free( var->resetString );
814 			}
815 			// clear the var completely, since we
816 			// can't remove the index from the list
817 			Com_Memset( var, 0, sizeof( var ) );
818 			continue;
819 		}
820 
821 		Cvar_Set( var->name, var->resetString );
822 
823 		prev = &var->next;
824 	}
825 }
826 
827 
828 
829 /*
830 =====================
831 Cvar_InfoString
832 =====================
833 */
Cvar_InfoString(int bit)834 char	*Cvar_InfoString( int bit ) {
835 	static char	info[MAX_INFO_STRING];
836 	cvar_t	*var;
837 
838 	info[0] = 0;
839 
840 	for (var = cvar_vars ; var ; var = var->next) {
841 		if (var->flags & bit) {
842 			Info_SetValueForKey (info, var->name, var->string);
843 		}
844 	}
845 	return info;
846 }
847 
848 /*
849 =====================
850 Cvar_InfoString_Big
851 
852   handles large info strings ( CS_SYSTEMINFO )
853 =====================
854 */
Cvar_InfoString_Big(int bit)855 char	*Cvar_InfoString_Big( int bit ) {
856 	static char	info[BIG_INFO_STRING];
857 	cvar_t	*var;
858 
859 	info[0] = 0;
860 
861 	for (var = cvar_vars ; var ; var = var->next) {
862 		if (var->flags & bit) {
863 			Info_SetValueForKey_Big (info, var->name, var->string);
864 		}
865 	}
866 	return info;
867 }
868 
869 
870 
871 /*
872 =====================
873 Cvar_InfoStringBuffer
874 =====================
875 */
Cvar_InfoStringBuffer(int bit,char * buff,int buffsize)876 void Cvar_InfoStringBuffer( int bit, char* buff, int buffsize ) {
877 	Q_strncpyz(buff,Cvar_InfoString(bit),buffsize);
878 }
879 
880 /*
881 =====================
882 Cvar_Register
883 
884 basically a slightly modified Cvar_Get for the interpreted modules
885 =====================
886 */
Cvar_Register(vmCvar_t * vmCvar,const char * varName,const char * defaultValue,int flags)887 void	Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
888 	cvar_t	*cv;
889 
890 	cv = Cvar_Get( varName, defaultValue, flags );
891 	if ( !vmCvar ) {
892 		return;
893 	}
894 	vmCvar->handle = cv - cvar_indexes;
895 	vmCvar->modificationCount = -1;
896 	Cvar_Update( vmCvar );
897 }
898 
899 
900 /*
901 =====================
902 Cvar_Register
903 
904 updates an interpreted modules' version of a cvar
905 =====================
906 */
Cvar_Update(vmCvar_t * vmCvar)907 void	Cvar_Update( vmCvar_t *vmCvar ) {
908 	cvar_t	*cv = NULL;
909 	assert(vmCvar);
910 
911 	if ( (unsigned)vmCvar->handle >= cvar_numIndexes ) {
912 		Com_Error( ERR_DROP, "Cvar_Update: handle out of range" );
913 	}
914 
915 	cv = cvar_indexes + vmCvar->handle;
916 
917 	if ( cv->modificationCount == vmCvar->modificationCount ) {
918 		return;
919 	}
920 	if ( !cv->string ) {
921 		return;		// variable might have been cleared by a cvar_restart
922 	}
923 	vmCvar->modificationCount = cv->modificationCount;
924 	if ( strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING )
925 	  Com_Error( ERR_DROP, "Cvar_Update: src %s length %zd exceeds MAX_CVAR_VALUE_STRING",
926 		     cv->string,
927 		     strlen(cv->string));
928 	Q_strncpyz( vmCvar->string, cv->string,  MAX_CVAR_VALUE_STRING );
929 
930 	vmCvar->value = cv->value;
931 	vmCvar->integer = cv->integer;
932 }
933 
934 
935 /*
936 ============
937 Cvar_Init
938 
939 Reads in all archived cvars
940 ============
941 */
Cvar_Init(void)942 void Cvar_Init (void) {
943 	cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO );
944 
945 	Cmd_AddCommand ("print", Cvar_Print_f);
946 	Cmd_AddCommand ("toggle", Cvar_Toggle_f);
947 	Cmd_AddCommand ("set", Cvar_Set_f);
948 	Cmd_AddCommand ("sets", Cvar_Set_f);
949 	Cmd_AddCommand ("setu", Cvar_Set_f);
950 	Cmd_AddCommand ("seta", Cvar_Set_f);
951 	Cmd_AddCommand ("reset", Cvar_Reset_f);
952 	Cmd_AddCommand ("cvarlist", Cvar_List_f);
953 	Cmd_AddCommand ("cvar_restart", Cvar_Restart_f);
954 }
955