l_struct.c (12367B)
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 Foobar; 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 "../game/q_shared.h" 34 #include "../game/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 //=========================================================================== 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 //=========================================================================== 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 //=========================================================================== 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 //=========================================================================== 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 //=========================================================================== 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 //=========================================================================== 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 //=========================================================================== 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 //=========================================================================== 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 //=========================================================================== 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