File: qcommon\cvar.c
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 }
528