00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "../game/q_shared.h"
00025 #include "qcommon.h"
00026
00027 cvar_t *cvar_vars;
00028 cvar_t *cvar_cheats;
00029 int cvar_modifiedFlags;
00030
00031 #define MAX_CVARS 1024
00032 cvar_t cvar_indexes[MAX_CVARS];
00033 int cvar_numIndexes;
00034
00035 #define FILE_HASH_SIZE 256
00036 static cvar_t* hashTable[FILE_HASH_SIZE];
00037
00038 cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force);
00039
00040
00041
00042
00043
00044
00045 static long generateHashValue( const char *fname ) {
00046 int i;
00047 long hash;
00048 char letter;
00049
00050 hash = 0;
00051 i = 0;
00052 while (fname[i] != '\0') {
00053 letter = tolower(fname[i]);
00054 hash+=(long)(letter)*(i+119);
00055 i++;
00056 }
00057 hash &= (FILE_HASH_SIZE-1);
00058 return hash;
00059 }
00060
00061
00062
00063
00064
00065
00066 static qboolean Cvar_ValidateString( const char *s ) {
00067 if ( !s ) {
00068 return qfalse;
00069 }
00070 if ( strchr( s, '\\' ) ) {
00071 return qfalse;
00072 }
00073 if ( strchr( s, '\"' ) ) {
00074 return qfalse;
00075 }
00076 if ( strchr( s, ';' ) ) {
00077 return qfalse;
00078 }
00079 return qtrue;
00080 }
00081
00082
00083
00084
00085
00086
00087 static cvar_t *Cvar_FindVar( const char *var_name ) {
00088 cvar_t *var;
00089 long hash;
00090
00091 hash = generateHashValue(var_name);
00092
00093 for (var=hashTable[hash] ; var ; var=var->hashNext) {
00094 if (!Q_stricmp(var_name, var->name)) {
00095 return var;
00096 }
00097 }
00098
00099 return NULL;
00100 }
00101
00102
00103
00104
00105
00106
00107 float Cvar_VariableValue( const char *var_name ) {
00108 cvar_t *var;
00109
00110 var = Cvar_FindVar (var_name);
00111 if (!var)
00112 return 0;
00113 return var->value;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122 int Cvar_VariableIntegerValue( const char *var_name ) {
00123 cvar_t *var;
00124
00125 var = Cvar_FindVar (var_name);
00126 if (!var)
00127 return 0;
00128 return var->integer;
00129 }
00130
00131
00132
00133
00134
00135
00136
00137 char *Cvar_VariableString( const char *var_name ) {
00138 cvar_t *var;
00139
00140 var = Cvar_FindVar (var_name);
00141 if (!var)
00142 return "";
00143 return var->string;
00144 }
00145
00146
00147
00148
00149
00150
00151
00152 void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
00153 cvar_t *var;
00154
00155 var = Cvar_FindVar (var_name);
00156 if (!var) {
00157 *buffer = 0;
00158 }
00159 else {
00160 Q_strncpyz( buffer, var->string, bufsize );
00161 }
00162 }
00163
00164
00165
00166
00167
00168
00169
00170 void Cvar_CommandCompletion( void(*callback)(const char *s) ) {
00171 cvar_t *cvar;
00172
00173 for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) {
00174 callback( cvar->name );
00175 }
00176 }
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) {
00188 cvar_t *var;
00189 long hash;
00190
00191 if ( !var_name || ! var_value ) {
00192 Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" );
00193 }
00194
00195 if ( !Cvar_ValidateString( var_name ) ) {
00196 Com_Printf("invalid cvar name string: %s\n", var_name );
00197 var_name = "BADNAME";
00198 }
00199
00200 #if 0 // FIXME: values with backslash happen
00201 if ( !Cvar_ValidateString( var_value ) ) {
00202 Com_Printf("invalid cvar value string: %s\n", var_value );
00203 var_value = "BADVALUE";
00204 }
00205 #endif
00206
00207 var = Cvar_FindVar (var_name);
00208 if ( var ) {
00209
00210
00211 if ( ( var->flags & CVAR_USER_CREATED ) && !( flags & CVAR_USER_CREATED )
00212 && var_value[0] ) {
00213 var->flags &= ~CVAR_USER_CREATED;
00214 Z_Free( var->resetString );
00215 var->resetString = CopyString( var_value );
00216
00217
00218
00219 cvar_modifiedFlags |= flags;
00220 }
00221
00222 var->flags |= flags;
00223
00224 if ( !var->resetString[0] ) {
00225
00226 Z_Free( var->resetString );
00227 var->resetString = CopyString( var_value );
00228 } else if ( var_value[0] && strcmp( var->resetString, var_value ) ) {
00229 Com_DPrintf( "Warning: cvar \"%s\" given initial values: \"%s\" and \"%s\"\n",
00230 var_name, var->resetString, var_value );
00231 }
00232
00233 if ( var->latchedString ) {
00234 char *s;
00235
00236 s = var->latchedString;
00237 var->latchedString = NULL;
00238 Cvar_Set2( var_name, s, qtrue );
00239 Z_Free( s );
00240 }
00241
00242
00243 #if 0
00244
00245 if ( flags & CVAR_ROM ) {
00246 Cvar_Set2( var_name, var_value, qtrue );
00247 }
00248 #endif
00249 return var;
00250 }
00251
00252
00253
00254
00255 if ( cvar_numIndexes >= MAX_CVARS ) {
00256 Com_Error( ERR_FATAL, "MAX_CVARS" );
00257 }
00258 var = &cvar_indexes[cvar_numIndexes];
00259 cvar_numIndexes++;
00260 var->name = CopyString (var_name);
00261 var->string = CopyString (var_value);
00262 var->modified = qtrue;
00263 var->modificationCount = 1;
00264 var->value = atof (var->string);
00265 var->integer = atoi(var->string);
00266 var->resetString = CopyString( var_value );
00267
00268
00269 var->next = cvar_vars;
00270 cvar_vars = var;
00271
00272 var->flags = flags;
00273
00274 hash = generateHashValue(var_name);
00275 var->hashNext = hashTable[hash];
00276 hashTable[hash] = var;
00277
00278 return var;
00279 }
00280
00281
00282
00283
00284
00285
00286 cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) {
00287 cvar_t *var;
00288
00289 Com_DPrintf( "Cvar_Set2: %s %s\n", var_name, value );
00290
00291 if ( !Cvar_ValidateString( var_name ) ) {
00292 Com_Printf("invalid cvar name string: %s\n", var_name );
00293 var_name = "BADNAME";
00294 }
00295
00296 #if 0 // FIXME
00297 if ( value && !Cvar_ValidateString( value ) ) {
00298 Com_Printf("invalid cvar value string: %s\n", value );
00299 var_value = "BADVALUE";
00300 }
00301 #endif
00302
00303 var = Cvar_FindVar (var_name);
00304 if (!var) {
00305 if ( !value ) {
00306 return NULL;
00307 }
00308
00309 if ( !force ) {
00310 return Cvar_Get( var_name, value, CVAR_USER_CREATED );
00311 } else {
00312 return Cvar_Get (var_name, value, 0);
00313 }
00314 }
00315
00316 if (!value ) {
00317 value = var->resetString;
00318 }
00319
00320 if (!strcmp(value,var->string)) {
00321 return var;
00322 }
00323
00324 cvar_modifiedFlags |= var->flags;
00325
00326 if (!force)
00327 {
00328 if (var->flags & CVAR_ROM)
00329 {
00330 Com_Printf ("%s is read only.\n", var_name);
00331 return var;
00332 }
00333
00334 if (var->flags & CVAR_INIT)
00335 {
00336 Com_Printf ("%s is write protected.\n", var_name);
00337 return var;
00338 }
00339
00340 if (var->flags & CVAR_LATCH)
00341 {
00342 if (var->latchedString)
00343 {
00344 if (strcmp(value, var->latchedString) == 0)
00345 return var;
00346 Z_Free (var->latchedString);
00347 }
00348 else
00349 {
00350 if (strcmp(value, var->string) == 0)
00351 return var;
00352 }
00353
00354 Com_Printf ("%s will be changed upon restarting.\n", var_name);
00355 var->latchedString = CopyString(value);
00356 var->modified = qtrue;
00357 var->modificationCount++;
00358 return var;
00359 }
00360
00361 if ( (var->flags & CVAR_CHEAT) && !cvar_cheats->integer )
00362 {
00363 Com_Printf ("%s is cheat protected.\n", var_name);
00364 return var;
00365 }
00366
00367 }
00368 else
00369 {
00370 if (var->latchedString)
00371 {
00372 Z_Free (var->latchedString);
00373 var->latchedString = NULL;
00374 }
00375 }
00376
00377 if (!strcmp(value, var->string))
00378 return var;
00379
00380 var->modified = qtrue;
00381 var->modificationCount++;
00382
00383 Z_Free (var->string);
00384
00385 var->string = CopyString(value);
00386 var->value = atof (var->string);
00387 var->integer = atoi (var->string);
00388
00389 return var;
00390 }
00391
00392
00393
00394
00395
00396
00397 void Cvar_Set( const char *var_name, const char *value) {
00398 Cvar_Set2 (var_name, value, qtrue);
00399 }
00400
00401
00402
00403
00404
00405
00406 void Cvar_SetLatched( const char *var_name, const char *value) {
00407 Cvar_Set2 (var_name, value, qfalse);
00408 }
00409
00410
00411
00412
00413
00414
00415 void Cvar_SetValue( const char *var_name, float value) {
00416 char val[32];
00417
00418 if ( value == (int)value ) {
00419 Com_sprintf (val, sizeof(val), "%i",(int)value);
00420 } else {
00421 Com_sprintf (val, sizeof(val), "%f",value);
00422 }
00423 Cvar_Set (var_name, val);
00424 }
00425
00426
00427
00428
00429
00430
00431
00432 void Cvar_Reset( const char *var_name ) {
00433 Cvar_Set2( var_name, NULL, qfalse );
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 void Cvar_SetCheatState( void ) {
00445 cvar_t *var;
00446
00447
00448 for ( var = cvar_vars ; var ; var = var->next ) {
00449 if ( var->flags & CVAR_CHEAT ) {
00450
00451
00452 if (var->latchedString)
00453 {
00454 Z_Free(var->latchedString);
00455 var->latchedString = NULL;
00456 }
00457 if (strcmp(var->resetString,var->string)) {
00458 Cvar_Set( var->name, var->resetString );
00459 }
00460 }
00461 }
00462 }
00463
00464
00465
00466
00467
00468
00469
00470
00471 qboolean Cvar_Command( void ) {
00472 cvar_t *v;
00473
00474
00475 v = Cvar_FindVar (Cmd_Argv(0));
00476 if (!v) {
00477 return qfalse;
00478 }
00479
00480
00481 if ( Cmd_Argc() == 1 ) {
00482 Com_Printf ("\"%s\" is:\"%s" S_COLOR_WHITE "\" default:\"%s" S_COLOR_WHITE "\"\n", v->name, v->string, v->resetString );
00483 if ( v->latchedString ) {
00484 Com_Printf( "latched: \"%s\"\n", v->latchedString );
00485 }
00486 return qtrue;
00487 }
00488
00489
00490 Cvar_Set2 (v->name, Cmd_Argv(1), qfalse);
00491 return qtrue;
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502 void Cvar_Toggle_f( void ) {
00503 int v;
00504
00505 if ( Cmd_Argc() != 2 ) {
00506 Com_Printf ("usage: toggle <variable>\n");
00507 return;
00508 }
00509
00510 v = Cvar_VariableValue( Cmd_Argv( 1 ) );
00511 v = !v;
00512
00513 Cvar_Set2 (Cmd_Argv(1), va("%i", v), qfalse);
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 void Cvar_Set_f( void ) {
00525 int i, c, l, len;
00526 char combined[MAX_STRING_TOKENS];
00527
00528 c = Cmd_Argc();
00529 if ( c < 3 ) {
00530 Com_Printf ("usage: set <variable> <value>\n");
00531 return;
00532 }
00533
00534 combined[0] = 0;
00535 l = 0;
00536 for ( i = 2 ; i < c ; i++ ) {
00537 len = strlen ( Cmd_Argv( i ) + 1 );
00538 if ( l + len >= MAX_STRING_TOKENS - 2 ) {
00539 break;
00540 }
00541 strcat( combined, Cmd_Argv( i ) );
00542 if ( i != c-1 ) {
00543 strcat( combined, " " );
00544 }
00545 l += len;
00546 }
00547 Cvar_Set2 (Cmd_Argv(1), combined, qfalse);
00548 }
00549
00550
00551
00552
00553
00554
00555
00556
00557 void Cvar_SetU_f( void ) {
00558 cvar_t *v;
00559
00560 if ( Cmd_Argc() != 3 ) {
00561 Com_Printf ("usage: setu <variable> <value>\n");
00562 return;
00563 }
00564 Cvar_Set_f();
00565 v = Cvar_FindVar( Cmd_Argv( 1 ) );
00566 if ( !v ) {
00567 return;
00568 }
00569 v->flags |= CVAR_USERINFO;
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579 void Cvar_SetS_f( void ) {
00580 cvar_t *v;
00581
00582 if ( Cmd_Argc() != 3 ) {
00583 Com_Printf ("usage: sets <variable> <value>\n");
00584 return;
00585 }
00586 Cvar_Set_f();
00587 v = Cvar_FindVar( Cmd_Argv( 1 ) );
00588 if ( !v ) {
00589 return;
00590 }
00591 v->flags |= CVAR_SERVERINFO;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601 void Cvar_SetA_f( void ) {
00602 cvar_t *v;
00603
00604 if ( Cmd_Argc() != 3 ) {
00605 Com_Printf ("usage: seta <variable> <value>\n");
00606 return;
00607 }
00608 Cvar_Set_f();
00609 v = Cvar_FindVar( Cmd_Argv( 1 ) );
00610 if ( !v ) {
00611 return;
00612 }
00613 v->flags |= CVAR_ARCHIVE;
00614 }
00615
00616
00617
00618
00619
00620
00621 void Cvar_Reset_f( void ) {
00622 if ( Cmd_Argc() != 2 ) {
00623 Com_Printf ("usage: reset <variable>\n");
00624 return;
00625 }
00626 Cvar_Reset( Cmd_Argv( 1 ) );
00627 }
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 void Cvar_WriteVariables( fileHandle_t f ) {
00638 cvar_t *var;
00639 char buffer[1024];
00640
00641 for (var = cvar_vars ; var ; var = var->next) {
00642 if( Q_stricmp( var->name, "cl_cdkey" ) == 0 ) {
00643 continue;
00644 }
00645 if( var->flags & CVAR_ARCHIVE ) {
00646
00647 if ( var->latchedString ) {
00648 Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->latchedString);
00649 } else {
00650 Com_sprintf (buffer, sizeof(buffer), "seta %s \"%s\"\n", var->name, var->string);
00651 }
00652 FS_Printf (f, "%s", buffer);
00653 }
00654 }
00655 }
00656
00657
00658
00659
00660
00661
00662 void Cvar_List_f( void ) {
00663 cvar_t *var;
00664 int i;
00665 char *match;
00666
00667 if ( Cmd_Argc() > 1 ) {
00668 match = Cmd_Argv( 1 );
00669 } else {
00670 match = NULL;
00671 }
00672
00673 i = 0;
00674 for (var = cvar_vars ; var ; var = var->next, i++)
00675 {
00676 if (match && !Com_Filter(match, var->name, qfalse)) continue;
00677
00678 if (var->flags & CVAR_SERVERINFO) {
00679 Com_Printf("S");
00680 } else {
00681 Com_Printf(" ");
00682 }
00683 if (var->flags & CVAR_USERINFO) {
00684 Com_Printf("U");
00685 } else {
00686 Com_Printf(" ");
00687 }
00688 if (var->flags & CVAR_ROM) {
00689 Com_Printf("R");
00690 } else {
00691 Com_Printf(" ");
00692 }
00693 if (var->flags & CVAR_INIT) {
00694 Com_Printf("I");
00695 } else {
00696 Com_Printf(" ");
00697 }
00698 if (var->flags & CVAR_ARCHIVE) {
00699 Com_Printf("A");
00700 } else {
00701 Com_Printf(" ");
00702 }
00703 if (var->flags & CVAR_LATCH) {
00704 Com_Printf("L");
00705 } else {
00706 Com_Printf(" ");
00707 }
00708 if (var->flags & CVAR_CHEAT) {
00709 Com_Printf("C");
00710 } else {
00711 Com_Printf(" ");
00712 }
00713
00714 Com_Printf (" %s \"%s\"\n", var->name, var->string);
00715 }
00716
00717 Com_Printf ("\n%i total cvars\n", i);
00718 Com_Printf ("%i cvar indexes\n", cvar_numIndexes);
00719 }
00720
00721
00722
00723
00724
00725
00726
00727
00728 void Cvar_Restart_f( void ) {
00729 cvar_t *var;
00730 cvar_t **prev;
00731
00732 prev = &cvar_vars;
00733 while ( 1 ) {
00734 var = *prev;
00735 if ( !var ) {
00736 break;
00737 }
00738
00739
00740
00741 if ( var->flags & ( CVAR_ROM | CVAR_INIT | CVAR_NORESTART ) ) {
00742 prev = &var->next;
00743 continue;
00744 }
00745
00746
00747 if ( var->flags & CVAR_USER_CREATED ) {
00748 *prev = var->next;
00749 if ( var->name ) {
00750 Z_Free( var->name );
00751 }
00752 if ( var->string ) {
00753 Z_Free( var->string );
00754 }
00755 if ( var->latchedString ) {
00756 Z_Free( var->latchedString );
00757 }
00758 if ( var->resetString ) {
00759 Z_Free( var->resetString );
00760 }
00761
00762
00763 Com_Memset( var, 0, sizeof( var ) );
00764 continue;
00765 }
00766
00767 Cvar_Set( var->name, var->resetString );
00768
00769 prev = &var->next;
00770 }
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780 char *Cvar_InfoString( int bit ) {
00781 static char info[MAX_INFO_STRING];
00782 cvar_t *var;
00783
00784 info[0] = 0;
00785
00786 for (var = cvar_vars ; var ; var = var->next) {
00787 if (var->flags & bit) {
00788 Info_SetValueForKey (info, var->name, var->string);
00789 }
00790 }
00791 return info;
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801 char *Cvar_InfoString_Big( int bit ) {
00802 static char info[BIG_INFO_STRING];
00803 cvar_t *var;
00804
00805 info[0] = 0;
00806
00807 for (var = cvar_vars ; var ; var = var->next) {
00808 if (var->flags & bit) {
00809 Info_SetValueForKey_Big (info, var->name, var->string);
00810 }
00811 }
00812 return info;
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822 void Cvar_InfoStringBuffer( int bit, char* buff, int buffsize ) {
00823 Q_strncpyz(buff,Cvar_InfoString(bit),buffsize);
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833 void Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) {
00834 cvar_t *cv;
00835
00836 cv = Cvar_Get( varName, defaultValue, flags );
00837 if ( !vmCvar ) {
00838 return;
00839 }
00840 vmCvar->handle = cv - cvar_indexes;
00841 vmCvar->modificationCount = -1;
00842 Cvar_Update( vmCvar );
00843 }
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 void Cvar_Update( vmCvar_t *vmCvar ) {
00854 cvar_t *cv = NULL;
00855 assert(vmCvar);
00856
00857 if ( (unsigned)vmCvar->handle >= cvar_numIndexes ) {
00858 Com_Error( ERR_DROP, "Cvar_Update: handle out of range" );
00859 }
00860
00861 cv = cvar_indexes + vmCvar->handle;
00862
00863 if ( cv->modificationCount == vmCvar->modificationCount ) {
00864 return;
00865 }
00866 if ( !cv->string ) {
00867 return;
00868 }
00869 vmCvar->modificationCount = cv->modificationCount;
00870
00871 if ( strlen(cv->string)+1 > MAX_CVAR_VALUE_STRING )
00872 Com_Error( ERR_DROP, "Cvar_Update: src %s length %d exceeds MAX_CVAR_VALUE_STRING",
00873 cv->string,
00874 strlen(cv->string),
00875 sizeof(vmCvar->string) );
00876
00877
00878
00879
00880
00881 Q_strncpyz( vmCvar->string, cv->string, MAX_CVAR_VALUE_STRING );
00882
00883 vmCvar->value = cv->value;
00884 vmCvar->integer = cv->integer;
00885 }
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895 void Cvar_Init (void) {
00896 cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO );
00897
00898 Cmd_AddCommand ("toggle", Cvar_Toggle_f);
00899 Cmd_AddCommand ("set", Cvar_Set_f);
00900 Cmd_AddCommand ("sets", Cvar_SetS_f);
00901 Cmd_AddCommand ("setu", Cvar_SetU_f);
00902 Cmd_AddCommand ("seta", Cvar_SetA_f);
00903 Cmd_AddCommand ("reset", Cvar_Reset_f);
00904 Cmd_AddCommand ("cvarlist", Cvar_List_f);
00905 Cmd_AddCommand ("cvar_restart", Cvar_Restart_f);
00906 }