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 #include <stdio.h>
22
23 #include "cmd.h"
24 #include "common.h"
25 #include "console.h"
26 #include "cvar.h"
27 #include "shell.h"
28 #include "zone.h"
29
30 #ifdef NQ_HACK
31 #include "server.h"
32 #include "quakedef.h"
33 #include "host.h"
34 #endif
35
36 #ifdef SERVERONLY
37 #include "qwsvdef.h"
38 #include "server.h"
39 #else
40 #ifdef QW_HACK
41 #include "quakedef.h"
42 #include "client.h"
43 #endif
44 #endif
45
46 #define cvar_entry(ptr) container_of(ptr, struct cvar_s, stree)
47 DECLARE_STREE_ROOT(cvar_tree);
48
49 /*
50 ============
51 Cvar_FindVar
52 ============
53 */
54 cvar_t *
Cvar_FindVar(const char * var_name)55 Cvar_FindVar(const char *var_name)
56 {
57 struct cvar_s *ret = NULL;
58 struct stree_node *n;
59
60 n = STree_Find(&cvar_tree, var_name);
61 if (n)
62 ret = cvar_entry(n);
63
64 return ret;
65 }
66
67 /*
68 * Return a string tree with all possible argument completions of the given
69 * buffer for the given cvar.
70 */
71 struct stree_root *
Cvar_ArgCompletions(const char * name,const char * buf)72 Cvar_ArgCompletions(const char *name, const char *buf)
73 {
74 cvar_t *cvar;
75 struct stree_root *root = NULL;
76
77 cvar = Cvar_FindVar(name);
78 if (cvar && cvar->completion)
79 root = cvar->completion(buf);
80
81 return root;
82 }
83
84 /*
85 * Call the argument completion function for cvar "name".
86 * Returned result should be Z_Free'd after use.
87 */
88 char *
Cvar_ArgComplete(const char * name,const char * buf)89 Cvar_ArgComplete(const char *name, const char *buf)
90 {
91 char *result = NULL;
92 struct stree_root *root;
93
94 root = Cvar_ArgCompletions(name, buf);
95 if (root) {
96 result = STree_MaxMatch(root, buf);
97 Z_Free(root);
98 }
99
100 return result;
101 }
102
103
104 #ifdef NQ_HACK
105 /*
106 * For NQ/net_dgrm.c, command == CCREQ_RULE_INFO case
107 */
108 cvar_t *
Cvar_NextServerVar(const char * var_name)109 Cvar_NextServerVar(const char *var_name)
110 {
111 cvar_t *ret = NULL;
112 cvar_t *var;
113 struct stree_node *n;
114
115 if (var_name[0] == '\0')
116 var_name = NULL;
117
118 if (var_name)
119 {
120 STree_ForEach_Init__(&cvar_tree, &n);
121 STree_ForEach_After__(&cvar_tree, &n, var_name);
122 for (; STree_WalkLeft__(&cvar_tree, &n) ; STree_WalkRight__(&n)) {
123 var = cvar_entry(n);
124 if (var->server) {
125 ret = var;
126 STree_ForEach_Cleanup__(&cvar_tree);
127 return ret;
128 }
129 }
130 }
131 else
132 {
133 STree_ForEach_After_NullStr(&cvar_tree, n) {
134 var = cvar_entry(n);
135 if (var->server) {
136 ret = var;
137 STree_ForEach_Cleanup__(&cvar_tree);
138 return ret;
139 }
140 }
141 }
142
143 return ret;
144 }
145 #endif
146
147 /*
148 ============
149 Cvar_VariableValue
150 ============
151 */
152 float
Cvar_VariableValue(const char * var_name)153 Cvar_VariableValue(const char *var_name)
154 {
155 cvar_t *var;
156
157 var = Cvar_FindVar(var_name);
158 if (!var)
159 return 0;
160 return Q_atof(var->string);
161 }
162
163
164 /*
165 ============
166 Cvar_VariableString
167 ============
168 */
169 const char *
Cvar_VariableString(const char * var_name)170 Cvar_VariableString(const char *var_name)
171 {
172 cvar_t *var;
173
174 var = Cvar_FindVar(var_name);
175
176 return var ? var->string : "";
177 }
178
179
180 /*
181 ============
182 Cvar_Set
183 ============
184 */
185 void
Cvar_Set(const char * var_name,const char * value)186 Cvar_Set(const char *var_name, const char *value)
187 {
188 cvar_t *var;
189 char *newstring;
190 qboolean changed;
191
192 var = Cvar_FindVar(var_name);
193 if (!var) {
194 /* there is an error in C code if this happens */
195 Con_Printf("Cvar_Set: variable %s not found\n", var_name);
196 return;
197 }
198
199 if (var->flags & CVAR_OBSOLETE) {
200 Con_Printf("%s is obsolete.\n", var_name);
201 return;
202 }
203
204 changed = strcmp(var->string, value);
205
206 /* Check for developer-only cvar */
207 if (changed && (var->flags & CVAR_DEVELOPER) && !developer.value) {
208 Con_Printf("%s is settable only in developer mode.\n", var_name);
209 return;
210 }
211
212 #ifdef SERVERONLY
213 if (var->info) {
214 Info_SetValueForKey(svs.info, var_name, value, MAX_SERVERINFO_STRING);
215 SV_SendServerInfoChange(var_name, value);
216 // SV_BroadcastCommand ("fullserverinfo \"%s\"\n", svs.info);
217 }
218 #else
219 #ifdef QW_HACK
220 if (var->info) {
221 Info_SetValueForKey(cls.userinfo, var_name, value, MAX_INFO_STRING);
222 if (cls.state >= ca_connected) {
223 MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
224 MSG_WriteStringf(&cls.netchan.message, "setinfo \"%s\" \"%s\"\n",
225 var_name, value);
226 }
227 }
228 #endif
229 #endif
230
231 Z_Free(var->string); // free the old value string
232
233 newstring = (char*)Z_Malloc(strlen(value) + 1);
234 strcpy(newstring, value);
235 var->string = newstring;
236 var->value = Q_atof(var->string);
237
238 #ifdef NQ_HACK
239 if (var->server && changed) {
240 if (sv.active)
241 SV_BroadcastPrintf("\"%s\" changed to \"%s\"\n", var->name,
242 var->string);
243 }
244 #endif
245
246 if (changed && var->callback)
247 var->callback(var);
248
249 #ifdef NQ_HACK
250 // Don't allow deathmatch and coop at the same time...
251 if ((var->value != 0) && (!strcmp(var->name, deathmatch.name)))
252 Cvar_Set("coop", "0");
253 if ((var->value != 0) && (!strcmp(var->name, coop.name)))
254 Cvar_Set("deathmatch", "0");
255 #endif
256 }
257
258 /*
259 ============
260 Cvar_SetValue
261 ============
262 */
263 void
Cvar_SetValue(const char * var_name,float value)264 Cvar_SetValue(const char *var_name, float value)
265 {
266 char val[32];
267
268 snprintf(val, sizeof(val), "%f", value);
269 Cvar_Set(var_name, val);
270 }
271
272
273 /*
274 ============
275 Cvar_RegisterVariable
276
277 Adds a freestanding variable to the variable list.
278 ============
279 */
Cvar_RegisterVariable(cvar_t * variable)280 void Cvar_RegisterVariable(cvar_t *variable)
281 {
282 char value[512]; // FIXME - magic numbers...
283 float old_developer;
284
285 /* first check to see if it has allready been defined */
286 if (Cvar_FindVar(variable->name))
287 {
288 Con_Printf("Can't register variable %s, allready defined\n",
289 variable->name);
290 return;
291 }
292 /* check for overlap with a command */
293 if (Cmd_Exists(variable->name)) {
294 Con_Printf("Cvar_RegisterVariable: %s is a command\n",
295 variable->name);
296 return;
297 }
298
299 variable->stree.string = variable->name;
300 STree_Insert(&cvar_tree, &variable->stree);
301
302 // copy the value off, because future sets will Z_Free it
303 strncpy(value, variable->string, 511);
304 value[511] = '\0';
305 variable->string = (const char*)Z_Malloc(1);
306
307 if (!(variable->flags & CVAR_CALLBACK))
308 variable->callback = NULL;
309
310 /*
311 * FIXME (BARF) - readonly cvars need to be initialised
312 * developer 1 allows set
313 */
314 /* set it through the function to be consistant */
315 old_developer = developer.value;
316 developer.value = 1;
317 Cvar_Set(variable->name, value);
318 developer.value = old_developer;
319 }
320
321 /*
322 ============
323 Cvar_SetCallback
324
325 Set a callback function to the var
326 ============
327 */
Cvar_SetCallback(cvar_t * var,cvar_callback func)328 void Cvar_SetCallback (cvar_t *var, cvar_callback func)
329 {
330 var->callback = func;
331 if (func)
332 var->flags |= CVAR_CALLBACK;
333 else var->flags &= ~CVAR_CALLBACK;
334 }
335
336 /*
337 ============
338 Cvar_Command
339
340 Handles variable inspection and changing from the console
341 ============
342 */
Cvar_Command(void)343 qboolean Cvar_Command(void)
344 {
345 /* check variables */
346 cvar_t *v = Cvar_FindVar(Cmd_Argv(0));
347 if (!v)
348 return false;
349
350 /* perform a variable print or set */
351 if (Cmd_Argc() == 1)
352 {
353 if (v->flags & CVAR_OBSOLETE)
354 Con_Printf("%s is obsolete.\n", v->name);
355 else
356 Con_Printf("\"%s\" is \"%s\"\n", v->name, v->string);
357 return true;
358 }
359
360 Cvar_Set(v->name, Cmd_Argv(1));
361 return true;
362 }
363
364
365 /*
366 ============
367 Cvar_WriteVariables
368
369 Writes lines containing "set variable value" for all variables
370 with the archive flag set to true.
371 ============
372 */
Cvar_WriteVariables(FILE * f)373 void Cvar_WriteVariables(FILE *f)
374 {
375 struct stree_node *n;
376
377 STree_ForEach_After_NullStr(&cvar_tree, n)
378 {
379 cvar_t *var = cvar_entry(n);
380 if (var->archive)
381 fprintf(f, "%s \"%s\"\n", var->name, var->string);
382 }
383 }
384