1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2000-2006 Tim Angus
5 
6 This file is part of Tremulous.
7 
8 Tremulous is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12 
13 Tremulous is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Tremulous; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 ===========================================================================
22 */
23 
24 /*****************************************************************************
25  * name:		l_struct.c
26  *
27  * desc:		structure reading / writing
28  *
29  * $Archive: /MissionPack/CODE/botlib/l_struct.c $
30  *
31  *****************************************************************************/
32 
33 #ifdef BOTLIB
34 #include "../qcommon/q_shared.h"
35 #include "botlib.h"				//for the include of be_interface.h
36 #include "l_script.h"
37 #include "l_precomp.h"
38 #include "l_struct.h"
39 #include "l_utils.h"
40 #include "be_interface.h"
41 #endif //BOTLIB
42 
43 #ifdef BSPC
44 //include files for usage in the BSP Converter
45 #include "../bspc/qbsp.h"
46 #include "../bspc/l_log.h"
47 #include "../bspc/l_mem.h"
48 #include "l_precomp.h"
49 #include "l_struct.h"
50 
51 #define qtrue	true
52 #define qfalse	false
53 #endif //BSPC
54 
55 //===========================================================================
56 //
57 // Parameter:				-
58 // Returns:					-
59 // Changes Globals:		-
60 //===========================================================================
FindField(fielddef_t * defs,char * name)61 fielddef_t *FindField(fielddef_t *defs, char *name)
62 {
63 	int i;
64 
65 	for (i = 0; defs[i].name; i++)
66 	{
67 		if (!strcmp(defs[i].name, name)) return &defs[i];
68 	} //end for
69 	return NULL;
70 } //end of the function FindField
71 //===========================================================================
72 //
73 // Parameter:				-
74 // Returns:					-
75 // Changes Globals:		-
76 //===========================================================================
ReadNumber(source_t * source,fielddef_t * fd,void * p)77 qboolean ReadNumber(source_t *source, fielddef_t *fd, void *p)
78 {
79 	token_t token;
80 	int negative = qfalse;
81 	long int intval, intmin = 0, intmax = 0;
82 	double floatval;
83 
84 	if (!PC_ExpectAnyToken(source, &token)) return 0;
85 
86 	//check for minus sign
87 	if (token.type == TT_PUNCTUATION)
88 	{
89 		if (fd->type & FT_UNSIGNED)
90 		{
91 			SourceError(source, "expected unsigned value, found %s", token.string);
92 			return 0;
93 		} //end if
94 		//if not a minus sign
95 		if (strcmp(token.string, "-"))
96 		{
97 			SourceError(source, "unexpected punctuation %s", token.string);
98 			return 0;
99 		} //end if
100 		negative = qtrue;
101 		//read the number
102 		if (!PC_ExpectAnyToken(source, &token)) return 0;
103 	} //end if
104 	//check if it is a number
105 	if (token.type != TT_NUMBER)
106 	{
107 		SourceError(source, "expected number, found %s", token.string);
108 		return 0;
109 	} //end if
110 	//check for a float value
111 	if (token.subtype & TT_FLOAT)
112 	{
113 		if ((fd->type & FT_TYPE) != FT_FLOAT)
114 		{
115 			SourceError(source, "unexpected float");
116 			return 0;
117 		} //end if
118 		floatval = token.floatvalue;
119 		if (negative) floatval = -floatval;
120 		if (fd->type & FT_BOUNDED)
121 		{
122 			if (floatval < fd->floatmin || floatval > fd->floatmax)
123 			{
124 				SourceError(source, "float out of range [%f, %f]", fd->floatmin, fd->floatmax);
125 				return 0;
126 			} //end if
127 		} //end if
128 		*(float *) p = (float) floatval;
129 		return 1;
130 	} //end if
131 	//
132 	intval = token.intvalue;
133 	if (negative) intval = -intval;
134 	//check bounds
135 	if ((fd->type & FT_TYPE) == FT_CHAR)
136 	{
137 		if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 255;}
138 		else {intmin = -128; intmax = 127;}
139 	} //end if
140 	if ((fd->type & FT_TYPE) == FT_INT)
141 	{
142 		if (fd->type & FT_UNSIGNED) {intmin = 0; intmax = 65535;}
143 		else {intmin = -32768; intmax = 32767;}
144 	} //end else if
145 	if ((fd->type & FT_TYPE) == FT_CHAR || (fd->type & FT_TYPE) == FT_INT)
146 	{
147 		if (fd->type & FT_BOUNDED)
148 		{
149 			intmin = Maximum(intmin, fd->floatmin);
150 			intmax = Minimum(intmax, fd->floatmax);
151 		} //end if
152 		if (intval < intmin || intval > intmax)
153 		{
154 			SourceError(source, "value %d out of range [%d, %d]", intval, intmin, intmax);
155 			return 0;
156 		} //end if
157 	} //end if
158 	else if ((fd->type & FT_TYPE) == FT_FLOAT)
159 	{
160 		if (fd->type & FT_BOUNDED)
161 		{
162 			if (intval < fd->floatmin || intval > fd->floatmax)
163 			{
164 				SourceError(source, "value %d out of range [%f, %f]", intval, fd->floatmin, fd->floatmax);
165 				return 0;
166 			} //end if
167 		} //end if
168 	} //end else if
169 	//store the value
170 	if ((fd->type & FT_TYPE) == FT_CHAR)
171 	{
172 		if (fd->type & FT_UNSIGNED) *(unsigned char *) p = (unsigned char) intval;
173 		else *(char *) p = (char) intval;
174 	} //end if
175 	else if ((fd->type & FT_TYPE) == FT_INT)
176 	{
177 		if (fd->type & FT_UNSIGNED) *(unsigned int *) p = (unsigned int) intval;
178 		else *(int *) p = (int) intval;
179 	} //end else
180 	else if ((fd->type & FT_TYPE) == FT_FLOAT)
181 	{
182 		*(float *) p = (float) intval;
183 	} //end else
184 	return 1;
185 } //end of the function ReadNumber
186 //===========================================================================
187 //
188 // Parameter:				-
189 // Returns:					-
190 // Changes Globals:		-
191 //===========================================================================
ReadChar(source_t * source,fielddef_t * fd,void * p)192 qboolean ReadChar(source_t *source, fielddef_t *fd, void *p)
193 {
194 	token_t token;
195 
196 	if (!PC_ExpectAnyToken(source, &token)) return 0;
197 
198 	//take literals into account
199 	if (token.type == TT_LITERAL)
200 	{
201 		StripSingleQuotes(token.string);
202 		*(char *) p = token.string[0];
203 	} //end if
204 	else
205 	{
206 		PC_UnreadLastToken(source);
207 		if (!ReadNumber(source, fd, p)) return 0;
208 	} //end if
209 	return 1;
210 } //end of the function ReadChar
211 //===========================================================================
212 //
213 // Parameter:				-
214 // Returns:					-
215 // Changes Globals:		-
216 //===========================================================================
ReadString(source_t * source,fielddef_t * fd,void * p)217 int ReadString(source_t *source, fielddef_t *fd, void *p)
218 {
219 	token_t token;
220 
221 	if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) return 0;
222 	//remove the double quotes
223 	StripDoubleQuotes(token.string);
224 	//copy the string
225 	strncpy((char *) p, token.string, MAX_STRINGFIELD);
226 	//make sure the string is closed with a zero
227 	((char *)p)[MAX_STRINGFIELD-1] = '\0';
228 	//
229 	return 1;
230 } //end of the function ReadString
231 //===========================================================================
232 //
233 // Parameter:				-
234 // Returns:					-
235 // Changes Globals:		-
236 //===========================================================================
ReadStructure(source_t * source,structdef_t * def,char * structure)237 int ReadStructure(source_t *source, structdef_t *def, char *structure)
238 {
239 	token_t token;
240 	fielddef_t *fd;
241 	void *p;
242 	int num;
243 
244 	if (!PC_ExpectTokenString(source, "{")) return 0;
245 	while(1)
246 	{
247 		if (!PC_ExpectAnyToken(source, &token)) return qfalse;
248 		//if end of structure
249 		if (!strcmp(token.string, "}")) break;
250 		//find the field with the name
251 		fd = FindField(def->fields, token.string);
252 		if (!fd)
253 		{
254 			SourceError(source, "unknown structure field %s", token.string);
255 			return qfalse;
256 		} //end if
257 		if (fd->type & FT_ARRAY)
258 		{
259 			num = fd->maxarray;
260 			if (!PC_ExpectTokenString(source, "{")) return qfalse;
261 		} //end if
262 		else
263 		{
264 			num = 1;
265 		} //end else
266 		p = (void *)(structure + fd->offset);
267 		while (num-- > 0)
268 		{
269 			if (fd->type & FT_ARRAY)
270 			{
271 				if (PC_CheckTokenString(source, "}")) break;
272 			} //end if
273 			switch(fd->type & FT_TYPE)
274 			{
275 				case FT_CHAR:
276 				{
277 					if (!ReadChar(source, fd, p)) return qfalse;
278 					p = (char *) p + sizeof(char);
279 					break;
280 				} //end case
281 				case FT_INT:
282 				{
283 					if (!ReadNumber(source, fd, p)) return qfalse;
284 					p = (char *) p + sizeof(int);
285 					break;
286 				} //end case
287 				case FT_FLOAT:
288 				{
289 					if (!ReadNumber(source, fd, p)) return qfalse;
290 					p = (char *) p + sizeof(float);
291 					break;
292 				} //end case
293 				case FT_STRING:
294 				{
295 					if (!ReadString(source, fd, p)) return qfalse;
296 					p = (char *) p + MAX_STRINGFIELD;
297 					break;
298 				} //end case
299 				case FT_STRUCT:
300 				{
301 					if (!fd->substruct)
302 					{
303 						SourceError(source, "BUG: no sub structure defined");
304 						return qfalse;
305 					} //end if
306 					ReadStructure(source, fd->substruct, (char *) p);
307 					p = (char *) p + fd->substruct->size;
308 					break;
309 				} //end case
310 			} //end switch
311 			if (fd->type & FT_ARRAY)
312 			{
313 				if (!PC_ExpectAnyToken(source, &token)) return qfalse;
314 				if (!strcmp(token.string, "}")) break;
315 				if (strcmp(token.string, ","))
316 				{
317 					SourceError(source, "expected a comma, found %s", token.string);
318 					return qfalse;
319 				} //end if
320 			} //end if
321 		} //end while
322 	} //end while
323 	return qtrue;
324 } //end of the function ReadStructure
325 //===========================================================================
326 //
327 // Parameter:				-
328 // Returns:					-
329 // Changes Globals:		-
330 //===========================================================================
WriteIndent(FILE * fp,int indent)331 int WriteIndent(FILE *fp, int indent)
332 {
333 	while(indent-- > 0)
334 	{
335 		if (fprintf(fp, "\t") < 0) return qfalse;
336 	} //end while
337 	return qtrue;
338 } //end of the function WriteIndent
339 //===========================================================================
340 //
341 // Parameter:				-
342 // Returns:					-
343 // Changes Globals:		-
344 //===========================================================================
WriteFloat(FILE * fp,float value)345 int WriteFloat(FILE *fp, float value)
346 {
347 	char buf[128];
348 	int l;
349 
350 	sprintf(buf, "%f", value);
351 	l = strlen(buf);
352 	//strip any trailing zeros
353 	while(l-- > 1)
354 	{
355 		if (buf[l] != '0' && buf[l] != '.') break;
356 		if (buf[l] == '.')
357 		{
358 			buf[l] = 0;
359 			break;
360 		} //end if
361 		buf[l] = 0;
362 	} //end while
363 	//write the float to file
364 	if (fprintf(fp, "%s", buf) < 0) return 0;
365 	return 1;
366 } //end of the function WriteFloat
367 //===========================================================================
368 //
369 // Parameter:				-
370 // Returns:					-
371 // Changes Globals:		-
372 //===========================================================================
WriteStructWithIndent(FILE * fp,structdef_t * def,char * structure,int indent)373 int WriteStructWithIndent(FILE *fp, structdef_t *def, char *structure, int indent)
374 {
375 	int i, num;
376 	void *p;
377 	fielddef_t *fd;
378 
379 	if (!WriteIndent(fp, indent)) return qfalse;
380 	if (fprintf(fp, "{\r\n") < 0) return qfalse;
381 
382 	indent++;
383 	for (i = 0; def->fields[i].name; i++)
384 	{
385 		fd = &def->fields[i];
386 		if (!WriteIndent(fp, indent)) return qfalse;
387 		if (fprintf(fp, "%s\t", fd->name) < 0) return qfalse;
388 		p = (void *)(structure + fd->offset);
389 		if (fd->type & FT_ARRAY)
390 		{
391 			num = fd->maxarray;
392 			if (fprintf(fp, "{") < 0) return qfalse;
393 		} //end if
394 		else
395 		{
396 			num = 1;
397 		} //end else
398 		while(num-- > 0)
399 		{
400 			switch(fd->type & FT_TYPE)
401 			{
402 				case FT_CHAR:
403 				{
404 					if (fprintf(fp, "%d", *(char *) p) < 0) return qfalse;
405 					p = (char *) p + sizeof(char);
406 					break;
407 				} //end case
408 				case FT_INT:
409 				{
410 					if (fprintf(fp, "%d", *(int *) p) < 0) return qfalse;
411 					p = (char *) p + sizeof(int);
412 					break;
413 				} //end case
414 				case FT_FLOAT:
415 				{
416 					if (!WriteFloat(fp, *(float *)p)) return qfalse;
417 					p = (char *) p + sizeof(float);
418 					break;
419 				} //end case
420 				case FT_STRING:
421 				{
422 					if (fprintf(fp, "\"%s\"", (char *) p) < 0) return qfalse;
423 					p = (char *) p + MAX_STRINGFIELD;
424 					break;
425 				} //end case
426 				case FT_STRUCT:
427 				{
428 					if (!WriteStructWithIndent(fp, fd->substruct, structure, indent)) return qfalse;
429 					p = (char *) p + fd->substruct->size;
430 					break;
431 				} //end case
432 			} //end switch
433 			if (fd->type & FT_ARRAY)
434 			{
435 				if (num > 0)
436 				{
437 					if (fprintf(fp, ",") < 0) return qfalse;
438 				} //end if
439 				else
440 				{
441 					if (fprintf(fp, "}") < 0) return qfalse;
442 				} //end else
443 			} //end if
444 		} //end while
445 		if (fprintf(fp, "\r\n") < 0) return qfalse;
446 	} //end for
447 	indent--;
448 
449 	if (!WriteIndent(fp, indent)) return qfalse;
450 	if (fprintf(fp, "}\r\n") < 0) return qfalse;
451 	return qtrue;
452 } //end of the function WriteStructWithIndent
453 //===========================================================================
454 //
455 // Parameter:				-
456 // Returns:					-
457 // Changes Globals:		-
458 //===========================================================================
WriteStructure(FILE * fp,structdef_t * def,char * structure)459 int WriteStructure(FILE *fp, structdef_t *def, char *structure)
460 {
461 	return WriteStructWithIndent(fp, def, structure, 0);
462 } //end of the function WriteStructure
463 
464