1 /*
2 #FILENAME#
3
4 #DESCRIPTION#
5
6 Copyright (C) 2002 #AUTHOR#
7
8 Author: #AUTHOR#
9 Date: #DATE#
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20 See the GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to:
24
25 Free Software Foundation, Inc.
26 59 Temple Place - Suite 330
27 Boston, MA 02111-1307, USA
28
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <string.h>
36 #include <stdlib.h>
37
38 #include "QF/dstring.h"
39 #include "QF/va.h"
40 #include "QF/hash.h"
41 #include "QF/cvar.h"
42
43 #include "gib_parse.h"
44 #include "gib_vars.h"
45
46 hashtab_t *gib_globals = 0;
47 hashtab_t *gib_domains = 0;
48
49 static gib_var_t *
GIB_Var_New(const char * key)50 GIB_Var_New (const char *key)
51 {
52 gib_var_t *new = calloc (1, sizeof (gib_var_t));
53
54 new->array = calloc (1, sizeof (dstring_t *));
55 new->key = strdup (key);
56 return new;
57 }
58
59 static const char *
GIB_Var_Get_Key(const void * ele,void * ptr)60 GIB_Var_Get_Key (const void *ele, void *ptr)
61 {
62 return ((gib_var_t *) ele)->key;
63 }
64
65 static void
GIB_Var_Free(void * ele,void * ptr)66 GIB_Var_Free (void *ele, void *ptr)
67 {
68 unsigned int i;
69 gib_var_t *l = (gib_var_t *) ele;
70
71 for (i = 0; i < l->size; i++) {
72 if (l->array[i].value)
73 dstring_delete (l->array[i].value);
74 if (l->array[i].leaves)
75 Hash_DelTable (l->array[i].leaves);
76 }
77 free (l->array);
78 free ((void *) l->key);
79 free (l);
80 }
81
82 gib_var_t *
GIB_Var_Get(hashtab_t * first,hashtab_t * second,const char * key)83 GIB_Var_Get (hashtab_t * first, hashtab_t * second, const char *key)
84 {
85 gib_var_t *var;
86
87 if (first && (var = Hash_Find (first, key)))
88 return var;
89 else if (second && (var = Hash_Find (second, key)))
90 return var;
91 else
92 return 0;
93 }
94
95 /* Alters key, but restores it */
96 gib_var_t *
GIB_Var_Get_Complex(hashtab_t ** first,hashtab_t ** second,char * key,unsigned int * ind,qboolean create)97 GIB_Var_Get_Complex (hashtab_t ** first, hashtab_t ** second, char *key,
98 unsigned int *ind, qboolean create)
99 {
100 static hashtab_t *zero = 0;
101 unsigned int i, n, index = 0, len, start;
102 gib_var_t *var = 0;
103
104 len = strlen(key);
105 for (start = i = 0; i <= len; i++) {
106 if (key[i] == '.' || key[i] == 0) {
107 index = 0;
108 key[i] = 0;
109 n = 0;
110 if (i && key[i - 1] == ']')
111 for (n = i - 1; n; n--)
112 if (key[n] == '[') {
113 index = atoi (key + n + 1);
114 key[n] = 0;
115 break;
116 }
117 if (!(var = GIB_Var_Get (*first, *second, key+start)) && create) {
118 var = GIB_Var_New (key+start);
119 if (!*first)
120 *first = Hash_NewTable (256, GIB_Var_Get_Key, GIB_Var_Free, 0);
121 Hash_Add (*first, var);
122 }
123
124 // We are done looking up/creating var, fix up key
125 if (n)
126 key[n] = '[';
127 if (i < len)
128 key[i] = '.';
129
130 // Give up
131 if (!var)
132 return 0;
133 else if (index >= var->size) {
134 if (create) {
135 var->array = realloc (var->array,
136 (index + 1) * sizeof (struct gib_varray_s));
137 memset (var->array + var->size, 0,
138 (index + 1 - var->size) * sizeof (struct gib_varray_s));
139 var->size = index + 1;
140 } else
141 return 0;
142 }
143 second = &zero;
144 first = &var->array[index].leaves;
145 start = i+1;
146 }
147 }
148 if (!var->array[index].value)
149 var->array[index].value = dstring_newstr ();
150 *ind = index;
151 return var;
152 }
153
154 /* Mangles the hell out of key */
155 gib_var_t *
GIB_Var_Get_Very_Complex(hashtab_t ** first,hashtab_t ** second,dstring_t * key,unsigned int start,unsigned int * ind,qboolean create)156 GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *key, unsigned int start,
157 unsigned int *ind, qboolean create)
158 {
159 static hashtab_t *zero = 0;
160 hashtab_t *one = *first, *two = *second;
161 unsigned int i, index = 0, index2 = 0, n, protect, varstartskip;
162 gib_var_t *var = 0;
163 cvar_t *cvar;
164 char c, *str;
165 qboolean done = false;
166
167 for (i = start, protect = 0; !done; i++) {
168 if (key->str[i] == '.' || key->str[i] == 0) {
169 index = 0;
170 if (!key->str[i])
171 done = true;
172 key->str[i] = 0;
173 if (i && key->str[i - 1] == ']')
174 for (n = i-1; n; n--)
175 if (key->str[n] == '[') {
176 index = atoi (key->str + n + 1);
177 key->str[n] = 0;
178 break;
179 }
180 if (!(var = GIB_Var_Get (*first, *second, key->str+start))) {
181 if (create) {
182 var = GIB_Var_New (key->str+start);
183 if (!*first)
184 *first = Hash_NewTable (256, GIB_Var_Get_Key, GIB_Var_Free, 0);
185 Hash_Add (*first, var);
186 } else
187 return 0;
188 }
189 if (index >= var->size) {
190 if (create) {
191 var->array = realloc (var->array,
192 (index + 1) * sizeof (struct gib_varray_s));
193 memset (var->array + var->size, 0,
194 (index + 1 - var->size) * sizeof (struct gib_varray_s));
195 var->size = index + 1;
196 } else
197 return 0;
198 }
199 second = &zero;
200 first = &var->array[index].leaves;
201 start = i+1;
202 } else if (i >= protect && (key->str[i] == '$' || key->str[i] == '#')) {
203 n = i;
204 if (GIB_Parse_Match_Var (key->str, &i))
205 return 0;
206 c = key->str[i];
207 varstartskip = (c == '}');
208 key->str[i] = 0;
209 if ((var = GIB_Var_Get_Very_Complex (&one, &two, key, n+1+varstartskip, &index2, create))) {
210 if (key->str[n] == '#')
211 str = va("%u", var->size);
212 else
213 str = var->array[index2].value->str;
214 key->str[i] = c;
215 dstring_replace (key, n, i-n+varstartskip, str, strlen (str));
216 protect = n+strlen(str);
217 } else if (key->str[n] == '#') {
218 key->str[i] = c;
219 dstring_replace (key, n, i-n+varstartskip, "0", 1);
220 protect = n+1;
221 } else if ((cvar = Cvar_FindVar (key->str+n+1+varstartskip))) {
222 key->str[i] = c;
223 dstring_replace (key, n, i-n+varstartskip, cvar->string, strlen (cvar->string));
224 protect = n+strlen(cvar->string);
225 } else {
226 key->str[i] = c;
227 dstring_snip (key, n, n-i+varstartskip);
228 protect = 0;
229 }
230 i = n;
231 }
232
233 }
234 if (!var->array[index].value)
235 var->array[index].value = dstring_newstr ();
236 *ind = index;
237 return var;
238 }
239
240 void
GIB_Var_Assign(gib_var_t * var,unsigned int index,dstring_t ** values,unsigned int numv,qboolean shrink)241 GIB_Var_Assign (gib_var_t * var, unsigned int index, dstring_t ** values,
242 unsigned int numv, qboolean shrink)
243 {
244 unsigned int i, len;
245
246 // Now, expand the array to the correct size
247 len = numv + index;
248 if (len >= var->size) {
249 var->array = realloc (var->array, len * sizeof (struct gib_varray_s));
250 memset (var->array + var->size, 0,
251 (len - var->size) * sizeof (struct gib_varray_s));
252 var->size = len;
253 } else if (len < var->size && shrink) {
254 for (i = len; i < var->size; i++) {
255 if (var->array[i].value)
256 dstring_delete (var->array[i].value);
257 if (var->array[i].leaves)
258 Hash_DelTable (var->array[i].leaves);
259 }
260 var->array = realloc (var->array, len * sizeof (struct gib_varray_s));
261 var->size = len;
262 }
263 for (i = 0; i < numv; i++) {
264 if (var->array[i + index].value)
265 dstring_clearstr (var->array[i + index].value);
266 else
267 var->array[i + index].value = dstring_newstr ();
268 dstring_appendstr (var->array[i + index].value, values[i]->str);
269 }
270 }
271
272 static const char *
GIB_Domain_Get_Key(const void * ele,void * ptr)273 GIB_Domain_Get_Key (const void *ele, void *ptr)
274 {
275 return ((gib_domain_t *) ele)->name;
276 }
277
278 static void
GIB_Domain_Free(void * ele,void * ptr)279 GIB_Domain_Free (void *ele, void *ptr)
280 {
281 gib_domain_t *l = (gib_domain_t *) ele;
282
283 Hash_DelTable (l->vars);
284 free ((void *) l->name);
285 free (l);
286 }
287
288 hashtab_t *
GIB_Domain_Get(const char * name)289 GIB_Domain_Get (const char *name)
290 {
291 gib_domain_t *d = Hash_Find (gib_domains, name);
292
293 if (!d) {
294 d = calloc (1, sizeof (gib_domain_t));
295 d->name = strdup (name);
296 d->vars = Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0);
297 Hash_Add (gib_domains, d);
298 }
299 return d->vars;
300 }
301
302 hashtab_t *
GIB_Var_Hash_New(void)303 GIB_Var_Hash_New (void)
304 {
305 return Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0);
306 }
307
308 void
GIB_Var_Init(void)309 GIB_Var_Init (void)
310 {
311 gib_globals = Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0);
312 gib_domains = Hash_NewTable (1024, GIB_Domain_Get_Key, GIB_Domain_Free, 0);
313 }
314