]> icculus.org git repositories - divverent/darkplaces.git/blob - cvar.c
fix a very stupid bug in Mod_AllocSurfMesh that causes memory corruption
[divverent/darkplaces.git] / cvar.c
1 /*
2 Copyright (C) 1996-1997 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 "quakedef.h"
23
24 cvar_t *cvar_vars = NULL;
25 char *cvar_null_string = "";
26
27 /*
28 ============
29 Cvar_FindVar
30 ============
31 */
32 cvar_t *Cvar_FindVar (const char *var_name)
33 {
34         cvar_t *var;
35
36         for (var = cvar_vars;var;var = var->next)
37                 if (!strcasecmp (var_name, var->name))
38                         return var;
39
40         return NULL;
41 }
42
43 cvar_t *Cvar_FindVarAfter (const char *prev_var_name, int neededflags)
44 {
45         cvar_t *var;
46
47         if (*prev_var_name)
48         {
49                 var = Cvar_FindVar (prev_var_name);
50                 if (!var)
51                         return NULL;
52                 var = var->next;
53         }
54         else
55                 var = cvar_vars;
56
57         // search for the next cvar matching the needed flags
58         while (var)
59         {
60                 if ((var->flags & neededflags) || !neededflags)
61                         break;
62                 var = var->next;
63         }
64         return var;
65 }
66
67 /*
68 ============
69 Cvar_VariableValue
70 ============
71 */
72 float Cvar_VariableValue (const char *var_name)
73 {
74         cvar_t *var;
75
76         var = Cvar_FindVar (var_name);
77         if (!var)
78                 return 0;
79         return atof (var->string);
80 }
81
82
83 /*
84 ============
85 Cvar_VariableString
86 ============
87 */
88 const char *Cvar_VariableString (const char *var_name)
89 {
90         cvar_t *var;
91
92         var = Cvar_FindVar (var_name);
93         if (!var)
94                 return cvar_null_string;
95         return var->string;
96 }
97
98 /*
99 ============
100 Cvar_VariableDefString
101 ============
102 */
103 const char *Cvar_VariableDefString (const char *var_name)
104 {
105         cvar_t *var;
106
107         var = Cvar_FindVar (var_name);
108         if (!var)
109                 return cvar_null_string;
110         return var->defstring;
111 }
112
113
114 /*
115 ============
116 Cvar_CompleteVariable
117 ============
118 */
119 const char *Cvar_CompleteVariable (const char *partial)
120 {
121         cvar_t          *cvar;
122         size_t          len;
123
124         len = strlen(partial);
125
126         if (!len)
127                 return NULL;
128
129 // check functions
130         for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
131                 if (!strncasecmp (partial,cvar->name, len))
132                         return cvar->name;
133
134         return NULL;
135 }
136
137
138 /*
139         CVar_CompleteCountPossible
140
141         New function for tab-completion system
142         Added by EvilTypeGuy
143         Thanks to Fett erich@heintz.com
144
145 */
146 int Cvar_CompleteCountPossible (const char *partial)
147 {
148         cvar_t  *cvar;
149         size_t  len;
150         int             h;
151
152         h = 0;
153         len = strlen(partial);
154
155         if (!len)
156                 return  0;
157
158         // Loop through the cvars and count all possible matches
159         for (cvar = cvar_vars; cvar; cvar = cvar->next)
160                 if (!strncasecmp(partial, cvar->name, len))
161                         h++;
162
163         return h;
164 }
165
166 /*
167         CVar_CompleteBuildList
168
169         New function for tab-completion system
170         Added by EvilTypeGuy
171         Thanks to Fett erich@heintz.com
172         Thanks to taniwha
173
174 */
175 const char **Cvar_CompleteBuildList (const char *partial)
176 {
177         const cvar_t *cvar;
178         size_t len = 0;
179         size_t bpos = 0;
180         size_t sizeofbuf = (Cvar_CompleteCountPossible (partial) + 1) * sizeof (const char *);
181         const char **buf;
182
183         len = strlen(partial);
184         buf = Mem_Alloc(tempmempool, sizeofbuf + sizeof (const char *));
185         // Loop through the alias list and print all matches
186         for (cvar = cvar_vars; cvar; cvar = cvar->next)
187                 if (!strncasecmp(partial, cvar->name, len))
188                         buf[bpos++] = cvar->name;
189
190         buf[bpos] = NULL;
191         return buf;
192 }
193
194 /*
195 ============
196 Cvar_Set
197 ============
198 */
199 void Cvar_SetQuick_Internal (cvar_t *var, const char *value)
200 {
201         qboolean changed;
202
203         changed = strcmp(var->string, value);
204         // LordHavoc: don't reallocate when there is no change
205         if (!changed)
206                 return;
207
208         // LordHavoc: don't reallocate when the buffer is the same size
209         if (!var->string || strlen(var->string) != strlen(value))
210         {
211                 Z_Free (var->string);   // free the old value string
212
213                 var->string = Z_Malloc (strlen(value)+1);
214         }
215         strcpy (var->string, value);
216         var->value = atof (var->string);
217         var->integer = (int) var->value;
218         if ((var->flags & CVAR_NOTIFY) && changed && sv.active)
219                 SV_BroadcastPrintf("\"%s\" changed to \"%s\"\n", var->name, var->string);
220 }
221
222 void Cvar_SetQuick (cvar_t *var, const char *value)
223 {
224         if (var == NULL)
225         {
226                 Con_Print("Cvar_SetQuick: var == NULL\n");
227                 return;
228         }
229
230         if (developer.integer)
231                 Con_Printf("Cvar_SetQuick({\"%s\", \"%s\", %i, \"%s\"}, \"%s\");\n", var->name, var->string, var->flags, var->defstring, value);
232
233         Cvar_SetQuick_Internal(var, value);
234 }
235
236 void Cvar_Set (const char *var_name, const char *value)
237 {
238         cvar_t *var;
239         var = Cvar_FindVar (var_name);
240         if (var == NULL)
241         {
242                 Con_Printf("Cvar_Set: variable %s not found\n", var_name);
243                 return;
244         }
245         Cvar_SetQuick(var, value);
246 }
247
248 /*
249 ============
250 Cvar_SetValue
251 ============
252 */
253 void Cvar_SetValueQuick(cvar_t *var, float value)
254 {
255         char val[256];
256
257         if ((float)((int)value) == value)
258                 sprintf(val, "%i", (int)value);
259         else
260                 sprintf(val, "%f", value);
261         Cvar_SetQuick(var, val);
262 }
263
264 void Cvar_SetValue(const char *var_name, float value)
265 {
266         char val[256];
267
268         if ((float)((int)value) == value)
269                 sprintf(val, "%i", (int)value);
270         else
271                 sprintf(val, "%f", value);
272         Cvar_Set(var_name, val);
273 }
274
275 /*
276 ============
277 Cvar_RegisterVariable
278
279 Adds a freestanding variable to the variable list.
280 ============
281 */
282 void Cvar_RegisterVariable (cvar_t *variable)
283 {
284         cvar_t *current, *next, *cvar;
285         char *oldstr;
286
287         if (developer.integer)
288                 Con_Printf("Cvar_RegisterVariable({\"%s\", \"%s\", %i});\n", variable->name, variable->string, variable->flags);
289
290 // first check to see if it has already been defined
291         cvar = Cvar_FindVar (variable->name);
292         if (cvar)
293         {
294                 if (cvar->flags & CVAR_ALLOCATED)
295                 {
296                         if (developer.integer)
297                                 Con_Printf("...  replacing existing allocated cvar {\"%s\", \"%s\", %i}", cvar->name, cvar->string, cvar->flags);
298                         // fixed variables replace allocated ones
299                         // (because the engine directly accesses fixed variables)
300                         // NOTE: this isn't actually used currently
301                         // (all cvars are registered before config parsing)
302                         variable->flags |= (cvar->flags & ~CVAR_ALLOCATED);
303                         // cvar->string is now owned by variable instead
304                         variable->string = cvar->string;
305                         variable->defstring = cvar->defstring;
306                         variable->value = atof (variable->string);
307                         variable->integer = (int) variable->value;
308                         // replace cvar with this one...
309                         variable->next = cvar->next;
310                         if (cvar_vars == cvar)
311                         {
312                                 // head of the list is easy to change
313                                 cvar_vars = variable;
314                         }
315                         else
316                         {
317                                 // otherwise find it somewhere in the list
318                                 for (current = cvar_vars;current->next != cvar;current = current->next)
319                                         ;
320                                 current->next = variable;
321                         }
322
323                         // get rid of old allocated cvar
324                         // (but not cvar->string and cvar->defstring, because we kept those)
325                         Z_Free(cvar->name);
326                         Z_Free(cvar);
327                 }
328                 else
329                         Con_Printf("Can't register variable %s, already defined\n", variable->name);
330                 return;
331         }
332
333 // check for overlap with a command
334         if (Cmd_Exists (variable->name))
335         {
336                 Con_Printf("Cvar_RegisterVariable: %s is a command\n", variable->name);
337                 return;
338         }
339
340 // copy the value off, because future sets will Z_Free it
341         oldstr = variable->string;
342         variable->string = Z_Malloc (strlen(variable->string)+1);
343         strcpy (variable->string, oldstr);
344         variable->defstring = Z_Malloc (strlen(variable->string)+1);
345         strcpy (variable->defstring, oldstr);
346         variable->value = atof (variable->string);
347         variable->integer = (int) variable->value;
348
349 // link the variable in
350 // alphanumerical order
351         for( current = NULL, next = cvar_vars ; next && strcmp( next->name, variable->name ) < 0 ; current = next, next = next->next )
352                 ;
353         if( current ) {
354                 current->next = variable;
355         } else {
356                 cvar_vars = variable;
357         }
358         variable->next = next;
359 }
360
361 /*
362 ============
363 Cvar_Get
364
365 Adds a newly allocated variable to the variable list or sets its value.
366 ============
367 */
368 cvar_t *Cvar_Get (const char *name, const char *value, int flags)
369 {
370         cvar_t *cvar;
371
372         if (developer.integer)
373                 Con_Printf("Cvar_Get(\"%s\", \"%s\", %i);\n", name, value, flags);
374
375 // first check to see if it has already been defined
376         cvar = Cvar_FindVar (name);
377         if (cvar)
378         {
379                 cvar->flags |= flags;
380                 Cvar_SetQuick_Internal (cvar, value);
381                 // also set the default value (but only once)
382                 if (~cvar->flags & CVAR_DEFAULTSET)
383                 {
384                         cvar->flags |= CVAR_DEFAULTSET;
385
386                         Z_Free(cvar->defstring);
387                         cvar->defstring = Z_Malloc(strlen(value) + 1);
388                         strcpy(cvar->defstring, value);
389                 }
390                 return cvar;
391         }
392
393 // check for overlap with a command
394         if (Cmd_Exists (name))
395         {
396                 Con_Printf("Cvar_Get: %s is a command\n", name);
397                 return NULL;
398         }
399
400 // allocate a new cvar, cvar name, and cvar string
401 // FIXME: these never get Z_Free'd
402         cvar = Z_Malloc(sizeof(cvar_t));
403         cvar->flags = flags | CVAR_ALLOCATED | CVAR_DEFAULTSET;
404         cvar->name = Z_Malloc(strlen(name)+1);
405         strcpy(cvar->name, name);
406         cvar->string = Z_Malloc(strlen(value)+1);
407         strcpy(cvar->string, value);
408         cvar->defstring = Z_Malloc(strlen(value)+1);
409         strcpy(cvar->defstring, value);
410         cvar->value = atof (cvar->string);
411         cvar->integer = (int) cvar->value;
412
413 // link the variable in
414         cvar->next = cvar_vars;
415         cvar_vars = cvar;
416         return cvar;
417 }
418
419
420 /*
421 ============
422 Cvar_Command
423
424 Handles variable inspection and changing from the console
425 ============
426 */
427 qboolean        Cvar_Command (void)
428 {
429         cvar_t                  *v;
430
431 // check variables
432         v = Cvar_FindVar (Cmd_Argv(0));
433         if (!v)
434                 return false;
435
436 // perform a variable print or set
437         if (Cmd_Argc() == 1)
438         {
439                 Con_Printf("\"%s\" is \"%s\" [\"%s\"]\n", v->name, v->string, v->defstring);
440                 return true;
441         }
442
443         Con_DPrint("Cvar_Command: ");
444
445         if (v->flags & CVAR_READONLY)
446         {
447                 Con_Printf("%s is read-only\n", v->name);
448                 return true;
449         }
450         Cvar_Set (v->name, Cmd_Argv(1));
451         return true;
452 }
453
454
455 /*
456 ============
457 Cvar_WriteVariables
458
459 Writes lines containing "set variable value" for all variables
460 with the archive flag set to true.
461 ============
462 */
463 void Cvar_WriteVariables (qfile_t *f)
464 {
465         cvar_t  *var;
466
467         for (var = cvar_vars ; var ; var = var->next)
468                 if (var->flags & CVAR_SAVE)
469                         FS_Printf(f, "%s%s \"%s\"\n", var->flags & CVAR_ALLOCATED ? "seta " : "", var->name, var->string);
470 }
471
472
473 // Added by EvilTypeGuy eviltypeguy@qeradiant.com
474 // 2000-01-09 CvarList command By Matthias "Maddes" Buecher, http://www.inside3d.com/qip/
475 /*
476 =========
477 Cvar_List
478 =========
479 */
480 void Cvar_List_f (void)
481 {
482         cvar_t *cvar;
483         const char *partial;
484         size_t len;
485         int count;
486
487         if (Cmd_Argc() > 1)
488         {
489                 partial = Cmd_Argv (1);
490                 len = strlen(partial);
491         }
492         else
493         {
494                 partial = NULL;
495                 len = 0;
496         }
497
498         count = 0;
499         for (cvar = cvar_vars; cvar; cvar = cvar->next)
500         {
501                 if (partial && strncasecmp (partial,cvar->name,len))
502                         continue;
503
504                 Con_Printf("%s is \"%s\" [\"%s\"]\n", cvar->name, cvar->string, cvar->defstring);
505                 count++;
506         }
507
508         Con_Printf("%i cvar(s)", count);
509         if (partial)
510                 Con_Printf(" beginning with \"%s\"", partial);
511         Con_Print("\n");
512 }
513 // 2000-01-09 CvarList command by Maddes
514
515 void Cvar_Set_f (void)
516 {
517         cvar_t *cvar;
518
519         // make sure it's the right number of parameters
520         if (Cmd_Argc() < 3)
521         {
522                 Con_Printf("Set: wrong number of parameters, usage: set <variablename> <value>\n");
523                 return;
524         }
525
526         // check if it's read-only
527         cvar = Cvar_FindVar(Cmd_Argv(1));
528         if (cvar && cvar->flags & CVAR_READONLY)
529         {
530                 Con_Printf("Set: %s is read-only\n", cvar->name);
531                 return;
532         }
533
534         Con_DPrint("Set: ");
535
536         // all looks ok, create/modify the cvar
537         Cvar_Get(Cmd_Argv(1), Cmd_Argv(2), 0);
538 }
539
540 void Cvar_SetA_f (void)
541 {
542         cvar_t *cvar;
543
544         // make sure it's the right number of parameters
545         if (Cmd_Argc() < 3)
546         {
547                 Con_Printf("SetA: wrong number of parameters, usage: seta <variablename> <value>\n");
548                 return;
549         }
550
551         // check if it's read-only
552         cvar = Cvar_FindVar(Cmd_Argv(1));
553         if (cvar && cvar->flags & CVAR_READONLY)
554         {
555                 Con_Printf("SetA: %s is read-only\n", cvar->name);
556                 return;
557         }
558
559         Con_DPrint("SetA: ");
560
561         // all looks ok, create/modify the cvar
562         Cvar_Get(Cmd_Argv(1), Cmd_Argv(2), CVAR_SAVE);
563 }
564
565