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