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