1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // cvar.c -- dynamic variable tracking
21
22 #include "qcommon.h"
23
24 cvarAPI_t cvar;
25
26 cvar_t *cvar_vars;
27
28 uint32 cvar_latchedModified;
29 uint32 cvar_infoModified;
30
31 #define Cvar_Malloc( size ) Z_TagMalloc( size, TAG_CVAR )
32
33 #define CVARHASH_SIZE 256
34
35 static cvar_t *cvarHash[CVARHASH_SIZE];
36 static cvarSubsystem_t currentSubsystem;
37
38 static cvar_t *cvar_silent;
39
40 /*
41 ============
42 Cvar_FindVar
43 ============
44 */
Cvar_FindVar(const char * var_name)45 cvar_t *Cvar_FindVar( const char *var_name ) {
46 cvar_t *var;
47 int hash;
48
49 hash = Com_HashString( var_name, CVARHASH_SIZE );
50
51 for( var = cvarHash[hash]; var; var = var->hashNext ) {
52 if( !strcmp( var_name, var->name ) ) {
53 return var;
54 }
55 }
56
57 return NULL;
58 }
59
60 /*
61 ============
62 Cvar_Exists
63 ============
64 */
Cvar_Exists(const char * name)65 qboolean Cvar_Exists( const char *name ) {
66 if( Cvar_FindVar( name ) ) {
67 return qtrue;
68 }
69 return qfalse;
70 }
71
72 /*
73 ============
74 Cvar_VariableValue
75 ============
76 */
Cvar_VariableValue(const char * var_name)77 float Cvar_VariableValue( const char *var_name ) {
78 cvar_t *var;
79
80 var = Cvar_FindVar( var_name );
81 if( !var )
82 return 0;
83
84 return var->value;
85 }
86
87 /*
88 ============
89 Cvar_VariableInteger
90 ============
91 */
Cvar_VariableInteger(const char * var_name)92 int Cvar_VariableInteger( const char *var_name ) {
93 cvar_t *var;
94
95 var = Cvar_FindVar( var_name );
96 if( !var )
97 return 0;
98
99 return var->integer;
100 }
101
102
103 /*
104 ============
105 Cvar_VariableString
106 ============
107 */
Cvar_VariableString(const char * var_name)108 char *Cvar_VariableString( const char *var_name ) {
109 cvar_t *var;
110
111 var = Cvar_FindVar( var_name );
112 if( !var )
113 return "";
114
115 return var->string;
116 }
117
118 /*
119 ============
120 Cvar_VariableStringBuffer
121 ============
122 */
Cvar_VariableStringBuffer(const char * var_name,char * buffer,int bufferSize)123 void Cvar_VariableStringBuffer( const char *var_name, char *buffer,
124 int bufferSize )
125 {
126 Q_strncpyz( buffer, Cvar_VariableString( var_name ), bufferSize );
127 }
128
129
130
Cvar_Generator(const char * text,int state)131 const char *Cvar_Generator( const char *text, int state ) {
132 static int length;
133 static cvar_t *cvar;
134 const char *name;
135
136 if( !state ) {
137 length = strlen( text );
138 cvar = cvar_vars;
139 }
140
141 while( cvar ) {
142 name = cvar->name;
143 cvar = cvar->next;
144 if( !strncmp( text, name, length ) ) {
145 return name;
146 }
147 }
148
149 return NULL;
150 }
151
Cvar_ParseString(cvar_t * var)152 static void Cvar_ParseString( cvar_t *var ) {
153 char *s = var->string;
154
155 if( s[0] == '0' && s[1] == 'x' ) {
156 var->integer = COM_ParseHex( s + 2 );
157 var->value = ( float )var->integer;
158 } else {
159 var->integer = atoi( var->string );
160 var->value = atof( var->string );
161 }
162 }
163
164 /*
165 ============
166 Cvar_Get
167
168 If the variable already exists, the value will not be set
169 The flags will be or'ed in if the variable exists.
170 ============
171 */
Cvar_Get(const char * var_name,const char * var_value,int flags)172 cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
173 cvar_t *var;
174 uint32 hash;
175 int length;
176
177 if( !var_name ) {
178 Com_Error( ERR_FATAL, "Cvar_Get: NULL variable name" );
179 }
180 if( !var_value ) {
181 var_value = "";
182 }
183
184 if( flags & CVAR_INFOMASK ) {
185 length = strlen( var_name );
186 if( length >= MAX_INFO_KEY ) {
187 Com_WPrintf( "Oversize info cvar name: %d chars.\n", length );
188 goto badvar;
189 }
190 if( !Info_ValidateSubstring( var_name ) ) {
191 Com_WPrintf( "Invalid info cvar name.\n" );
192 goto badvar;
193 }
194 length = strlen( var_value );
195 if( length >= MAX_INFO_VALUE ) {
196 Com_WPrintf( "Oversize info cvar value: %d chars.\n", length );
197 goto badvar;
198 }
199 if( !Info_ValidateSubstring( var_value ) ) {
200 Com_WPrintf( "Invalid info cvar value.\n" );
201 goto badvar;
202 }
203 }
204
205 var = Cvar_FindVar( var_name );
206 if( var ) {
207 if( ( var->flags & CVAR_LATCHED ) && var->latched_string ) {
208 if( strcmp( var->latched_string, var->string ) ) {
209 // update latched cvar
210 Z_Free( var->string );
211 var->string = Cvar_CopyString( var->latched_string );
212 Cvar_ParseString( var );
213
214 if( var->flags & CVAR_USERINFO ) {
215 CL_UpdateUserinfo( var, CVAR_SET_DIRECT );
216 }
217
218 var->modified = qtrue;
219 }
220
221 Z_Free( var->latched_string );
222 var->latched_string = NULL;
223 }
224
225 if( !( flags & CVAR_USER_CREATED ) ) {
226 if( var->flags & CVAR_USER_CREATED ) {
227 /* update default string if cvar was set from command line */
228 Z_Free( var->defaultString );
229 var->defaultString = Cvar_CopyString( var_value );
230 var->flags &= ~CVAR_USER_CREATED;
231 var->subsystem = currentSubsystem;
232 } else if( !( var->flags & CVAR_DEFAULTS_MIXED ) ) {
233 if( strcmp( var->defaultString, var_value ) ) {
234 Com_DPrintf( "Cvar \"%s\" given initial values: "
235 "\"%s\" and \"%s\"\n",
236 var->name, var->defaultString, var_value );
237 var->flags |= CVAR_DEFAULTS_MIXED;
238 }
239 }
240 if( ( var->flags & CVAR_LATCHED ) && !( flags & CVAR_LATCHED ) ) {
241 if( var->latched_string ) {
242 Z_Free( var->latched_string );
243 var->latched_string = NULL;
244 }
245 var->flags &= ~CVAR_LATCHED;
246 }
247 } else {
248 flags &= ~CVAR_USER_CREATED;
249 }
250
251 var->flags |= flags;
252 return var;
253 }
254
255 /* once allocated, cvar name is never changed */
256 length = strlen( var_name ) + 1;
257 var = Cvar_Malloc( sizeof( *var ) + length );
258 var->name = ( char * )( var + 1 );
259 strcpy( var->name, var_name );
260 var->string = Cvar_CopyString( var_value );
261 var->latched_string = NULL;
262 var->defaultString = Cvar_CopyString( var_value );
263 Cvar_ParseString( var );
264 var->flags = flags;
265 var->subsystem = currentSubsystem;
266 var->changedFunc = NULL;
267 var->changedArg = NULL;
268 var->description = NULL;
269
270 hash = Com_HashString( var_name, CVARHASH_SIZE );
271
272 // link the variable in
273 var->next = cvar_vars;
274 cvar_vars = var;
275 var->hashNext = cvarHash[hash];
276 cvarHash[hash] = var;
277
278 var->modified = qtrue;
279
280 return var;
281
282 badvar:
283 if( !( flags & CVAR_USER_CREATED ) ) {
284 Com_Error( ERR_FATAL, "Cvar_Get: invalid info variable" );
285 }
286 return NULL;
287 }
288
Cvar_Subsystem(cvarSubsystem_t subsystem)289 void Cvar_Subsystem( cvarSubsystem_t subsystem ) {
290 currentSubsystem = subsystem;
291 }
292
293 /*
294 ============
295 Cvar_SetByVar
296 ============
297 */
Cvar_SetByVar(cvar_t * var,const char * value,cvarSetSource_t source)298 void Cvar_SetByVar( cvar_t *var, const char *value, cvarSetSource_t source ) {
299 int length;
300
301 if( !strcmp( value, var->string ) &&
302 !( var->flags & (CVAR_LATCHED|CVAR_LATCH) ) )
303 {
304 return; // not changed
305 }
306
307 Com_DPrintf( "Cvar_Set( \"%s\", \"%s\" )\n", var->name, value );
308
309 if( var->flags & CVAR_INFOMASK ) {
310 length = strlen( value );
311 if( length >= MAX_INFO_VALUE ) {
312 Com_WPrintf(
313 "Oversize info cvar value specified (%d chars), ignored.\n",
314 length );
315 return;
316 }
317 if( !Info_ValidateSubstring( value ) ) {
318 Com_WPrintf( "Invalid info cvar value specified, ignored.\n" );
319 return;
320 }
321 }
322
323 /* some cvars may not be changed by user at all */
324 if( source != CVAR_SET_DIRECT ) {
325 if( var->flags & CVAR_ROM ) {
326 Com_Printf( "%s is read-only.\n", var->name );
327 return;
328 }
329
330 if( var->flags & CVAR_CHEAT ) {
331 if( !CL_CheatsOK() ) {
332 Com_Printf( "%s is cheat protected.\n", var->name );
333 return;
334 }
335 }
336 }
337
338 /* some cvars may require special processing if set by user from console */
339 if( source == CVAR_SET_CONSOLE ) {
340 if( var->flags & CVAR_NOSET ) {
341 Com_Printf( "%s may be set from command line only.\n", var->name );
342 return;
343 }
344
345 if( var->flags & (CVAR_LATCHED|CVAR_LATCH) ) {
346 if( !strcmp( var->string, value ) ) {
347 /* set back to current value? */
348 if( var->latched_string ) {
349 Z_Free( var->latched_string );
350 var->latched_string = NULL;
351 }
352 return;
353 }
354 if( var->latched_string ) {
355 if( !strcmp( var->latched_string, value ) ) {
356 /* latched string not changed? */
357 return;
358 }
359 Z_Free( var->latched_string );
360 var->latched_string = NULL;
361 }
362
363
364 if( var->flags & CVAR_LATCH ) {
365 if( sv_running->integer ) {
366 if( !cvar_silent->integer ) {
367 Com_Printf( "%s will be changed for next game.\n",
368 var->name );
369 }
370 var->latched_string = Cvar_CopyString( value );
371 return;
372 }
373 /* server is down, it's ok to update this cvar now */
374 } else {
375 char *subsystem;
376
377 var->latched_string = Cvar_CopyString( value );
378 cvar_latchedModified |= 1 << var->subsystem;
379 if( cvar_silent->integer ) {
380 return;
381 }
382
383 switch( var->subsystem ) {
384 case CVAR_SYSTEM_GENERIC:
385 subsystem = "desired subsystem";
386 break;
387 case CVAR_SYSTEM_VIDEO:
388 subsystem = "video subsystem";
389 break;
390 case CVAR_SYSTEM_SOUND:
391 subsystem = "sound subsystem";
392 break;
393 case CVAR_SYSTEM_INPUT:
394 subsystem = "input subsystem";
395 break;
396 case CVAR_SYSTEM_NET:
397 subsystem = "network subsystem";
398 break;
399 case CVAR_SYSTEM_FILES:
400 subsystem = "filesystem";
401 break;
402 default:
403 Com_Error( ERR_FATAL, "Cvar_SetByVar: invalid subsystem %u",
404 var->subsystem );
405 subsystem = NULL;
406 break;
407 }
408 Com_Printf( "%s will be changed upon restarting the %s.\n",
409 var->name, subsystem );
410 return;
411 }
412 }
413
414 }
415
416 /* free latched string, if any */
417 if( var->latched_string ) {
418 Z_Free( var->latched_string );
419 var->latched_string = NULL;
420 }
421
422 Z_Free( var->string ); // free the old value string
423
424 var->string = Cvar_CopyString( value );
425 Cvar_ParseString( var );
426
427 if( var->flags & CVAR_INFOMASK ) {
428 cvar_infoModified |= var->flags & CVAR_INFOMASK;
429 if( var->flags & CVAR_USERINFO ) {
430 CL_UpdateUserinfo( var, source );
431 }
432 }
433
434 var->modified = qtrue;
435 if( source != CVAR_SET_DIRECT && var->changedFunc ) {
436 var->changedFunc( var, var->changedArg );
437 }
438 }
439
440 /*
441 ============
442 Cvar_SetEx
443 ============
444 */
Cvar_SetEx(const char * var_name,const char * value,cvarSetSource_t source)445 cvar_t *Cvar_SetEx( const char *var_name, const char *value,
446 cvarSetSource_t source )
447 {
448 cvar_t *var;
449
450 var = Cvar_FindVar( var_name );
451 if( !var ) {
452 // create it
453 return Cvar_Get( var_name, value, CVAR_USER_CREATED );
454 }
455
456 Cvar_SetByVar( var, value, source );
457
458 return var;
459 }
460
461 /*
462 ============
463 Cvar_FullSet
464 ============
465 */
Cvar_FullSet(const char * var_name,const char * value,int flags,cvarSetSource_t source)466 cvar_t *Cvar_FullSet( const char *var_name, const char *value, int flags, cvarSetSource_t source ) {
467 cvar_t *var;
468
469 var = Cvar_FindVar( var_name );
470 if( !var ) {
471 // create it
472 return Cvar_Get( var_name, value, flags | CVAR_USER_CREATED );
473 }
474
475 Cvar_SetByVar( var, value, source );
476
477 // force retransmit of userinfo variables
478 // needed for compatibility with q2admin
479 if( ( var->flags | flags ) & CVAR_USERINFO ) {
480 cvar_infoModified |= CVAR_USERINFO;
481 CL_UpdateUserinfo( var, source );
482 }
483
484 var->flags &= ~CVAR_INFOMASK;
485 var->flags |= flags;
486
487 return var;
488 }
489
490 /*
491 ============
492 Cvar_Set
493 ============
494 */
Cvar_Set(const char * var_name,const char * value)495 cvar_t *Cvar_Set( const char *var_name, const char *value ) {
496 return Cvar_SetEx( var_name, value, CVAR_SET_DIRECT );
497 }
498
499 /*
500 ============
501 Cvar_UserSet
502 ============
503 */
Cvar_UserSet(const char * var_name,const char * value)504 cvar_t *Cvar_UserSet( const char *var_name, const char *value ) {
505 return Cvar_SetEx( var_name, value, CVAR_SET_CONSOLE );
506 }
507
508
509 /*
510 ============
511 Cvar_SetValue
512 ============
513 */
Cvar_SetValue(const char * var_name,float value)514 void Cvar_SetValue( const char *var_name, float value ) {
515 char val[32];
516
517 if( value == (int)value )
518 Com_sprintf( val, sizeof( val ), "%i", (int)value );
519 else
520 Com_sprintf( val, sizeof( val ), "%f", value);
521
522 Cvar_SetEx( var_name, val, CVAR_SET_DIRECT );
523 }
524
525 /*
526 ============
527 Cvar_SetInteger
528 ============
529 */
Cvar_SetInteger(const char * var_name,int value)530 void Cvar_SetInteger( const char *var_name, int value ) {
531 char val[32];
532
533 Com_sprintf( val, sizeof( val ), "%i", value );
534
535 Cvar_SetEx( var_name, val, CVAR_SET_DIRECT );
536 }
537
538 /*
539 ============
540 Cvar_SetInteger
541 ============
542 */
Cvar_SetIntegerHex(const char * var_name,uint32 value)543 void Cvar_SetIntegerHex( const char *var_name, uint32 value ) {
544 char val[32];
545
546 Com_sprintf( val, sizeof( val ), "0x%X", value );
547
548 Cvar_SetEx( var_name, val, CVAR_SET_DIRECT );
549 }
550
551 /*
552 ============
553 Cvar_ClampInteger
554 ============
555 */
Cvar_ClampInteger(cvar_t * var,int min,int max)556 void Cvar_ClampInteger( cvar_t *var, int min, int max ) {
557 char val[32];
558
559 if( var->integer < min ) {
560 Com_sprintf( val, sizeof( val ), "%i", min );
561 Cvar_SetByVar( var, val, CVAR_SET_DIRECT );
562 } else if( var->integer > max ) {
563 Com_sprintf( val, sizeof( val ), "%i", max );
564 Cvar_SetByVar( var, val, CVAR_SET_DIRECT );
565 }
566 }
567
568 /*
569 ============
570 Cvar_ClampValue
571 ============
572 */
Cvar_ClampValue(cvar_t * var,float min,float max)573 void Cvar_ClampValue( cvar_t *var, float min, float max ) {
574 char val[32];
575
576 if( var->value < min ) {
577 if( min == (int)min ) {
578 Com_sprintf( val, sizeof( val ), "%i", (int)min );
579 } else {
580 Com_sprintf( val, sizeof( val ), "%f", min );
581 }
582 Cvar_SetByVar( var, val, CVAR_SET_DIRECT );
583 } else if( var->value > max ) {
584 if( max == (int)max ) {
585 Com_sprintf( val, sizeof( val ), "%i", (int)max );
586 } else {
587 Com_sprintf( val, sizeof( val ), "%f", max );
588 }
589 Cvar_SetByVar( var, val, CVAR_SET_DIRECT );
590 }
591 }
592
593 /*
594 ==================
595 Cvar_FixCheats
596 ==================
597 */
Cvar_FixCheats(void)598 void Cvar_FixCheats( void ) {
599 cvar_t *var;
600
601 if ( CL_CheatsOK() ) {
602 return;
603 }
604
605 // fix any cheating cvars
606 for( var = cvar_vars ; var ; var = var->next ) {
607 if( var->flags & CVAR_CHEAT ) {
608 Cvar_SetByVar( var, var->defaultString, CVAR_SET_DIRECT );
609 }
610 }
611 }
612
613 /*
614 ============
615 Cvar_GetLatchedVars
616
617 Any variables with latched values will now be updated
618 Only used for game latched cvars now
619 ============
620 */
Cvar_GetLatchedVars(void)621 void Cvar_GetLatchedVars( void ) {
622 cvar_t *var;
623
624 for( var = cvar_vars; var; var = var->next ) {
625 if( !(var->flags & CVAR_LATCH) )
626 continue;
627 if( var->flags & CVAR_LATCHED )
628 continue; // don't update engine cvars
629 if( !var->latched_string )
630 continue;
631 Z_Free( var->string );
632 var->string = var->latched_string;
633 var->latched_string = NULL;
634 Cvar_ParseString( var );
635
636 var->modified = qtrue;
637 }
638 }
639
640 /*
641 ============
642 Cvar_Command
643
644 Handles variable inspection and changing from the console
645 ============
646 */
Cvar_Command(void)647 qboolean Cvar_Command( void ) {
648 cvar_t *v;
649
650 // check variables
651 v = Cvar_FindVar( Cmd_Argv( 0 ) );
652 if( !v )
653 return qfalse;
654
655 // perform a variable print or set
656 if( Cmd_Argc() == 1 ) {
657 if( v->flags & CVAR_ROM ) {
658 Com_Printf( "\"%s\" is \"%s\"\n", v->name, v->string );
659 } else {
660 Com_Printf( "\"%s\" is \"%s\" ", v->name, v->string );
661 if( strcmp( v->string, v->defaultString ) ) {
662 Com_Printf( "default: \"%s\" ", v->defaultString );
663 }
664 if( v->latched_string && strcmp( v->latched_string, v->string ) ) {
665 Com_Printf( "latched: \"%s\"", v->latched_string );
666 }
667 Com_Printf( "\n" );
668 }
669 return qtrue;
670 }
671
672 Cvar_SetByVar( v, Cmd_Argv( 1 ), CVAR_SET_CONSOLE );
673
674 return qtrue;
675 }
676
677
678 /*
679 ============
680 Cvar_Set_f
681
682 Allows setting and defining of arbitrary cvars from console
683 ============
684 */
Cvar_Set_f(void)685 void Cvar_Set_f( void ) {
686 int c, flags;
687 char *f;
688 cvar_t *var;
689
690 c = Cmd_Argc();
691 if( c != 3 && c != 4 ) {
692 Com_Printf( "Usage: set <variable> <value> [u / s]\n" );
693 return;
694 }
695
696 if( c != 4 ) {
697 Cvar_SetEx( Cmd_Argv( 1 ), Cmd_Argv( 2 ), CVAR_SET_CONSOLE );
698 return;
699 }
700
701 f = Cmd_Argv( 3 );
702 if( !strcmp( f, "u" ) ) {
703 flags = CVAR_USERINFO;
704 } else if( !strcmp( f, "s" ) ) {
705 flags = CVAR_SERVERINFO;
706 } else {
707 Com_Printf( "Flags can only be 'u' or 's'\n" );
708 return;
709 }
710
711 var = Cvar_FullSet( Cmd_Argv( 1 ), Cmd_Argv( 2 ), flags, CVAR_SET_CONSOLE );
712 if( !var ) {
713 return;
714 }
715 }
716
717 /*
718 ============
719 Cvar_SetFlag_f
720
721 Allows setting and defining of arbitrary cvars from console
722 ============
723 */
Cvar_SetFlag_f(void)724 static void Cvar_SetFlag_f( void ) {
725 char *s;
726 int flags;
727
728 if( Cmd_Argc() < 3 ) {
729 Com_Printf( "Usage: %s <variable> <value>\n", Cmd_Argv( 0 ) );
730 return;
731 }
732
733 s = Cmd_Argv( 0 );
734 if( !Q_stricmp( s, "setu" ) ) {
735 flags = CVAR_USERINFO;
736 } else if( !Q_stricmp( s, "sets" ) ) {
737 flags = CVAR_SERVERINFO;
738 } else if( !Q_stricmp( s, "seta" ) ) {
739 flags = CVAR_ARCHIVE;
740 } else {
741 return;
742 }
743
744 Cvar_FullSet( Cmd_Argv( 1 ), Cmd_ArgsFrom( 2 ), flags, CVAR_SET_CONSOLE );
745 }
746
747 #ifndef DEDICATED_ONLY
748
749 /*
750 ============
751 Cvar_WriteVariables
752
753 Appends lines containing "set variable value" for all variables
754 with the archive flag set to true.
755 ============
756 */
Cvar_WriteVariables(fileHandle_t f)757 void Cvar_WriteVariables( fileHandle_t f ) {
758 cvar_t *var;
759 char *string;
760
761 for( var = cvar_vars; var; var = var->next ) {
762 if( var->flags & CVAR_ARCHIVE ) {
763 if( ( var->flags & CVAR_LATCHED ) && var->latched_string ) {
764 string = var->latched_string;
765 } else {
766 string = var->string;
767 }
768 FS_FPrintf( f, "set %s \"%s\"\n", var->name, string );
769 }
770 }
771 }
772
773 #endif
774
775 /*
776 ============
777 Cvar_List_f
778
779 ============
780 */
Cvar_List_f(void)781 static void Cvar_List_f( void ) {
782 cvar_t *var;
783 int i, total;
784 char *wildcard;
785 int showDesc;
786 int showFlags;
787 char buffer[6];
788
789 if( Cmd_CheckParam( "h", "help" ) ) {
790 Com_Printf( "Usage: %s [-f] [-d] [-h] [-w <wildcard>]\n",
791 Cmd_Argv( 0 ) );
792 Com_Printf( "Options:\n"
793 "-d, --desc : display description of each cvar\n"
794 "-f, --flags : display flags of each cvar\n"
795 "-h, --help : display this help message\n"
796 "-w, --wildcard : filter cvars by wildcard\n"
797 "Flags legend:\n"
798 "C: cheat protected\n"
799 "A: archived in config file\n"
800 "U: included in userinfo\n"
801 "S: included in serverinfo\n"
802 "N: set from command line only\n"
803 "R: read-only variable\n"
804 "L: latched (requires subsystem restart)\n"
805 "G: latched (requires game map restart)\n"
806 "?: created by user\n" );
807 return;
808 }
809
810 showFlags = Cmd_CheckParam( "f", "flags" );
811 showDesc = Cmd_CheckParam( "d", "desc" );
812 wildcard = Cmd_FindParam( "w", "wildcard" );
813
814 buffer[sizeof( buffer ) - 1] = 0;
815 i = 0;
816 for( var = cvar_vars, total = 0; var; var = var->next, total++ ) {
817 if( wildcard && !Com_WildCmp( wildcard, var->name, qtrue ) ) {
818 continue;
819 }
820
821 if( showFlags ) {
822 memset( buffer, ' ', sizeof( buffer ) - 1 );
823
824 if( var->flags & CVAR_CHEAT )
825 buffer[0] = 'C';
826
827 if( var->flags & CVAR_ARCHIVE )
828 buffer[1] = 'A';
829
830 if( var->flags & CVAR_USERINFO )
831 buffer[2] = 'U';
832
833 if( var->flags & CVAR_SERVERINFO )
834 buffer[3] = 'S';
835
836 if( var->flags & CVAR_ROM )
837 buffer[4] = 'R';
838 else if( var->flags & CVAR_NOSET )
839 buffer[4] = 'N';
840 else if( var->flags & CVAR_LATCHED )
841 buffer[4] = 'L';
842 else if( var->flags & CVAR_LATCH )
843 buffer[4] = 'G';
844 else if( var->flags & CVAR_USER_CREATED )
845 buffer[4] = '?';
846
847 Com_Printf( "%s ", buffer );
848 }
849
850 if( showDesc && var->description ) {
851 Com_Printf( "%s \"%s\" %s\n", var->name, var->string,
852 var->description );
853 } else {
854 Com_Printf( "%s \"%s\"\n", var->name, var->string );
855 }
856
857 i++;
858 }
859 Com_Printf( "%i of %i cvars\n", i, total );
860 }
861
862 /*
863 ============
864 Cvar_Toggle_f
865 ============
866 */
Cvar_Toggle_f(void)867 static void Cvar_Toggle_f( void ) {
868 char buffer[MAX_STRING_CHARS];
869 cvar_t *var;
870 int i;
871 int numArgs;
872
873 if( Cmd_Argc() < 2 ) {
874 Com_Printf( "Usage: %s <variable> [values]\n", Cmd_Argv( 0 ) );
875 return;
876 }
877
878 var = Cvar_FindVar( Cmd_Argv( 1 ) );
879 if( !var ) {
880 Com_Printf( "%s is not a variable\n", Cmd_Argv( 1 ) );
881 return;
882 }
883
884 if( Cmd_Argc() < 3 ) {
885 if( !strcmp( var->string, "0" ) ) {
886 Cvar_SetByVar( var, "1", CVAR_SET_CONSOLE );
887 } else if( !strcmp( var->string, "1" ) ) {
888 Cvar_SetByVar( var, "0", CVAR_SET_CONSOLE );
889 } else {
890 Com_Printf( "\"%s\" is \"%s\", can't toggle\n",
891 var->name, var->string );
892 }
893 return;
894 }
895
896 Q_strncpyz( buffer, Cmd_RawArgsFrom( 2 ), sizeof( buffer ) );
897 Cmd_TokenizeString( buffer, qfalse );
898 numArgs = Cmd_Argc();
899 for( i = 0; i < numArgs; i++ ) {
900 if( !Q_stricmp( var->string, Cmd_Argv( i ) ) ) {
901 i = ( i + 1 ) % numArgs;
902 Cvar_SetByVar( var, Cmd_Argv( i ), CVAR_SET_CONSOLE );
903 return;
904 }
905 }
906
907 Com_Printf( "\"%s\" is \"%s\", can't cycle\n", var->name, var->string );
908 }
909
910 /*
911 ============
912 Cvar_Inc_f
913 ============
914 */
Cvar_Inc_f(void)915 static void Cvar_Inc_f( void ) {
916 cvar_t *var;
917 float val;
918
919 if( Cmd_Argc() < 2 ) {
920 Com_Printf( "Usage: %s <variable> [value]\n", Cmd_Argv( 0 ) );
921 return;
922 }
923
924 var = Cvar_FindVar( Cmd_Argv( 1 ) );
925 if( !var ) {
926 Com_Printf( "%s is not a variable\n", Cmd_Argv( 1 ) );
927 return;
928 }
929
930 if( !COM_IsNumeric( var->string ) ) {
931 Com_Printf( "\"%s\" is \"%s\", can't increment\n",
932 var->name, var->string );
933 return;
934 }
935
936 val = 1.0f;
937 if( Cmd_Argc() > 2 ) {
938 val = atof( Cmd_Argv( 2 ) );
939 }
940
941 Cvar_SetValue( var->name, var->value + val );
942 }
943
944 /*
945 ============
946 Cvar_Reset_f
947 ============
948 */
Cvar_Reset_f(void)949 static void Cvar_Reset_f( void ) {
950 cvar_t *var;
951
952 if( Cmd_Argc() < 2 ) {
953 Com_Printf( "Usage: %s <variable>\n", Cmd_Argv( 0 ) );
954 return;
955 }
956
957 var = Cvar_FindVar( Cmd_Argv( 1 ) );
958 if( !var ) {
959 Com_Printf( "%s is not a variable\n", Cmd_Argv( 1 ) );
960 return;
961 }
962
963 Cvar_SetByVar( var, var->defaultString, CVAR_SET_CONSOLE );
964 }
965
Cvar_BitInfo(int bit)966 char *Cvar_BitInfo( int bit ) {
967 static char info[MAX_INFO_STRING];
968 char newi[MAX_INFO_STRING];
969 cvar_t *var;
970 int length, totalLength;
971
972 info[0] = 0;
973 totalLength = 0;
974
975 for( var = cvar_vars; var; var = var->next ) {
976 if( !( var->flags & bit ) ) {
977 continue;
978 }
979 if( !var->string[0] ) {
980 continue;
981 }
982 length = Com_sprintf( newi, sizeof( newi ), "\\%s\\%s",
983 var->name, var->string );
984 if( totalLength + length > MAX_INFO_STRING - 1 ) {
985 break;
986 }
987 strcpy( info + totalLength, newi );
988 totalLength += length;
989 }
990 return info;
991 }
992
993 // used for generating enhanced server status response
Cvar_BitInfo_Big(int bit)994 char *Cvar_BitInfo_Big( int bit ) {
995 static char info[MAX_STRING_CHARS];
996 char newi[MAX_STRING_CHARS];
997 cvar_t *var;
998 int length, totalLength;
999
1000 info[0] = 0;
1001 totalLength = 0;
1002
1003 for( var = cvar_vars; var; var = var->next ) {
1004 if( !( var->flags & bit ) ) {
1005 continue;
1006 }
1007 if( !var->string[0] ) {
1008 continue;
1009 }
1010 length = Com_sprintf( newi, sizeof( newi ), "\\%s\\%s",
1011 var->name, var->string );
1012 if( totalLength + length > MAX_STRING_CHARS - 1 ) {
1013 break;
1014 }
1015 strcpy( info + totalLength, newi );
1016 totalLength += length;
1017 }
1018 return info;
1019 }
1020
1021 /*
1022 ============
1023 Cvar_FillAPI
1024 ============
1025 */
Cvar_FillAPI(cvarAPI_t * api)1026 void Cvar_FillAPI( cvarAPI_t *api ) {
1027 api->Get = Cvar_Get;
1028 api->Set = Cvar_Set;
1029 api->SetValue = Cvar_SetValue;
1030 api->SetInteger = Cvar_SetInteger;
1031 api->VariableValue = Cvar_VariableValue;
1032 api->VariableInteger = Cvar_VariableInteger;
1033 api->VariableString = Cvar_VariableString;
1034 api->VariableStringBuffer = Cvar_VariableStringBuffer;
1035 api->Subsystem = Cvar_Subsystem;
1036 }
1037
1038 /*
1039 ============
1040 Cvar_Init
1041 ============
1042 */
Cvar_Init(void)1043 void Cvar_Init( void ) {
1044 cvar_silent = Cvar_Get( "cvar_silent", "0", 0 );
1045
1046 Cmd_AddCommandEx( "set", Cvar_Set_f, Cvar_Generator );
1047 Cmd_AddCommandEx( "setu", Cvar_SetFlag_f, Cvar_Generator );
1048 Cmd_AddCommandEx( "sets", Cvar_SetFlag_f, Cvar_Generator );
1049 Cmd_AddCommandEx( "seta", Cvar_SetFlag_f, Cvar_Generator );
1050 Cmd_AddCommand( "cvarlist", Cvar_List_f );
1051 Cmd_AddCommandEx( "cvar_toggle", Cvar_Toggle_f, Cvar_Generator );
1052 Cmd_AddCommandEx( "cvar_inc", Cvar_Inc_f, Cvar_Generator );
1053 Cmd_AddCommandEx( "cvar_reset", Cvar_Reset_f, Cvar_Generator );
1054
1055 Cvar_FillAPI( &cvar );
1056 }
1057
1058