cvar.c (9024B)
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 cvar_t *cvar_vars; 25 26 /* 27 ============ 28 Cvar_InfoValidate 29 ============ 30 */ 31 static qboolean Cvar_InfoValidate (char *s) 32 { 33 if (strstr (s, "\\")) 34 return false; 35 if (strstr (s, "\"")) 36 return false; 37 if (strstr (s, ";")) 38 return false; 39 return true; 40 } 41 42 /* 43 ============ 44 Cvar_FindVar 45 ============ 46 */ 47 static cvar_t *Cvar_FindVar (char *var_name) 48 { 49 cvar_t *var; 50 51 for (var=cvar_vars ; var ; var=var->next) 52 if (!strcmp (var_name, var->name)) 53 return var; 54 55 return NULL; 56 } 57 58 /* 59 ============ 60 Cvar_VariableValue 61 ============ 62 */ 63 float Cvar_VariableValue (char *var_name) 64 { 65 cvar_t *var; 66 67 var = Cvar_FindVar (var_name); 68 if (!var) 69 return 0; 70 return atof (var->string); 71 } 72 73 74 /* 75 ============ 76 Cvar_VariableString 77 ============ 78 */ 79 char *Cvar_VariableString (char *var_name) 80 { 81 cvar_t *var; 82 83 var = Cvar_FindVar (var_name); 84 if (!var) 85 return ""; 86 return var->string; 87 } 88 89 90 /* 91 ============ 92 Cvar_CompleteVariable 93 ============ 94 */ 95 char *Cvar_CompleteVariable (char *partial) 96 { 97 cvar_t *cvar; 98 int len; 99 100 len = strlen(partial); 101 102 if (!len) 103 return NULL; 104 105 // check exact match 106 for (cvar=cvar_vars ; cvar ; cvar=cvar->next) 107 if (!strcmp (partial,cvar->name)) 108 return cvar->name; 109 110 // check partial match 111 for (cvar=cvar_vars ; cvar ; cvar=cvar->next) 112 if (!strncmp (partial,cvar->name, len)) 113 return cvar->name; 114 115 return NULL; 116 } 117 118 119 /* 120 ============ 121 Cvar_Get 122 123 If the variable already exists, the value will not be set 124 The flags will be or'ed in if the variable exists. 125 ============ 126 */ 127 cvar_t *Cvar_Get (char *var_name, char *var_value, int flags) 128 { 129 cvar_t *var; 130 131 if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) 132 { 133 if (!Cvar_InfoValidate (var_name)) 134 { 135 Com_Printf("invalid info cvar name\n"); 136 return NULL; 137 } 138 } 139 140 var = Cvar_FindVar (var_name); 141 if (var) 142 { 143 var->flags |= flags; 144 return var; 145 } 146 147 if (!var_value) 148 return NULL; 149 150 if (flags & (CVAR_USERINFO | CVAR_SERVERINFO)) 151 { 152 if (!Cvar_InfoValidate (var_value)) 153 { 154 Com_Printf("invalid info cvar value\n"); 155 return NULL; 156 } 157 } 158 159 var = Z_Malloc (sizeof(*var)); 160 var->name = CopyString (var_name); 161 var->string = CopyString (var_value); 162 var->modified = true; 163 var->value = atof (var->string); 164 165 // link the variable in 166 var->next = cvar_vars; 167 cvar_vars = var; 168 169 var->flags = flags; 170 171 return var; 172 } 173 174 /* 175 ============ 176 Cvar_Set2 177 ============ 178 */ 179 cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force) 180 { 181 cvar_t *var; 182 183 var = Cvar_FindVar (var_name); 184 if (!var) 185 { // create it 186 return Cvar_Get (var_name, value, 0); 187 } 188 189 if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO)) 190 { 191 if (!Cvar_InfoValidate (value)) 192 { 193 Com_Printf("invalid info cvar value\n"); 194 return var; 195 } 196 } 197 198 if (!force) 199 { 200 if (var->flags & CVAR_NOSET) 201 { 202 Com_Printf ("%s is write protected.\n", var_name); 203 return var; 204 } 205 206 if (var->flags & CVAR_LATCH) 207 { 208 if (var->latched_string) 209 { 210 if (strcmp(value, var->latched_string) == 0) 211 return var; 212 Z_Free (var->latched_string); 213 } 214 else 215 { 216 if (strcmp(value, var->string) == 0) 217 return var; 218 } 219 220 if (Com_ServerState()) 221 { 222 Com_Printf ("%s will be changed for next game.\n", var_name); 223 var->latched_string = CopyString(value); 224 } 225 else 226 { 227 var->string = CopyString(value); 228 var->value = atof (var->string); 229 if (!strcmp(var->name, "game")) 230 { 231 FS_SetGamedir (var->string); 232 FS_ExecAutoexec (); 233 } 234 } 235 return var; 236 } 237 } 238 else 239 { 240 if (var->latched_string) 241 { 242 Z_Free (var->latched_string); 243 var->latched_string = NULL; 244 } 245 } 246 247 if (!strcmp(value, var->string)) 248 return var; // not changed 249 250 var->modified = true; 251 252 if (var->flags & CVAR_USERINFO) 253 userinfo_modified = true; // transmit at next oportunity 254 255 Z_Free (var->string); // free the old value string 256 257 var->string = CopyString(value); 258 var->value = atof (var->string); 259 260 return var; 261 } 262 263 /* 264 ============ 265 Cvar_ForceSet 266 ============ 267 */ 268 cvar_t *Cvar_ForceSet (char *var_name, char *value) 269 { 270 return Cvar_Set2 (var_name, value, true); 271 } 272 273 /* 274 ============ 275 Cvar_Set 276 ============ 277 */ 278 cvar_t *Cvar_Set (char *var_name, char *value) 279 { 280 return Cvar_Set2 (var_name, value, false); 281 } 282 283 /* 284 ============ 285 Cvar_FullSet 286 ============ 287 */ 288 cvar_t *Cvar_FullSet (char *var_name, char *value, int flags) 289 { 290 cvar_t *var; 291 292 var = Cvar_FindVar (var_name); 293 if (!var) 294 { // create it 295 return Cvar_Get (var_name, value, flags); 296 } 297 298 var->modified = true; 299 300 if (var->flags & CVAR_USERINFO) 301 userinfo_modified = true; // transmit at next oportunity 302 303 Z_Free (var->string); // free the old value string 304 305 var->string = CopyString(value); 306 var->value = atof (var->string); 307 var->flags = flags; 308 309 return var; 310 } 311 312 /* 313 ============ 314 Cvar_SetValue 315 ============ 316 */ 317 void Cvar_SetValue (char *var_name, float value) 318 { 319 char val[32]; 320 321 if (value == (int)value) 322 Com_sprintf (val, sizeof(val), "%i",(int)value); 323 else 324 Com_sprintf (val, sizeof(val), "%f",value); 325 Cvar_Set (var_name, val); 326 } 327 328 329 /* 330 ============ 331 Cvar_GetLatchedVars 332 333 Any variables with latched values will now be updated 334 ============ 335 */ 336 void Cvar_GetLatchedVars (void) 337 { 338 cvar_t *var; 339 340 for (var = cvar_vars ; var ; var = var->next) 341 { 342 if (!var->latched_string) 343 continue; 344 Z_Free (var->string); 345 var->string = var->latched_string; 346 var->latched_string = NULL; 347 var->value = atof(var->string); 348 if (!strcmp(var->name, "game")) 349 { 350 FS_SetGamedir (var->string); 351 FS_ExecAutoexec (); 352 } 353 } 354 } 355 356 /* 357 ============ 358 Cvar_Command 359 360 Handles variable inspection and changing from the console 361 ============ 362 */ 363 qboolean Cvar_Command (void) 364 { 365 cvar_t *v; 366 367 // check variables 368 v = Cvar_FindVar (Cmd_Argv(0)); 369 if (!v) 370 return false; 371 372 // perform a variable print or set 373 if (Cmd_Argc() == 1) 374 { 375 Com_Printf ("\"%s\" is \"%s\"\n", v->name, v->string); 376 return true; 377 } 378 379 Cvar_Set (v->name, Cmd_Argv(1)); 380 return true; 381 } 382 383 384 /* 385 ============ 386 Cvar_Set_f 387 388 Allows setting and defining of arbitrary cvars from console 389 ============ 390 */ 391 void Cvar_Set_f (void) 392 { 393 int c; 394 int flags; 395 396 c = Cmd_Argc(); 397 if (c != 3 && c != 4) 398 { 399 Com_Printf ("usage: set <variable> <value> [u / s]\n"); 400 return; 401 } 402 403 if (c == 4) 404 { 405 if (!strcmp(Cmd_Argv(3), "u")) 406 flags = CVAR_USERINFO; 407 else if (!strcmp(Cmd_Argv(3), "s")) 408 flags = CVAR_SERVERINFO; 409 else 410 { 411 Com_Printf ("flags can only be 'u' or 's'\n"); 412 return; 413 } 414 Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags); 415 } 416 else 417 Cvar_Set (Cmd_Argv(1), Cmd_Argv(2)); 418 } 419 420 421 /* 422 ============ 423 Cvar_WriteVariables 424 425 Appends lines containing "set variable value" for all variables 426 with the archive flag set to true. 427 ============ 428 */ 429 void Cvar_WriteVariables (char *path) 430 { 431 cvar_t *var; 432 char buffer[1024]; 433 FILE *f; 434 435 f = fopen (path, "a"); 436 for (var = cvar_vars ; var ; var = var->next) 437 { 438 if (var->flags & CVAR_ARCHIVE) 439 { 440 Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string); 441 fprintf (f, "%s", buffer); 442 } 443 } 444 fclose (f); 445 } 446 447 /* 448 ============ 449 Cvar_List_f 450 451 ============ 452 */ 453 void Cvar_List_f (void) 454 { 455 cvar_t *var; 456 int i; 457 458 i = 0; 459 for (var = cvar_vars ; var ; var = var->next, i++) 460 { 461 if (var->flags & CVAR_ARCHIVE) 462 Com_Printf ("*"); 463 else 464 Com_Printf (" "); 465 if (var->flags & CVAR_USERINFO) 466 Com_Printf ("U"); 467 else 468 Com_Printf (" "); 469 if (var->flags & CVAR_SERVERINFO) 470 Com_Printf ("S"); 471 else 472 Com_Printf (" "); 473 if (var->flags & CVAR_NOSET) 474 Com_Printf ("-"); 475 else if (var->flags & CVAR_LATCH) 476 Com_Printf ("L"); 477 else 478 Com_Printf (" "); 479 Com_Printf (" %s \"%s\"\n", var->name, var->string); 480 } 481 Com_Printf ("%i cvars\n", i); 482 } 483 484 485 qboolean userinfo_modified; 486 487 488 char *Cvar_BitInfo (int bit) 489 { 490 static char info[MAX_INFO_STRING]; 491 cvar_t *var; 492 493 info[0] = 0; 494 495 for (var = cvar_vars ; var ; var = var->next) 496 { 497 if (var->flags & bit) 498 Info_SetValueForKey (info, var->name, var->string); 499 } 500 return info; 501 } 502 503 // returns an info string containing all the CVAR_USERINFO cvars 504 char *Cvar_Userinfo (void) 505 { 506 return Cvar_BitInfo (CVAR_USERINFO); 507 } 508 509 // returns an info string containing all the CVAR_SERVERINFO cvars 510 char *Cvar_Serverinfo (void) 511 { 512 return Cvar_BitInfo (CVAR_SERVERINFO); 513 } 514 515 /* 516 ============ 517 Cvar_Init 518 519 Reads in all archived cvars 520 ============ 521 */ 522 void Cvar_Init (void) 523 { 524 Cmd_AddCommand ("set", Cvar_Set_f); 525 Cmd_AddCommand ("cvarlist", Cvar_List_f); 526 527 }