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