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