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