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 */
Cvar_InfoValidate(char * s)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 */
Cvar_FindVar(char * var_name)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 */
Cvar_VariableValue(char * var_name)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 */
Cvar_VariableString(char * var_name)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 */
Cvar_CompleteVariable(char * partial)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 */
Cvar_Get(char * var_name,char * var_value,int flags)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 
145 		Z_Free(var->default_string);
146 		var->default_string = CopyString (var_value);
147 
148 		return var;
149 	}
150 
151 	if (!var_value)
152 		return NULL;
153 
154 	if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
155 	{
156 		if (!Cvar_InfoValidate (var_value))
157 		{
158 			Com_Printf("invalid info cvar value\n");
159 			return NULL;
160 		}
161 	}
162 
163 	var = Z_Malloc (sizeof(*var));
164 	var->name = CopyString (var_name);
165 	var->string = CopyString (var_value);
166 	var->default_string = CopyString (var_value);
167 	var->modified = true;
168 	var->value = atof (var->string);
169 
170 	// link the variable in
171 	var->next = cvar_vars;
172 	cvar_vars = var;
173 
174 	var->flags = flags;
175 
176 	return var;
177 }
178 
179 /*
180 ============
181 Cvar_Set2
182 ============
183 */
Cvar_Set2(char * var_name,char * value,qboolean force)184 cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force)
185 {
186 	cvar_t	*var;
187 
188 	var = Cvar_FindVar (var_name);
189 	if (!var)
190 	{	// create it
191 		return Cvar_Get (var_name, value, 0);
192 	}
193 
194 	if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO))
195 	{
196 		if (!Cvar_InfoValidate (value))
197 		{
198 			Com_Printf("invalid info cvar value\n");
199 			return var;
200 		}
201 	}
202 
203 	if (!force)
204 	{
205 		if (var->flags & CVAR_NOSET)
206 		{
207 			Com_Printf ("%s is write protected.\n", var_name);
208 			return var;
209 		}
210 
211 		if (var->flags & CVAR_LATCH)
212 		{
213 			if (var->latched_string)
214 			{
215 				if (strcmp(value, var->latched_string) == 0)
216 					return var;
217 				Z_Free (var->latched_string);
218 			}
219 			else
220 			{
221 				if (strcmp(value, var->string) == 0)
222 					return var;
223 			}
224 
225 			if (Com_ServerState())
226 			{
227 				Com_Printf ("%s will be changed for next game.\n", var_name);
228 				var->latched_string = CopyString(value);
229 			}
230 			else
231 			{
232 				var->string = CopyString(value);
233 				var->value = atof (var->string);
234 				if (!strcmp(var->name, "game"))
235 				{
236 					FS_SetGamedir (var->string);
237 					FS_ExecAutoexec ();
238 				}
239 			}
240 			return var;
241 		}
242 	}
243 	else
244 	{
245 		if (var->latched_string)
246 		{
247 			Z_Free (var->latched_string);
248 			var->latched_string = NULL;
249 		}
250 	}
251 
252 	if (!strcmp(value, var->string))
253 		return var;		// not changed
254 
255 	var->modified = true;
256 
257 	if (var->flags & CVAR_USERINFO)
258 		userinfo_modified = true;	// transmit at next oportunity
259 
260 	Z_Free (var->string);	// free the old value string
261 
262 	var->string = CopyString(value);
263 	var->value = atof (var->string);
264 
265 	return var;
266 }
267 
268 /*
269 ============
270 Cvar_ForceSet
271 ============
272 */
Cvar_ForceSet(char * var_name,char * value)273 cvar_t *Cvar_ForceSet (char *var_name, char *value)
274 {
275 	return Cvar_Set2 (var_name, value, true);
276 }
277 
278 /*
279 ============
280 Cvar_Set
281 ============
282 */
Cvar_Set(char * var_name,char * value)283 cvar_t *Cvar_Set (char *var_name, char *value)
284 {
285 	return Cvar_Set2 (var_name, value, false);
286 }
287 
288 /*
289 ============
290 Cvar_FullSet
291 ============
292 */
Cvar_FullSet(char * var_name,char * value,int flags)293 cvar_t *Cvar_FullSet (char *var_name, char *value, int flags)
294 {
295 	cvar_t	*var;
296 
297 	var = Cvar_FindVar (var_name);
298 	if (!var)
299 	{	// create it
300 		return Cvar_Get (var_name, value, flags);
301 	}
302 
303 	var->modified = true;
304 
305 	if (var->flags & CVAR_USERINFO)
306 		userinfo_modified = true;	// transmit at next oportunity
307 
308 	Z_Free (var->string);	// free the old value string
309 
310 	var->string = CopyString(value);
311 	var->value = atof (var->string);
312 	var->flags = flags;
313 
314 	return var;
315 }
316 
317 /*
318 ============
319 Cvar_SetValue
320 ============
321 */
Cvar_SetValue(char * var_name,float value)322 void Cvar_SetValue (char *var_name, float value)
323 {
324 	char	val[32];
325 
326 	if (value == (int)value)
327 		Com_sprintf (val, sizeof(val), "%i",(int)value);
328 	else
329 		Com_sprintf (val, sizeof(val), "%f",value);
330 	Cvar_Set (var_name, val);
331 }
332 
333 
334 /*
335 ============
336 Cvar_GetLatchedVars
337 
338 Any variables with latched values will now be updated
339 ============
340 */
Cvar_GetLatchedVars(void)341 void Cvar_GetLatchedVars (void)
342 {
343 	cvar_t	*var;
344 
345 	for (var = cvar_vars ; var ; var = var->next)
346 	{
347 		if (!var->latched_string)
348 			continue;
349 		Z_Free (var->string);
350 		var->string = var->latched_string;
351 		var->latched_string = NULL;
352 		var->value = atof(var->string);
353 		if (!strcmp(var->name, "game"))
354 		{
355 			FS_SetGamedir (var->string);
356 			FS_ExecAutoexec ();
357 		}
358 	}
359 }
360 
361 /*
362 ============
363 Cvar_Command
364 
365 Handles variable inspection and changing from the console
366 ============
367 */
Cvar_Command(void)368 qboolean Cvar_Command (void)
369 {
370 	cvar_t			*v;
371 
372 // check variables
373 	v = Cvar_FindVar (Cmd_Argv(0));
374 	if (!v)
375 		return false;
376 
377 // perform a variable print or set
378 	if (Cmd_Argc() == 1)
379 	{
380 		Com_Printf ("\"%s\" is \"%s\" : default is \"%s\"\n", v->name, v->string, v->default_string);
381 		return true;
382 	}
383 
384 	Cvar_Set (v->name, Cmd_Argv(1));
385 	return true;
386 }
387 
388 
389 /*
390 ============
391 Cvar_Set_f
392 
393 Allows setting and defining of arbitrary cvars from console
394 ============
395 */
Cvar_Set_f(void)396 void Cvar_Set_f (void)
397 {
398 	int		c;
399 	int		flags;
400 
401 	c = Cmd_Argc();
402 	if (c != 3 && c != 4)
403 	{
404 		Com_Printf ("usage: set <variable> <value> [u / s]\n");
405 		return;
406 	}
407 
408 	if (c == 4)
409 	{
410 		if (!strcmp(Cmd_Argv(3), "u"))
411 			flags = CVAR_USERINFO;
412 		else if (!strcmp(Cmd_Argv(3), "s"))
413 			flags = CVAR_SERVERINFO;
414 		else
415 		{
416 			Com_Printf ("flags can only be 'u' or 's'\n");
417 			return;
418 		}
419 		Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags);
420 	}
421 	else
422 		Cvar_Set (Cmd_Argv(1), Cmd_Argv(2));
423 }
424 
425 
426 /*
427 ============
428 Cvar_WriteVariables
429 
430 Appends lines containing "set variable value" for all variables
431 with the archive flag set to true.
432 ============
433 */
Cvar_WriteVariables(char * path)434 void Cvar_WriteVariables (char *path)
435 {
436 	cvar_t	*var;
437 	char	buffer[1024];
438 	FILE	*f;
439 
440 	f = fopen (path, "a");
441 	for (var = cvar_vars ; var ; var = var->next)
442 	{
443 		if (var->flags & CVAR_ARCHIVE)
444 		{
445 			Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string);
446 			fprintf (f, "%s", buffer);
447 		}
448 	}
449 	fclose (f);
450 }
451 
452 
453 /*
454 ============
455 Cvar_WriteUserVariables
456 
457 Appends lines containing "set variable value" for all variables
458 with the archive flag set to true.
459 ============
460 */
Cvar_WriteUserVariables(char * path)461 void Cvar_WriteUserVariables (char *path)
462 {
463 	cvar_t	*var;
464 	char	buffer[1024];
465 	FILE	*f;
466 
467 	f = fopen (path, "a");
468 	for (var = cvar_vars ; var ; var = var->next)
469 	{
470 		if (var->flags & CVAR_USERVARS)
471 		{
472 			//set one as var, and one as game command
473 
474 			Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string);
475 			fprintf (f, "%s", buffer);
476 			Com_sprintf (buffer, sizeof(buffer), "%s %s\n", var->name, var->string);
477 			fprintf (f, "%s", buffer);
478 		}
479 	}
480 	fclose (f);
481 }
482 
483 /*
484 ============
485 Cvar_List_f
486 
487 ============
488 */
Cvar_List_f(void)489 void Cvar_List_f (void)
490 {
491 	cvar_t	*var;
492 	int		i, c;
493 
494 	c = Cmd_Argc();
495 	i = 0;
496 	for (var = cvar_vars ; var ; var = var->next)
497 	{
498 		if (c>1)
499 			if (!strstr (var->name, Cmd_Argv(1)))
500 				continue;
501 
502 		if (var->flags & CVAR_ARCHIVE)
503 			Com_Printf ("*");
504 		else
505 			Com_Printf (" ");
506 		if (var->flags & CVAR_USERINFO)
507 			Com_Printf ("U");
508 		else
509 			Com_Printf (" ");
510 		if (var->flags & CVAR_SERVERINFO)
511 			Com_Printf ("S");
512 		else
513 			Com_Printf (" ");
514 		if (var->flags & CVAR_NOSET)
515 			Com_Printf ("-");
516 		else if (var->flags & CVAR_LATCH)
517 			Com_Printf ("L");
518 		else
519 			Com_Printf (" ");
520 
521 		Com_Printf ("\"%s\" \"%s\" - default: \"%s\"\n", var->name, var->string, var->default_string);
522 		//Com_Printf (" %s \"%s\"\n", var->name, var->string);
523 
524 		i++;
525 	}
526 	Com_Printf ("%i cvars\n", i);
527 }
528 
529 
530 qboolean userinfo_modified;
531 
532 
Cvar_BitInfo(int bit)533 char	*Cvar_BitInfo (int bit)
534 {
535 	static char	info[MAX_INFO_STRING];
536 	cvar_t	*var;
537 
538 	info[0] = 0;
539 
540 	for (var = cvar_vars ; var ; var = var->next)
541 	{
542 		if (var->flags & bit)
543 			Info_SetValueForKey (info, var->name, var->string);
544 	}
545 	return info;
546 }
547 
548 // returns an info string containing all the CVAR_USERINFO cvars
Cvar_Userinfo(void)549 char	*Cvar_Userinfo (void)
550 {
551 	return Cvar_BitInfo (CVAR_USERINFO);
552 }
553 
554 // returns an info string containing all the CVAR_SERVERINFO cvars
Cvar_Serverinfo(void)555 char	*Cvar_Serverinfo (void)
556 {
557 	return Cvar_BitInfo (CVAR_SERVERINFO);
558 }
559 
560 /*
561 ============
562 Cvar_Init
563 
564 Reads in all archived cvars
565 ============
566 */
Cvar_Init(void)567 void Cvar_Init (void)
568 {
569 	Cmd_AddCommand ("set", Cvar_Set_f);
570 	Cmd_AddCommand ("cvarlist", Cvar_List_f);
571 
572 }
573