Quake II RTX doxygen  1.0 dev
cvar.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 // cvar.c -- dynamic variable tracking
19 
20 #include "shared/shared.h"
21 #include "common/cmd.h"
22 #include "common/common.h"
23 #include "common/cvar.h"
24 #include "common/files.h"
25 #include "common/prompt.h"
26 #include "common/utils.h"
27 #include "common/zone.h"
28 #include "client/client.h"
29 
30 cvar_t *cvar_vars;
31 
33 
34 #define Cvar_Malloc(size) Z_TagMalloc(size, TAG_CVAR)
35 
36 #define CVARHASH_SIZE 256
37 
38 static cvar_t *cvarHash[CVARHASH_SIZE];
39 
40 /*
41 ============
42 Cvar_FindVar
43 ============
44 */
45 cvar_t *Cvar_FindVar(const char *var_name)
46 {
47  cvar_t *var;
48  unsigned hash;
49 
50  hash = Com_HashString(var_name, CVARHASH_SIZE);
51 
52  for (var = cvarHash[hash]; var; var = var->hashNext) {
53  if (!strcmp(var_name, var->name)) {
54  return var;
55  }
56  }
57 
58  return NULL;
59 }
60 
61 xgenerator_t Cvar_FindGenerator(const char *var_name)
62 {
63  cvar_t *var = Cvar_FindVar(var_name);
64 
65  return var ? var->generator : NULL;
66 }
67 
68 /*
69 ============
70 Cvar_Exists
71 ============
72 */
73 qboolean Cvar_Exists(const char *var_name, qboolean weak)
74 {
75  cvar_t *var = Cvar_FindVar(var_name);
76 
77  if (!var)
78  return qfalse;
79  if (!weak && (var->flags & (CVAR_CUSTOM | CVAR_WEAK)))
80  return qfalse;
81  return qtrue;
82 }
83 
84 /*
85 ============
86 Cvar_VariableValue
87 ============
88 */
89 float Cvar_VariableValue(const char *var_name)
90 {
91  cvar_t *var;
92 
93  var = Cvar_FindVar(var_name);
94  if (!var)
95  return 0;
96 
97  return var->value;
98 }
99 
100 /*
101 ============
102 Cvar_VariableInteger
103 ============
104 */
105 int Cvar_VariableInteger(const char *var_name)
106 {
107  cvar_t *var;
108 
109  var = Cvar_FindVar(var_name);
110  if (!var)
111  return 0;
112 
113  return var->integer;
114 }
115 
116 
117 /*
118 ============
119 Cvar_VariableString
120 ============
121 */
122 char *Cvar_VariableString(const char *var_name)
123 {
124  cvar_t *var;
125 
126  var = Cvar_FindVar(var_name);
127  if (!var)
128  return "";
129 
130  return var->string;
131 }
132 
133 void Cvar_Variable_g(genctx_t *ctx)
134 {
135  cvar_t *c;
136 
137  for (c = cvar_vars; c; c = c->next) {
138  if (!Prompt_AddMatch(ctx, c->name)) {
139  break;
140  }
141  }
142 }
143 
144 void Cvar_Default_g(genctx_t *ctx)
145 {
146  cvar_t *c = ctx->data;
147 
148  if (c) {
149  if (strcmp(c->string, c->default_string)) {
150  Prompt_AddMatch(ctx, c->string);
151  }
152  Prompt_AddMatch(ctx, c->default_string);
153  }
154 }
155 
156 // parse integer and float values
157 static void parse_string_value(cvar_t *var)
158 {
159  char *s = var->string;
160 
161  if (s[0] == '0' && s[1] == 'x') {
162  long v = strtol(s, NULL, 16);
163 
164  var->integer = clamp(v, INT_MIN, INT_MAX);
165  var->value = (float)var->integer;
166  } else {
167  var->integer = atoi(var->string);
168  var->value = atof(var->string);
169  }
170 }
171 
172 // string value has been changed, do some things
173 static void change_string_value(cvar_t *var, const char *value, from_t from)
174 {
175  // free the old value string
176  Z_Free(var->string);
177 
178  var->string = Z_CvarCopyString(value);
179  parse_string_value(var);
180 
181  if (var->flags & CVAR_USERINFO) {
182  CL_UpdateUserinfo(var, from);
183  }
184 
185  var->modified = qtrue;
186  if (from != FROM_CODE) {
187  cvar_modified |= var->flags & CVAR_MODIFYMASK;
188  var->flags |= CVAR_MODIFIED;
189  if (from == FROM_MENU && !(var->flags & CVAR_NOARCHIVEMASK)) {
190  var->flags |= CVAR_ARCHIVE;
191  }
192  if (var->changed) {
193  var->changed(var);
194  }
195  }
196 }
197 
198 static qboolean validate_info_cvar(const char *s)
199 {
200  size_t len = Info_SubValidate(s);
201 
202  if (len == SIZE_MAX) {
203  Com_Printf("Info cvars should not contain '\\', ';' or '\"' characters.\n");
204  return qfalse;
205  }
206 
207  if (len >= MAX_QPATH) {
208  Com_Printf("Info cvars should be less than 64 characters long.\n");
209  return qfalse;
210  }
211 
212  return qtrue;
213 }
214 
215 
216 // Cvar_Get has been called from subsystem initialization routine.
217 // check if the first instance of this cvar has been created by user,
218 // and if so, enforce any restrictions on the cvar value as defined by flags
219 static void get_engine_cvar(cvar_t *var, const char *var_value, int flags)
220 {
221  if (var->flags & (CVAR_CUSTOM | CVAR_WEAK)) {
222  // update default string if cvar was set from command line
223  Z_Free(var->default_string);
224  var->default_string = Z_CvarCopyString(var_value);
225 
226  // see if it was changed from it's default value
227  if (strcmp(var_value, var->string)) {
228  if ((flags & CVAR_ROM) ||
229  ((flags & CVAR_NOSET) && com_initialized) ||
230  ((flags & CVAR_CHEAT) && !CL_CheatsOK()) ||
231  ((flags & CVAR_INFOMASK) && !validate_info_cvar(var->string)) ||
232  (var->flags & CVAR_WEAK)) {
233  // restricted cvars are reset back to default value
234  change_string_value(var, var_value, FROM_CODE);
235  } else {
236  // normal cvars are just flagged as modified by user
237  flags |= CVAR_MODIFIED;
238  }
239  }
240  } else {
241  flags &= ~CVAR_GAME;
242  }
243 
244  // some flags are not saved
245  var->flags &= ~(CVAR_GAME | CVAR_CUSTOM | CVAR_WEAK);
246  var->flags |= flags;
247 }
248 
249 /*
250 ============
251 Cvar_Get
252 
253 If the non-volatile variable already exists, the value will not be set.
254 The flags will be or'ed in if the variable exists.
255 ============
256 */
257 cvar_t *Cvar_Get(const char *var_name, const char *var_value, int flags)
258 {
259  cvar_t *var, *c, **p;
260  unsigned hash;
261  size_t length;
262 
263  if (!var_name) {
264  Com_Error(ERR_FATAL, "Cvar_Get: NULL var_name");
265  }
266  if (!var_value) {
267  return Cvar_FindVar(var_name);
268  }
269 
270  if (flags & CVAR_INFOMASK) {
271  if (!validate_info_cvar(var_name)) {
272  return NULL;
273  }
274  if (!validate_info_cvar(var_value)) {
275  return NULL;
276  }
277  }
278 
279  var = Cvar_FindVar(var_name);
280  if (var) {
281  if (!(flags & (CVAR_WEAK | CVAR_CUSTOM))) {
282  get_engine_cvar(var, var_value, flags);
283  }
284  return var;
285  }
286 
287 
288  // create new variable
289  length = strlen(var_name) + 1;
290  var = Cvar_Malloc(sizeof(*var) + length);
291  var->name = (char *)(var + 1);
292  memcpy(var->name, var_name, length);
293  var->string = Z_CvarCopyString(var_value);
294  var->latched_string = NULL;
295  var->default_string = Z_CvarCopyString(var_value);
296  parse_string_value(var);
297  var->flags = flags;
298  var->changed = NULL;
299  var->generator = Cvar_Default_g;
300  var->modified = qtrue;
301 
302  // sort the variable in
303  for (c = cvar_vars, p = &cvar_vars; c; p = &c->next, c = c->next) {
304  if (strcmp(var->name, c->name) < 0) {
305  break;
306  }
307  }
308  var->next = c;
309  *p = var;
310 
311  // link the variable in
312  hash = Com_HashString(var_name, CVARHASH_SIZE);
313  var->hashNext = cvarHash[hash];
314  cvarHash[hash] = var;
315 
316  return var;
317 }
318 
319 /*
320 ============
321 Cvar_WeakGet
322 ============
323 */
324 cvar_t *Cvar_WeakGet(const char *var_name)
325 {
326  return Cvar_Get(var_name, "", CVAR_WEAK);
327 }
328 
329 static void set_back_cvar(cvar_t *var)
330 {
331  if (var->flags & CVAR_LATCH) {
332  // set back to current value
333  if (var->latched_string) {
334  Z_Free(var->latched_string);
335  var->latched_string = NULL;
336  }
337  }
338 }
339 
340 /*
341 ============
342 Cvar_SetByVar
343 ============
344 */
345 void Cvar_SetByVar(cvar_t *var, const char *value, from_t from)
346 {
347  if (!value) {
348  value = "";
349  }
350  if (!strcmp(value, var->string)) {
351  set_back_cvar(var);
352  return; // not changed
353  }
354 
355  if (var->flags & CVAR_INFOMASK) {
356  if (!validate_info_cvar(value)) {
357  return;
358  }
359  }
360 
361  // some cvars may not be changed by user at all
362  if (from != FROM_CODE) {
363  if (var->flags & CVAR_ROM) {
364  Com_Printf("%s is read-only.\n", var->name);
365  return;
366  }
367 
368  if (var->flags & CVAR_CHEAT) {
369  if (!CL_CheatsOK()) {
370  Com_Printf("%s is cheat protected.\n", var->name);
371  return;
372  }
373  }
374  }
375 
376  // some cvars may require special processing if set by user from console
377  if (from <= FROM_CONSOLE && com_initialized) {
378  if (var->flags & CVAR_NOSET) {
379  Com_Printf("%s may be set from command line only.\n", var->name);
380  return;
381  }
382 
383  if (var->flags & CVAR_LATCH) {
384  // free latched value
385  if (var->latched_string) {
386  if (!strcmp(var->latched_string, value)) {
387  return; // latched string not changed
388  }
389  Z_Free(var->latched_string);
390  var->latched_string = NULL;
391  }
392 
393  if (sv_running->integer) {
394  Com_Printf("%s will be changed for next game.\n", var->name);
395  var->latched_string = Z_CvarCopyString(value);
396  return;
397  }
398  // server is down, it's ok to update this cvar now
399  }
400 
401  }
402 
403  // free latched string, if any
404  if (var->latched_string) {
405  Z_Free(var->latched_string);
406  var->latched_string = NULL;
407  }
408 
409  change_string_value(var, value, from);
410 }
411 
412 /*
413 ============
414 Cvar_SetEx
415 ============
416 */
417 cvar_t *Cvar_SetEx(const char *var_name, const char *value, from_t from)
418 {
419  cvar_t *var;
420 
421  var = Cvar_FindVar(var_name);
422  if (!var) {
423  // create it
424  return Cvar_Get(var_name, value, CVAR_CUSTOM);
425  }
426 
427  Cvar_SetByVar(var, value, from);
428 
429  return var;
430 }
431 
432 /*
433 ============
434 Cvar_FullSet
435 ============
436 */
437 cvar_t *Cvar_FullSet(const char *var_name, const char *value, int flags, from_t from)
438 {
439  cvar_t *var;
440 
441  var = Cvar_FindVar(var_name);
442  if (!var) {
443  // create it
444  return Cvar_Get(var_name, value, flags | CVAR_CUSTOM);
445  }
446 
447  Cvar_SetByVar(var, value, from);
448 
449  // force retransmit of userinfo variables
450  // needed for compatibility with q2admin
451  if ((var->flags | flags) & CVAR_USERINFO) {
452  CL_UpdateUserinfo(var, from);
453  }
454 
455  var->flags &= ~CVAR_INFOMASK;
456  var->flags |= flags;
457 
458  return var;
459 }
460 
461 /*
462 ============
463 Cvar_Set
464 ============
465 */
466 cvar_t *Cvar_Set(const char *var_name, const char *value)
467 {
468  return Cvar_SetEx(var_name, value, FROM_CODE);
469 }
470 
471 /*
472 ============
473 Cvar_UserSet
474 ============
475 */
476 cvar_t *Cvar_UserSet(const char *var_name, const char *value)
477 {
478  return Cvar_SetEx(var_name, value, FROM_CONSOLE);
479 }
480 
481 
482 /*
483 ============
484 Cvar_SetValue
485 ============
486 */
487 void Cvar_SetValue(cvar_t *var, float value, from_t from)
488 {
489  char val[32];
490 
491  if (var->value == value) {
492  set_back_cvar(var);
493  return; // not changed
494  }
495 
496  if (value == (int)value)
497  Q_snprintf(val, sizeof(val), "%i", (int)value);
498  else
499  Q_snprintf(val, sizeof(val), "%f", value);
500 
501  Cvar_SetByVar(var, val, from);
502 }
503 
504 /*
505 ============
506 Cvar_SetInteger
507 ============
508 */
509 void Cvar_SetInteger(cvar_t *var, int value, from_t from)
510 {
511  char val[32];
512 
513  if (var->integer == value) {
514  set_back_cvar(var);
515  return; // not changed
516  }
517 
518  Q_snprintf(val, sizeof(val), "%i", value);
519 
520  Cvar_SetByVar(var, val, from);
521 }
522 
523 #if 0
524 /*
525 ============
526 Cvar_SetHex
527 ============
528 */
529 void Cvar_SetHex(cvar_t *var, int value, from_t from)
530 {
531  char val[32];
532 
533  if (var->integer == value) {
534  set_back_cvar(var);
535  return; // not changed
536  }
537 
538  Q_snprintf(val, sizeof(val), "0x%X", value);
539 
540  Cvar_SetByVar(var, val, from);
541 }
542 #endif
543 
544 /*
545 ============
546 Cvar_ClampInteger
547 ============
548 */
549 int Cvar_ClampInteger(cvar_t *var, int min, int max)
550 {
551  char val[32];
552 
553  if (var->integer < min) {
554  Q_snprintf(val, sizeof(val), "%i", min);
555  Cvar_SetByVar(var, val, FROM_CODE);
556  return min;
557  }
558  if (var->integer > max) {
559  Q_snprintf(val, sizeof(val), "%i", max);
560  Cvar_SetByVar(var, val, FROM_CODE);
561  return max;
562  }
563  return var->integer;
564 }
565 
566 /*
567 ============
568 Cvar_ClampValue
569 ============
570 */
571 float Cvar_ClampValue(cvar_t *var, float min, float max)
572 {
573  char val[32];
574 
575  if (var->value < min) {
576  if (min == (int)min) {
577  Q_snprintf(val, sizeof(val), "%i", (int)min);
578  } else {
579  Q_snprintf(val, sizeof(val), "%f", min);
580  }
581  Cvar_SetByVar(var, val, FROM_CODE);
582  return min;
583  }
584  if (var->value > max) {
585  if (max == (int)max) {
586  Q_snprintf(val, sizeof(val), "%i", (int)max);
587  } else {
588  Q_snprintf(val, sizeof(val), "%f", max);
589  }
590  Cvar_SetByVar(var, val, FROM_CODE);
591  return max;
592  }
593  return var->value;
594 }
595 
596 /*
597 ==================
598 Cvar_FixCheats
599 ==================
600 */
601 void Cvar_FixCheats(void)
602 {
603  cvar_t *var;
604 
605  if (CL_CheatsOK()) {
606  return;
607  }
608 
609  // fix any cheating cvars
610  for (var = cvar_vars; var; var = var->next) {
611  if (var->flags & CVAR_CHEAT) {
612  Cvar_SetByVar(var, var->default_string, FROM_CODE);
613  if (var->changed)
614  var->changed(var);
615  }
616  }
617 }
618 
619 /*
620 ============
621 Cvar_GetLatchedVars
622 
623 Any variables with latched values will now be updated
624 ============
625 */
627 {
628  cvar_t *var;
629 
630  for (var = cvar_vars; var; var = var->next) {
631  if (var->flags & CVAR_GAME)
632  var->flags &= ~CVAR_SERVERINFO;
633  if (!(var->flags & CVAR_LATCH))
634  continue;
635  if (!var->latched_string)
636  continue;
637  Z_Free(var->string);
638  var->string = var->latched_string;
639  var->latched_string = NULL;
640  parse_string_value(var);
641  var->modified = qtrue;
642  cvar_modified |= var->flags & CVAR_MODIFYMASK;
643  if (var->changed) {
644  var->changed(var);
645  }
646  }
647 }
648 
650 {
651  cvar_t *var;
652  int total = 0;
653 
654  for (var = cvar_vars; var; var = var->next) {
655  if (!(var->flags & CVAR_LATCH))
656  continue;
657  if (!var->latched_string)
658  continue;
659  total++;
660  }
661 
662  return total;
663 }
664 
665 /*
666 ============
667 Cvar_Command
668 
669 Handles variable inspection and changing from the console
670 ============
671 */
672 void Cvar_Command(cvar_t *v)
673 {
674 // perform a variable print or set
675  if (Cmd_Argc() < 2) {
676  Com_Printf("\"%s\" is \"%s\"", v->name, v->string);
677  if (strcmp(v->string, v->default_string)) {
678  Com_Printf(" default: \"%s\"", v->default_string);
679  }
680  if (v->latched_string && strcmp(v->latched_string, v->string)) {
681  Com_Printf(" latched: \"%s\"", v->latched_string);
682  }
683  Com_Printf("\n");
684  } else {
686  }
687 }
688 
689 static void Cvar_Set_c(genctx_t *ctx, int argnum)
690 {
691  char *s;
692  cvar_t *var;
693  xgenerator_t g;
694 
695  if (argnum == 1) {
696  Cvar_Variable_g(ctx);
697  } else if (argnum == 2) {
698  s = Cmd_Argv(ctx->argnum - 1);
699  if ((var = Cvar_FindVar(s)) != NULL) {
700  g = var->generator;
701  if (g) {
702  ctx->data = var;
703  g(ctx);
704  }
705  }
706  }
707 }
708 
709 
710 /*
711 ============
712 Cvar_Set_f
713 
714 Allows setting and defining of arbitrary cvars from console
715 ============
716 */
717 void Cvar_Set_f(void)
718 {
719  int c, flags;
720  char *f;
721 
722  c = Cmd_Argc();
723  if (c < 3) {
724  Com_Printf("Usage: set <variable> <value> [u / s]\n");
725  return;
726  }
727 
728  if (c == 3) {
730  return;
731  }
732 
733  if (c == 4) {
734  f = Cmd_Argv(3);
735  if (!strcmp(f, "u")) {
736  flags = CVAR_USERINFO;
737  } else if (!strcmp(f, "s")) {
738  flags = CVAR_SERVERINFO;
739  } else {
740  goto set;
741  }
742  Cvar_FullSet(Cmd_Argv(1), Cmd_Argv(2), flags, Cmd_From());
743  return;
744  }
745 
746 set:
748 }
749 
750 /*
751 ============
752 Cvar_SetFlag_f
753 
754 Allows setting and defining of arbitrary cvars from console
755 ============
756 */
757 static void Cvar_SetFlag_f(void)
758 {
759  char *s = Cmd_Argv(0);
760  int flags;
761 
762  if (Cmd_Argc() < 3) {
763  Com_Printf("Usage: %s <variable> <value>\n", s);
764  return;
765  }
766 
767  if (!strcmp(s, "seta")) {
768  cvar_t *var = Cvar_SetEx(Cmd_Argv(1), Cmd_ArgsFrom(2), Cmd_From());
769  if (var && !(var->flags & CVAR_NOARCHIVEMASK))
770  var->flags |= CVAR_ARCHIVE;
771  return;
772  }
773 
774  if (!strcmp(s, "setu")) {
775  flags = CVAR_USERINFO;
776  } else if (!strcmp(s, "sets")) {
777  flags = CVAR_SERVERINFO;
778  } else {
779  return;
780  }
781 
782  Cvar_FullSet(Cmd_Argv(1), Cmd_ArgsFrom(2), flags, Cmd_From());
783 }
784 
785 #if USE_CLIENT
786 
787 /*
788 ============
789 Cvar_WriteVariables
790 
791 Appends lines containing "set variable value" for all variables
792 with the archive flag set to true.
793 ============
794 */
795 void Cvar_WriteVariables(qhandle_t f, int mask, qboolean modified)
796 {
797  cvar_t *var;
798  char *s, *a;
799 
800  for (var = cvar_vars; var; var = var->next) {
801  if (var->flags & CVAR_NOARCHIVEMASK)
802  continue;
803  if (!(var->flags & mask))
804  continue;
805 
806  s = var->latched_string ? var->latched_string : var->string;
807  if (modified && !strcmp(s, var->default_string))
808  continue;
809 
810  a = !modified && (var->flags & CVAR_ARCHIVE) ? "a" : "";
811  FS_FPrintf(f, "set%s %s \"%s\"\n", a, var->name, s);
812  }
813 }
814 
815 #endif
816 
817 /*
818 ============
819 Cvar_List_f
820 
821 ============
822 */
823 
824 static const cmd_option_t o_cvarlist[] = {
825  { "a", "archive", "list archived cvars" },
826  { "c", "cheat", "list cheat protected cvars" },
827  { "h", "help", "display this help message" },
828  { "l", "latched", "list latched cvars" },
829  { "m", "modified", "list modified cvars" },
830  { "n", "noset", "list command line cvars" },
831  { "r", "rom", "list read-only cvars" },
832  { "s", "serverinfo", "list serverinfo cvars" },
833  { "t", "custom", "list user-created cvars" },
834  { "u", "userinfo", "list userinfo cvars" },
835  { "v", "verbose", "display flags of each cvar" },
836  { "w:string", "wildcard", "list cvars matching wildcard" },
837  { NULL }
838 };
839 
840 static void Cvar_List_c(genctx_t *ctx, int argnum)
841 {
842  Cmd_Option_c(o_cvarlist, NULL, ctx, argnum);
843 }
844 
845 static void Cvar_List_f(void)
846 {
847  cvar_t *var;
848  int i, total;
849  qboolean verbose = qfalse, modified = qfalse, latched = qfalse;
850  int mask = 0;
851  char *wildcard = NULL;
852  char buffer[5];
853  int c;
854 
855  while ((c = Cmd_ParseOptions(o_cvarlist)) != -1) {
856  switch (c) {
857  case 'a':
858  mask |= CVAR_ARCHIVE;
859  break;
860  case 'c':
861  mask |= CVAR_CHEAT;
862  break;
863  case 'h':
864  Cmd_PrintUsage(o_cvarlist, NULL);
865  Com_Printf("List registered console variables.\n");
867  Com_Printf(
868  "Flags legend:\n"
869  "C: cheat protected\n"
870  "A: archived in config file\n"
871  "U: included in userinfo\n"
872  "S: included in serverinfo\n"
873  "N: set from command line only\n"
874  "R: read-only variable\n"
875  "L: latched\n"
876  "?: created by user\n");
877  return;
878  case 'l':
879  latched = qtrue;
880  break;
881  case 'm':
882  modified = qtrue;
883  break;
884  case 'n':
885  mask |= CVAR_NOSET;
886  break;
887  case 'r':
888  mask |= CVAR_ROM;
889  break;
890  case 's':
891  mask |= CVAR_SERVERINFO;
892  break;
893  case 't':
894  mask |= CVAR_CUSTOM;
895  break;
896  case 'u':
897  mask |= CVAR_USERINFO;
898  break;
899  case 'v':
900  verbose = qtrue;
901  break;
902  case 'w':
903  wildcard = cmd_optarg;
904  break;
905  default:
906  return;
907  }
908  }
909 
910  buffer[sizeof(buffer) - 1] = 0;
911  i = 0;
912  for (var = cvar_vars, total = 0; var; var = var->next, total++) {
913  if (latched && !var->latched_string) {
914  continue;
915  }
916  if (mask && !(var->flags & mask)) {
917  continue;
918  }
919  if (wildcard && !Com_WildCmp(wildcard, var->name)) {
920  continue;
921  }
922  if (modified && (!strcmp(var->latched_string ? var->latched_string :
923  var->string, var->default_string) || (var->flags & CVAR_ROM))) {
924  continue;
925  }
926 
927  if (verbose) {
928  memset(buffer, '-', sizeof(buffer) - 1);
929 
930  if (var->flags & CVAR_CHEAT)
931  buffer[0] = 'C';
932  else if (var->flags & CVAR_ARCHIVE)
933  buffer[0] = 'A';
934 
935  if (var->flags & CVAR_USERINFO)
936  buffer[1] = 'U';
937 
938  if (var->flags & CVAR_SERVERINFO)
939  buffer[2] = 'S';
940 
941  if (var->flags & CVAR_ROM)
942  buffer[3] = 'R';
943  else if (var->flags & CVAR_NOSET)
944  buffer[3] = 'N';
945  else if (var->flags & CVAR_LATCH)
946  buffer[3] = 'L';
947  else if (var->flags & CVAR_CUSTOM)
948  buffer[3] = '?';
949 
950  Com_Printf("%s ", buffer);
951  }
952 
953  Com_Printf("%s \"%s\"\n", var->name, var->string);
954 
955  i++;
956  }
957  Com_Printf("%i of %i cvars\n", i, total);
958 }
959 
960 /*
961 ============
962 Cvar_Toggle_f
963 ============
964 */
965 static void Cvar_Toggle_f(void)
966 {
967  cvar_t *var;
968  int i, argc = Cmd_Argc();
969 
970  if (argc < 2) {
971  Com_Printf("Usage: %s <variable> [values]\n", Cmd_Argv(0));
972  return;
973  }
974 
975  var = Cvar_FindVar(Cmd_Argv(1));
976  if (!var) {
977  Com_Printf("%s is not a variable\n", Cmd_Argv(1));
978  return;
979  }
980 
981  if (argc < 3) {
982  if (!strcmp(var->string, "0")) {
983  Cvar_SetByVar(var, "1", Cmd_From());
984  } else if (!strcmp(var->string, "1")) {
985  Cvar_SetByVar(var, "0", Cmd_From());
986  } else {
987  Com_Printf("\"%s\" is \"%s\", can't toggle\n",
988  var->name, var->string);
989  }
990  return;
991  }
992 
993  for (i = 0; i < argc - 2; i++) {
994  if (!Q_stricmp(var->string, Cmd_Argv(2 + i))) {
995  i = (i + 1) % (argc - 2);
996  Cvar_SetByVar(var, Cmd_Argv(2 + i), Cmd_From());
997  return;
998  }
999  }
1000 
1001  Com_Printf("\"%s\" is \"%s\", can't cycle\n", var->name, var->string);
1002 }
1003 
1004 static void Cvar_Toggle_c(genctx_t *ctx, int argnum)
1005 {
1006  char *s;
1007  xgenerator_t g;
1008 
1009  if (argnum == 1) {
1010  Cvar_Variable_g(ctx);
1011  } else {
1012  s = Cmd_Argv(ctx->argnum - argnum + 1);
1013  if ((g = Cvar_FindGenerator(s)) != NULL) {
1014  g(ctx);
1015  }
1016  }
1017 }
1018 
1019 /*
1020 ============
1021 Cvar_Inc_f
1022 ============
1023 */
1024 static void Cvar_Inc_f(void)
1025 {
1026  cvar_t *var;
1027  float value;
1028  char val[32];
1029 
1030  if (Cmd_Argc() < 2) {
1031  Com_Printf("Usage: %s <variable> [value]\n", Cmd_Argv(0));
1032  return;
1033  }
1034 
1035  var = Cvar_FindVar(Cmd_Argv(1));
1036  if (!var) {
1037  Com_Printf("%s is not a variable\n", Cmd_Argv(1));
1038  return;
1039  }
1040 
1041  if (!COM_IsFloat(var->string)) {
1042  Com_Printf("\"%s\" is \"%s\", can't %s\n",
1043  var->name, var->string, Cmd_Argv(0));
1044  return;
1045  }
1046 
1047  value = 1;
1048  if (Cmd_Argc() > 2) {
1049  value = atof(Cmd_Argv(2));
1050  }
1051  if (!strcmp(Cmd_Argv(0), "dec")) {
1052  value = -value;
1053  }
1054  value += var->value;
1055 
1056  if (value == (int)value)
1057  Q_snprintf(val, sizeof(val), "%i", (int)value);
1058  else
1059  Q_snprintf(val, sizeof(val), "%f", value);
1060 
1061  Cvar_SetByVar(var, val, Cmd_From());
1062 }
1063 
1064 /*
1065 ============
1066 Cvar_Reset_f
1067 ============
1068 */
1069 static void Cvar_Reset_f(void)
1070 {
1071  cvar_t *var;
1072 
1073  if (Cmd_Argc() < 2) {
1074  Com_Printf("Usage: %s <variable>\n", Cmd_Argv(0));
1075  return;
1076  }
1077 
1078  var = Cvar_FindVar(Cmd_Argv(1));
1079  if (!var) {
1080  Com_Printf("%s is not a variable\n", Cmd_Argv(1));
1081  return;
1082  }
1083 
1084  Cvar_SetByVar(var, var->default_string, Cmd_From());
1085 }
1086 
1087 static void Cvar_Reset_c(genctx_t *ctx, int argnum)
1088 {
1089  if (argnum == 1) {
1090  Cvar_Variable_g(ctx);
1091  }
1092 }
1093 
1094 static void Cvar_ResetAll_f(void)
1095 {
1096  cvar_t *var;
1097 
1098  for (var = cvar_vars; var; var = var->next) {
1099  if (var->flags & CVAR_ROM)
1100  continue;
1101  if ((var->flags & CVAR_NOSET) && com_initialized)
1102  continue;
1103  if (var == fs_game)
1104  continue;
1105  Cvar_SetByVar(var, var->default_string, Cmd_From());
1106  }
1107 }
1108 
1109 size_t Cvar_BitInfo(char *info, int bit)
1110 {
1111  char newi[MAX_INFO_STRING], *v;
1112  cvar_t *var;
1113  size_t len, total = 0;
1114  int c;
1115 
1116  for (var = cvar_vars; var; var = var->next) {
1117  if (!(var->flags & bit)) {
1118  continue;
1119  }
1120  if (var->flags & CVAR_PRIVATE) {
1121  continue;
1122  }
1123  if (!var->string[0]) {
1124  continue;
1125  }
1126  len = Q_concat(newi, sizeof(newi),
1127  "\\", var->name, "\\", var->string, NULL);
1128  if (len >= sizeof(newi)) {
1129  continue;
1130  }
1131  if (total + len >= MAX_INFO_STRING) {
1132  break;
1133  }
1134 
1135  // only copy ascii values
1136  v = newi;
1137  while (*v) {
1138  c = *v++;
1139  c &= 127; // strip high bits
1140  if (Q_isprint(c))
1141  info[total++] = c;
1142  }
1143  }
1144 
1145  info[total] = 0;
1146  return total;
1147 }
1148 
1149 static const cmdreg_t c_cvar[] = {
1150  { "set", Cvar_Set_f, Cvar_Set_c },
1151  { "setu", Cvar_SetFlag_f, Cvar_Set_c },
1152  { "sets", Cvar_SetFlag_f, Cvar_Set_c },
1153  { "seta", Cvar_SetFlag_f, Cvar_Set_c },
1154  { "cvarlist", Cvar_List_f, Cvar_List_c },
1155  { "toggle", Cvar_Toggle_f, Cvar_Toggle_c },
1156  { "inc", Cvar_Inc_f, Cvar_Reset_c },
1157  { "dec", Cvar_Inc_f, Cvar_Reset_c },
1158  { "reset", Cvar_Reset_f, Cvar_Reset_c },
1159  { "resetall", Cvar_ResetAll_f },
1160 
1161  { NULL }
1162 };
1163 
1164 /*
1165 ============
1166 Cvar_Init
1167 ============
1168 */
1169 void Cvar_Init(void)
1170 {
1172 }
1173 
cvarHash
static cvar_t * cvarHash[CVARHASH_SIZE]
Definition: cvar.c:38
COM_IsFloat
qboolean COM_IsFloat(const char *s)
Definition: shared.c:307
cvar_vars
cvar_t * cvar_vars
Definition: cvar.c:30
Cvar_Set
cvar_t * Cvar_Set(const char *var_name, const char *value)
Definition: cvar.c:466
Z_CvarCopyString
char * Z_CvarCopyString(const char *in)
Definition: zone.c:419
com_initialized
qboolean com_initialized
Definition: common.c:124
cvar_modified
int cvar_modified
Definition: cvar.c:32
cmd_optarg
char * cmd_optarg
Definition: cmd.c:848
change_string_value
static void change_string_value(cvar_t *var, const char *value, from_t from)
Definition: cvar.c:173
Cvar_BitInfo
size_t Cvar_BitInfo(char *info, int bit)
Definition: cvar.c:1109
o_cvarlist
static const cmd_option_t o_cvarlist[]
Definition: cvar.c:824
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
CVARHASH_SIZE
#define CVARHASH_SIZE
Definition: cvar.c:36
Cvar_Default_g
void Cvar_Default_g(genctx_t *ctx)
Definition: cvar.c:144
get_engine_cvar
static void get_engine_cvar(cvar_t *var, const char *var_value, int flags)
Definition: cvar.c:219
Cvar_Reset_c
static void Cvar_Reset_c(genctx_t *ctx, int argnum)
Definition: cvar.c:1087
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
Com_HashString
unsigned Com_HashString(const char *s, unsigned size)
Definition: utils.c:339
parse_string_value
static void parse_string_value(cvar_t *var)
Definition: cvar.c:157
Cvar_List_f
static void Cvar_List_f(void)
Definition: cvar.c:845
FS_FPrintf
ssize_t FS_FPrintf(qhandle_t f, const char *format,...)
Definition: files.c:2039
Cmd_From
from_t Cmd_From(void)
Definition: cmd.c:851
Cvar_Toggle_f
static void Cvar_Toggle_f(void)
Definition: cvar.c:965
Cmd_PrintUsage
void Cmd_PrintUsage(const cmd_option_t *opt, const char *suffix)
Definition: cmd.c:1143
Cvar_CountLatchedVars
int Cvar_CountLatchedVars(void)
Definition: cvar.c:649
Cvar_Inc_f
static void Cvar_Inc_f(void)
Definition: cvar.c:1024
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
Cvar_Reset_f
static void Cvar_Reset_f(void)
Definition: cvar.c:1069
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
Prompt_AddMatch
qboolean Prompt_AddMatch(genctx_t *ctx, const char *s)
Definition: prompt.c:149
Cvar_FindGenerator
xgenerator_t Cvar_FindGenerator(const char *var_name)
Definition: cvar.c:61
Cvar_Exists
qboolean Cvar_Exists(const char *var_name, qboolean weak)
Definition: cvar.c:73
Cmd_ArgsFrom
char * Cmd_ArgsFrom(int from)
Definition: cmd.c:981
Cvar_Variable_g
void Cvar_Variable_g(genctx_t *ctx)
Definition: cvar.c:133
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
Cmd_ParseOptions
int Cmd_ParseOptions(const cmd_option_t *opt)
Definition: cmd.c:1057
Cvar_Toggle_c
static void Cvar_Toggle_c(genctx_t *ctx, int argnum)
Definition: cvar.c:1004
set_back_cvar
static void set_back_cvar(cvar_t *var)
Definition: cvar.c:329
Cvar_ClampValue
float Cvar_ClampValue(cvar_t *var, float min, float max)
Definition: cvar.c:571
Cvar_SetValue
void Cvar_SetValue(cvar_t *var, float value, from_t from)
Definition: cvar.c:487
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
Cmd_Register
void Cmd_Register(const cmdreg_t *reg)
Definition: cmd.c:1572
fs_game
cvar_t * fs_game
Definition: files.c:202
Cvar_VariableInteger
int Cvar_VariableInteger(const char *var_name)
Definition: cvar.c:105
Cvar_Malloc
#define Cvar_Malloc(size)
Definition: cvar.c:34
Cvar_SetByVar
void Cvar_SetByVar(cvar_t *var, const char *value, from_t from)
Definition: cvar.c:345
Cvar_SetInteger
void Cvar_SetInteger(cvar_t *var, int value, from_t from)
Definition: cvar.c:509
Cvar_SetFlag_f
static void Cvar_SetFlag_f(void)
Definition: cvar.c:757
Cvar_FullSet
cvar_t * Cvar_FullSet(const char *var_name, const char *value, int flags, from_t from)
Definition: cvar.c:437
CL_CheatsOK
qboolean CL_CheatsOK(void)
Definition: main.c:2871
Cvar_UserSet
cvar_t * Cvar_UserSet(const char *var_name, const char *value)
Definition: cvar.c:476
Cvar_WeakGet
cvar_t * Cvar_WeakGet(const char *var_name)
Definition: cvar.c:324
Cvar_ResetAll_f
static void Cvar_ResetAll_f(void)
Definition: cvar.c:1094
c
statCounters_t c
Definition: main.c:30
c_cvar
static const cmdreg_t c_cvar[]
Definition: cvar.c:1149
Cvar_Init
void Cvar_Init(void)
Definition: cvar.c:1169
Cvar_Command
void Cvar_Command(cvar_t *v)
Definition: cvar.c:672
Cvar_FixCheats
void Cvar_FixCheats(void)
Definition: cvar.c:601
Cvar_ClampInteger
int Cvar_ClampInteger(cvar_t *var, int min, int max)
Definition: cvar.c:549
Cvar_Set_f
void Cvar_Set_f(void)
Definition: cvar.c:717
Cvar_GetLatchedVars
void Cvar_GetLatchedVars(void)
Definition: cvar.c:626
client.h
Cmd_PrintHelp
void Cmd_PrintHelp(const cmd_option_t *opt)
Definition: cmd.c:1160
Cmd_Option_c
void Cmd_Option_c(const cmd_option_t *opt, xgenerator_t g, genctx_t *ctx, int argnum)
Definition: cmd.c:1183
Cvar_Set_c
static void Cvar_Set_c(genctx_t *ctx, int argnum)
Definition: cvar.c:689
sv_running
cvar_t * sv_running
Definition: common.c:95
Cvar_FindVar
cvar_t * Cvar_FindVar(const char *var_name)
Definition: cvar.c:45
Cvar_VariableString
char * Cvar_VariableString(const char *var_name)
Definition: cvar.c:122
Cvar_SetEx
cvar_t * Cvar_SetEx(const char *var_name, const char *value, from_t from)
Definition: cvar.c:417
Q_concat
size_t Q_concat(char *dest, size_t size,...)
Definition: shared.c:758
Cvar_VariableValue
float Cvar_VariableValue(const char *var_name)
Definition: cvar.c:89
Cvar_List_c
static void Cvar_List_c(genctx_t *ctx, int argnum)
Definition: cvar.c:840
CL_UpdateUserinfo
void CL_UpdateUserinfo(cvar_t *var, from_t from)
Definition: main.c:1650
validate_info_cvar
static qboolean validate_info_cvar(const char *s)
Definition: cvar.c:198
Info_SubValidate
size_t Info_SubValidate(const char *s)
Definition: shared.c:1112