l_script.c (40381B)
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_script.c 25 * 26 * desc: lexicographical parser 27 * 28 * $Archive: /MissionPack/code/botlib/l_script.c $ 29 * 30 *****************************************************************************/ 31 32 //#define SCREWUP 33 //#define BOTLIB 34 //#define MEQCC 35 //#define BSPC 36 37 #ifdef SCREWUP 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <limits.h> 41 #include <string.h> 42 #include <stdarg.h> 43 #include "l_memory.h" 44 #include "l_script.h" 45 46 typedef enum {qfalse, qtrue} qboolean; 47 48 #endif //SCREWUP 49 50 #ifdef BOTLIB 51 //include files for usage in the bot library 52 #include "../game/q_shared.h" 53 #include "../game/botlib.h" 54 #include "be_interface.h" 55 #include "l_script.h" 56 #include "l_memory.h" 57 #include "l_log.h" 58 #include "l_libvar.h" 59 #endif //BOTLIB 60 61 #ifdef MEQCC 62 //include files for usage in MrElusive's QuakeC Compiler 63 #include "qcc.h" 64 #include "l_script.h" 65 #include "l_memory.h" 66 #include "l_log.h" 67 68 #define qtrue true 69 #define qfalse false 70 #endif //MEQCC 71 72 #ifdef BSPC 73 //include files for usage in the BSP Converter 74 #include "../bspc/qbsp.h" 75 #include "../bspc/l_log.h" 76 #include "../bspc/l_mem.h" 77 78 #define qtrue true 79 #define qfalse false 80 #endif //BSPC 81 82 83 #define PUNCTABLE 84 85 //longer punctuations first 86 punctuation_t default_punctuations[] = 87 { 88 //binary operators 89 {">>=",P_RSHIFT_ASSIGN, NULL}, 90 {"<<=",P_LSHIFT_ASSIGN, NULL}, 91 // 92 {"...",P_PARMS, NULL}, 93 //define merge operator 94 {"##",P_PRECOMPMERGE, NULL}, 95 //logic operators 96 {"&&",P_LOGIC_AND, NULL}, 97 {"||",P_LOGIC_OR, NULL}, 98 {">=",P_LOGIC_GEQ, NULL}, 99 {"<=",P_LOGIC_LEQ, NULL}, 100 {"==",P_LOGIC_EQ, NULL}, 101 {"!=",P_LOGIC_UNEQ, NULL}, 102 //arithmatic operators 103 {"*=",P_MUL_ASSIGN, NULL}, 104 {"/=",P_DIV_ASSIGN, NULL}, 105 {"%=",P_MOD_ASSIGN, NULL}, 106 {"+=",P_ADD_ASSIGN, NULL}, 107 {"-=",P_SUB_ASSIGN, NULL}, 108 {"++",P_INC, NULL}, 109 {"--",P_DEC, NULL}, 110 //binary operators 111 {"&=",P_BIN_AND_ASSIGN, NULL}, 112 {"|=",P_BIN_OR_ASSIGN, NULL}, 113 {"^=",P_BIN_XOR_ASSIGN, NULL}, 114 {">>",P_RSHIFT, NULL}, 115 {"<<",P_LSHIFT, NULL}, 116 //reference operators 117 {"->",P_POINTERREF, NULL}, 118 //C++ 119 {"::",P_CPP1, NULL}, 120 {".*",P_CPP2, NULL}, 121 //arithmatic operators 122 {"*",P_MUL, NULL}, 123 {"/",P_DIV, NULL}, 124 {"%",P_MOD, NULL}, 125 {"+",P_ADD, NULL}, 126 {"-",P_SUB, NULL}, 127 {"=",P_ASSIGN, NULL}, 128 //binary operators 129 {"&",P_BIN_AND, NULL}, 130 {"|",P_BIN_OR, NULL}, 131 {"^",P_BIN_XOR, NULL}, 132 {"~",P_BIN_NOT, NULL}, 133 //logic operators 134 {"!",P_LOGIC_NOT, NULL}, 135 {">",P_LOGIC_GREATER, NULL}, 136 {"<",P_LOGIC_LESS, NULL}, 137 //reference operator 138 {".",P_REF, NULL}, 139 //seperators 140 {",",P_COMMA, NULL}, 141 {";",P_SEMICOLON, NULL}, 142 //label indication 143 {":",P_COLON, NULL}, 144 //if statement 145 {"?",P_QUESTIONMARK, NULL}, 146 //embracements 147 {"(",P_PARENTHESESOPEN, NULL}, 148 {")",P_PARENTHESESCLOSE, NULL}, 149 {"{",P_BRACEOPEN, NULL}, 150 {"}",P_BRACECLOSE, NULL}, 151 {"[",P_SQBRACKETOPEN, NULL}, 152 {"]",P_SQBRACKETCLOSE, NULL}, 153 // 154 {"\\",P_BACKSLASH, NULL}, 155 //precompiler operator 156 {"#",P_PRECOMP, NULL}, 157 #ifdef DOLLAR 158 {"$",P_DOLLAR, NULL}, 159 #endif //DOLLAR 160 {NULL, 0} 161 }; 162 163 #ifdef BSPC 164 char basefolder[MAX_PATH]; 165 #else 166 char basefolder[MAX_QPATH]; 167 #endif 168 169 //=========================================================================== 170 // 171 // Parameter: - 172 // Returns: - 173 // Changes Globals: - 174 //=========================================================================== 175 void PS_CreatePunctuationTable(script_t *script, punctuation_t *punctuations) 176 { 177 int i; 178 punctuation_t *p, *lastp, *newp; 179 180 //get memory for the table 181 if (!script->punctuationtable) script->punctuationtable = (punctuation_t **) 182 GetMemory(256 * sizeof(punctuation_t *)); 183 Com_Memset(script->punctuationtable, 0, 256 * sizeof(punctuation_t *)); 184 //add the punctuations in the list to the punctuation table 185 for (i = 0; punctuations[i].p; i++) 186 { 187 newp = &punctuations[i]; 188 lastp = NULL; 189 //sort the punctuations in this table entry on length (longer punctuations first) 190 for (p = script->punctuationtable[(unsigned int) newp->p[0]]; p; p = p->next) 191 { 192 if (strlen(p->p) < strlen(newp->p)) 193 { 194 newp->next = p; 195 if (lastp) lastp->next = newp; 196 else script->punctuationtable[(unsigned int) newp->p[0]] = newp; 197 break; 198 } //end if 199 lastp = p; 200 } //end for 201 if (!p) 202 { 203 newp->next = NULL; 204 if (lastp) lastp->next = newp; 205 else script->punctuationtable[(unsigned int) newp->p[0]] = newp; 206 } //end if 207 } //end for 208 } //end of the function PS_CreatePunctuationTable 209 //=========================================================================== 210 // 211 // Parameter: - 212 // Returns: - 213 // Changes Globals: - 214 //=========================================================================== 215 char *PunctuationFromNum(script_t *script, int num) 216 { 217 int i; 218 219 for (i = 0; script->punctuations[i].p; i++) 220 { 221 if (script->punctuations[i].n == num) return script->punctuations[i].p; 222 } //end for 223 return "unkown punctuation"; 224 } //end of the function PunctuationFromNum 225 //=========================================================================== 226 // 227 // Parameter: - 228 // Returns: - 229 // Changes Globals: - 230 //=========================================================================== 231 void QDECL ScriptError(script_t *script, char *str, ...) 232 { 233 char text[1024]; 234 va_list ap; 235 236 if (script->flags & SCFL_NOERRORS) return; 237 238 va_start(ap, str); 239 vsprintf(text, str, ap); 240 va_end(ap); 241 #ifdef BOTLIB 242 botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", script->filename, script->line, text); 243 #endif //BOTLIB 244 #ifdef MEQCC 245 printf("error: file %s, line %d: %s\n", script->filename, script->line, text); 246 #endif //MEQCC 247 #ifdef BSPC 248 Log_Print("error: file %s, line %d: %s\n", script->filename, script->line, text); 249 #endif //BSPC 250 } //end of the function ScriptError 251 //=========================================================================== 252 // 253 // Parameter: - 254 // Returns: - 255 // Changes Globals: - 256 //=========================================================================== 257 void QDECL ScriptWarning(script_t *script, char *str, ...) 258 { 259 char text[1024]; 260 va_list ap; 261 262 if (script->flags & SCFL_NOWARNINGS) return; 263 264 va_start(ap, str); 265 vsprintf(text, str, ap); 266 va_end(ap); 267 #ifdef BOTLIB 268 botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", script->filename, script->line, text); 269 #endif //BOTLIB 270 #ifdef MEQCC 271 printf("warning: file %s, line %d: %s\n", script->filename, script->line, text); 272 #endif //MEQCC 273 #ifdef BSPC 274 Log_Print("warning: file %s, line %d: %s\n", script->filename, script->line, text); 275 #endif //BSPC 276 } //end of the function ScriptWarning 277 //=========================================================================== 278 // 279 // Parameter: - 280 // Returns: - 281 // Changes Globals: - 282 //=========================================================================== 283 void SetScriptPunctuations(script_t *script, punctuation_t *p) 284 { 285 #ifdef PUNCTABLE 286 if (p) PS_CreatePunctuationTable(script, p); 287 else PS_CreatePunctuationTable(script, default_punctuations); 288 #endif //PUNCTABLE 289 if (p) script->punctuations = p; 290 else script->punctuations = default_punctuations; 291 } //end of the function SetScriptPunctuations 292 //============================================================================ 293 // Reads spaces, tabs, C-like comments etc. 294 // When a newline character is found the scripts line counter is increased. 295 // 296 // Parameter: - 297 // Returns: - 298 // Changes Globals: - 299 //============================================================================ 300 int PS_ReadWhiteSpace(script_t *script) 301 { 302 while(1) 303 { 304 //skip white space 305 while(*script->script_p <= ' ') 306 { 307 if (!*script->script_p) return 0; 308 if (*script->script_p == '\n') script->line++; 309 script->script_p++; 310 } //end while 311 //skip comments 312 if (*script->script_p == '/') 313 { 314 //comments // 315 if (*(script->script_p+1) == '/') 316 { 317 script->script_p++; 318 do 319 { 320 script->script_p++; 321 if (!*script->script_p) return 0; 322 } //end do 323 while(*script->script_p != '\n'); 324 script->line++; 325 script->script_p++; 326 if (!*script->script_p) return 0; 327 continue; 328 } //end if 329 //comments /* */ 330 else if (*(script->script_p+1) == '*') 331 { 332 script->script_p++; 333 do 334 { 335 script->script_p++; 336 if (!*script->script_p) return 0; 337 if (*script->script_p == '\n') script->line++; 338 } //end do 339 while(!(*script->script_p == '*' && *(script->script_p+1) == '/')); 340 script->script_p++; 341 if (!*script->script_p) return 0; 342 script->script_p++; 343 if (!*script->script_p) return 0; 344 continue; 345 } //end if 346 } //end if 347 break; 348 } //end while 349 return 1; 350 } //end of the function PS_ReadWhiteSpace 351 //============================================================================ 352 // Reads an escape character. 353 // 354 // Parameter: script : script to read from 355 // ch : place to store the read escape character 356 // Returns: - 357 // Changes Globals: - 358 //============================================================================ 359 int PS_ReadEscapeCharacter(script_t *script, char *ch) 360 { 361 int c, val, i; 362 363 //step over the leading '\\' 364 script->script_p++; 365 //determine the escape character 366 switch(*script->script_p) 367 { 368 case '\\': c = '\\'; break; 369 case 'n': c = '\n'; break; 370 case 'r': c = '\r'; break; 371 case 't': c = '\t'; break; 372 case 'v': c = '\v'; break; 373 case 'b': c = '\b'; break; 374 case 'f': c = '\f'; break; 375 case 'a': c = '\a'; break; 376 case '\'': c = '\''; break; 377 case '\"': c = '\"'; break; 378 case '\?': c = '\?'; break; 379 case 'x': 380 { 381 script->script_p++; 382 for (i = 0, val = 0; ; i++, script->script_p++) 383 { 384 c = *script->script_p; 385 if (c >= '0' && c <= '9') c = c - '0'; 386 else if (c >= 'A' && c <= 'Z') c = c - 'A' + 10; 387 else if (c >= 'a' && c <= 'z') c = c - 'a' + 10; 388 else break; 389 val = (val << 4) + c; 390 } //end for 391 script->script_p--; 392 if (val > 0xFF) 393 { 394 ScriptWarning(script, "too large value in escape character"); 395 val = 0xFF; 396 } //end if 397 c = val; 398 break; 399 } //end case 400 default: //NOTE: decimal ASCII code, NOT octal 401 { 402 if (*script->script_p < '0' || *script->script_p > '9') ScriptError(script, "unknown escape char"); 403 for (i = 0, val = 0; ; i++, script->script_p++) 404 { 405 c = *script->script_p; 406 if (c >= '0' && c <= '9') c = c - '0'; 407 else break; 408 val = val * 10 + c; 409 } //end for 410 script->script_p--; 411 if (val > 0xFF) 412 { 413 ScriptWarning(script, "too large value in escape character"); 414 val = 0xFF; 415 } //end if 416 c = val; 417 break; 418 } //end default 419 } //end switch 420 //step over the escape character or the last digit of the number 421 script->script_p++; 422 //store the escape character 423 *ch = c; 424 //succesfully read escape character 425 return 1; 426 } //end of the function PS_ReadEscapeCharacter 427 //============================================================================ 428 // Reads C-like string. Escape characters are interpretted. 429 // Quotes are included with the string. 430 // Reads two strings with a white space between them as one string. 431 // 432 // Parameter: script : script to read from 433 // token : buffer to store the string 434 // Returns: qtrue when a string was read succesfully 435 // Changes Globals: - 436 //============================================================================ 437 int PS_ReadString(script_t *script, token_t *token, int quote) 438 { 439 int len, tmpline; 440 char *tmpscript_p; 441 442 if (quote == '\"') token->type = TT_STRING; 443 else token->type = TT_LITERAL; 444 445 len = 0; 446 //leading quote 447 token->string[len++] = *script->script_p++; 448 // 449 while(1) 450 { 451 //minus 2 because trailing double quote and zero have to be appended 452 if (len >= MAX_TOKEN - 2) 453 { 454 ScriptError(script, "string longer than MAX_TOKEN = %d", MAX_TOKEN); 455 return 0; 456 } //end if 457 //if there is an escape character and 458 //if escape characters inside a string are allowed 459 if (*script->script_p == '\\' && !(script->flags & SCFL_NOSTRINGESCAPECHARS)) 460 { 461 if (!PS_ReadEscapeCharacter(script, &token->string[len])) 462 { 463 token->string[len] = 0; 464 return 0; 465 } //end if 466 len++; 467 } //end if 468 //if a trailing quote 469 else if (*script->script_p == quote) 470 { 471 //step over the double quote 472 script->script_p++; 473 //if white spaces in a string are not allowed 474 if (script->flags & SCFL_NOSTRINGWHITESPACES) break; 475 // 476 tmpscript_p = script->script_p; 477 tmpline = script->line; 478 //read unusefull stuff between possible two following strings 479 if (!PS_ReadWhiteSpace(script)) 480 { 481 script->script_p = tmpscript_p; 482 script->line = tmpline; 483 break; 484 } //end if 485 //if there's no leading double qoute 486 if (*script->script_p != quote) 487 { 488 script->script_p = tmpscript_p; 489 script->line = tmpline; 490 break; 491 } //end if 492 //step over the new leading double quote 493 script->script_p++; 494 } //end if 495 else 496 { 497 if (*script->script_p == '\0') 498 { 499 token->string[len] = 0; 500 ScriptError(script, "missing trailing quote"); 501 return 0; 502 } //end if 503 if (*script->script_p == '\n') 504 { 505 token->string[len] = 0; 506 ScriptError(script, "newline inside string %s", token->string); 507 return 0; 508 } //end if 509 token->string[len++] = *script->script_p++; 510 } //end else 511 } //end while 512 //trailing quote 513 token->string[len++] = quote; 514 //end string with a zero 515 token->string[len] = '\0'; 516 //the sub type is the length of the string 517 token->subtype = len; 518 return 1; 519 } //end of the function PS_ReadString 520 //============================================================================ 521 // 522 // Parameter: - 523 // Returns: - 524 // Changes Globals: - 525 //============================================================================ 526 int PS_ReadName(script_t *script, token_t *token) 527 { 528 int len = 0; 529 char c; 530 531 token->type = TT_NAME; 532 do 533 { 534 token->string[len++] = *script->script_p++; 535 if (len >= MAX_TOKEN) 536 { 537 ScriptError(script, "name longer than MAX_TOKEN = %d", MAX_TOKEN); 538 return 0; 539 } //end if 540 c = *script->script_p; 541 } while ((c >= 'a' && c <= 'z') || 542 (c >= 'A' && c <= 'Z') || 543 (c >= '0' && c <= '9') || 544 c == '_'); 545 token->string[len] = '\0'; 546 //the sub type is the length of the name 547 token->subtype = len; 548 return 1; 549 } //end of the function PS_ReadName 550 //============================================================================ 551 // 552 // Parameter: - 553 // Returns: - 554 // Changes Globals: - 555 //============================================================================ 556 void NumberValue(char *string, int subtype, unsigned long int *intvalue, 557 long double *floatvalue) 558 { 559 unsigned long int dotfound = 0; 560 561 *intvalue = 0; 562 *floatvalue = 0; 563 //floating point number 564 if (subtype & TT_FLOAT) 565 { 566 while(*string) 567 { 568 if (*string == '.') 569 { 570 if (dotfound) return; 571 dotfound = 10; 572 string++; 573 } //end if 574 if (dotfound) 575 { 576 *floatvalue = *floatvalue + (long double) (*string - '0') / 577 (long double) dotfound; 578 dotfound *= 10; 579 } //end if 580 else 581 { 582 *floatvalue = *floatvalue * 10.0 + (long double) (*string - '0'); 583 } //end else 584 string++; 585 } //end while 586 *intvalue = (unsigned long) *floatvalue; 587 } //end if 588 else if (subtype & TT_DECIMAL) 589 { 590 while(*string) *intvalue = *intvalue * 10 + (*string++ - '0'); 591 *floatvalue = *intvalue; 592 } //end else if 593 else if (subtype & TT_HEX) 594 { 595 //step over the leading 0x or 0X 596 string += 2; 597 while(*string) 598 { 599 *intvalue <<= 4; 600 if (*string >= 'a' && *string <= 'f') *intvalue += *string - 'a' + 10; 601 else if (*string >= 'A' && *string <= 'F') *intvalue += *string - 'A' + 10; 602 else *intvalue += *string - '0'; 603 string++; 604 } //end while 605 *floatvalue = *intvalue; 606 } //end else if 607 else if (subtype & TT_OCTAL) 608 { 609 //step over the first zero 610 string += 1; 611 while(*string) *intvalue = (*intvalue << 3) + (*string++ - '0'); 612 *floatvalue = *intvalue; 613 } //end else if 614 else if (subtype & TT_BINARY) 615 { 616 //step over the leading 0b or 0B 617 string += 2; 618 while(*string) *intvalue = (*intvalue << 1) + (*string++ - '0'); 619 *floatvalue = *intvalue; 620 } //end else if 621 } //end of the function NumberValue 622 //============================================================================ 623 // 624 // Parameter: - 625 // Returns: - 626 // Changes Globals: - 627 //============================================================================ 628 int PS_ReadNumber(script_t *script, token_t *token) 629 { 630 int len = 0, i; 631 int octal, dot; 632 char c; 633 // unsigned long int intvalue = 0; 634 // long double floatvalue = 0; 635 636 token->type = TT_NUMBER; 637 //check for a hexadecimal number 638 if (*script->script_p == '0' && 639 (*(script->script_p + 1) == 'x' || 640 *(script->script_p + 1) == 'X')) 641 { 642 token->string[len++] = *script->script_p++; 643 token->string[len++] = *script->script_p++; 644 c = *script->script_p; 645 //hexadecimal 646 while((c >= '0' && c <= '9') || 647 (c >= 'a' && c <= 'f') || 648 (c >= 'A' && c <= 'A')) 649 { 650 token->string[len++] = *script->script_p++; 651 if (len >= MAX_TOKEN) 652 { 653 ScriptError(script, "hexadecimal number longer than MAX_TOKEN = %d", MAX_TOKEN); 654 return 0; 655 } //end if 656 c = *script->script_p; 657 } //end while 658 token->subtype |= TT_HEX; 659 } //end if 660 #ifdef BINARYNUMBERS 661 //check for a binary number 662 else if (*script->script_p == '0' && 663 (*(script->script_p + 1) == 'b' || 664 *(script->script_p + 1) == 'B')) 665 { 666 token->string[len++] = *script->script_p++; 667 token->string[len++] = *script->script_p++; 668 c = *script->script_p; 669 //binary 670 while(c == '0' || c == '1') 671 { 672 token->string[len++] = *script->script_p++; 673 if (len >= MAX_TOKEN) 674 { 675 ScriptError(script, "binary number longer than MAX_TOKEN = %d", MAX_TOKEN); 676 return 0; 677 } //end if 678 c = *script->script_p; 679 } //end while 680 token->subtype |= TT_BINARY; 681 } //end if 682 #endif //BINARYNUMBERS 683 else //decimal or octal integer or floating point number 684 { 685 octal = qfalse; 686 dot = qfalse; 687 if (*script->script_p == '0') octal = qtrue; 688 while(1) 689 { 690 c = *script->script_p; 691 if (c == '.') dot = qtrue; 692 else if (c == '8' || c == '9') octal = qfalse; 693 else if (c < '0' || c > '9') break; 694 token->string[len++] = *script->script_p++; 695 if (len >= MAX_TOKEN - 1) 696 { 697 ScriptError(script, "number longer than MAX_TOKEN = %d", MAX_TOKEN); 698 return 0; 699 } //end if 700 } //end while 701 if (octal) token->subtype |= TT_OCTAL; 702 else token->subtype |= TT_DECIMAL; 703 if (dot) token->subtype |= TT_FLOAT; 704 } //end else 705 for (i = 0; i < 2; i++) 706 { 707 c = *script->script_p; 708 //check for a LONG number 709 if ( (c == 'l' || c == 'L') // bk001204 - brackets 710 && !(token->subtype & TT_LONG)) 711 { 712 script->script_p++; 713 token->subtype |= TT_LONG; 714 } //end if 715 //check for an UNSIGNED number 716 else if ( (c == 'u' || c == 'U') // bk001204 - brackets 717 && !(token->subtype & (TT_UNSIGNED | TT_FLOAT))) 718 { 719 script->script_p++; 720 token->subtype |= TT_UNSIGNED; 721 } //end if 722 } //end for 723 token->string[len] = '\0'; 724 #ifdef NUMBERVALUE 725 NumberValue(token->string, token->subtype, &token->intvalue, &token->floatvalue); 726 #endif //NUMBERVALUE 727 if (!(token->subtype & TT_FLOAT)) token->subtype |= TT_INTEGER; 728 return 1; 729 } //end of the function PS_ReadNumber 730 //============================================================================ 731 // 732 // Parameter: - 733 // Returns: - 734 // Changes Globals: - 735 //============================================================================ 736 int PS_ReadLiteral(script_t *script, token_t *token) 737 { 738 token->type = TT_LITERAL; 739 //first quote 740 token->string[0] = *script->script_p++; 741 //check for end of file 742 if (!*script->script_p) 743 { 744 ScriptError(script, "end of file before trailing \'"); 745 return 0; 746 } //end if 747 //if it is an escape character 748 if (*script->script_p == '\\') 749 { 750 if (!PS_ReadEscapeCharacter(script, &token->string[1])) return 0; 751 } //end if 752 else 753 { 754 token->string[1] = *script->script_p++; 755 } //end else 756 //check for trailing quote 757 if (*script->script_p != '\'') 758 { 759 ScriptWarning(script, "too many characters in literal, ignored"); 760 while(*script->script_p && 761 *script->script_p != '\'' && 762 *script->script_p != '\n') 763 { 764 script->script_p++; 765 } //end while 766 if (*script->script_p == '\'') script->script_p++; 767 } //end if 768 //store the trailing quote 769 token->string[2] = *script->script_p++; 770 //store trailing zero to end the string 771 token->string[3] = '\0'; 772 //the sub type is the integer literal value 773 token->subtype = token->string[1]; 774 // 775 return 1; 776 } //end of the function PS_ReadLiteral 777 //============================================================================ 778 // 779 // Parameter: - 780 // Returns: - 781 // Changes Globals: - 782 //============================================================================ 783 int PS_ReadPunctuation(script_t *script, token_t *token) 784 { 785 int len; 786 char *p; 787 punctuation_t *punc; 788 789 #ifdef PUNCTABLE 790 for (punc = script->punctuationtable[(unsigned int)*script->script_p]; punc; punc = punc->next) 791 { 792 #else 793 int i; 794 795 for (i = 0; script->punctuations[i].p; i++) 796 { 797 punc = &script->punctuations[i]; 798 #endif //PUNCTABLE 799 p = punc->p; 800 len = strlen(p); 801 //if the script contains at least as much characters as the punctuation 802 if (script->script_p + len <= script->end_p) 803 { 804 //if the script contains the punctuation 805 if (!strncmp(script->script_p, p, len)) 806 { 807 strncpy(token->string, p, MAX_TOKEN); 808 script->script_p += len; 809 token->type = TT_PUNCTUATION; 810 //sub type is the number of the punctuation 811 token->subtype = punc->n; 812 return 1; 813 } //end if 814 } //end if 815 } //end for 816 return 0; 817 } //end of the function PS_ReadPunctuation 818 //============================================================================ 819 // 820 // Parameter: - 821 // Returns: - 822 // Changes Globals: - 823 //============================================================================ 824 int PS_ReadPrimitive(script_t *script, token_t *token) 825 { 826 int len; 827 828 len = 0; 829 while(*script->script_p > ' ' && *script->script_p != ';') 830 { 831 if (len >= MAX_TOKEN) 832 { 833 ScriptError(script, "primitive token longer than MAX_TOKEN = %d", MAX_TOKEN); 834 return 0; 835 } //end if 836 token->string[len++] = *script->script_p++; 837 } //end while 838 token->string[len] = 0; 839 //copy the token into the script structure 840 Com_Memcpy(&script->token, token, sizeof(token_t)); 841 //primitive reading successfull 842 return 1; 843 } //end of the function PS_ReadPrimitive 844 //============================================================================ 845 // 846 // Parameter: - 847 // Returns: - 848 // Changes Globals: - 849 //============================================================================ 850 int PS_ReadToken(script_t *script, token_t *token) 851 { 852 //if there is a token available (from UnreadToken) 853 if (script->tokenavailable) 854 { 855 script->tokenavailable = 0; 856 Com_Memcpy(token, &script->token, sizeof(token_t)); 857 return 1; 858 } //end if 859 //save script pointer 860 script->lastscript_p = script->script_p; 861 //save line counter 862 script->lastline = script->line; 863 //clear the token stuff 864 Com_Memset(token, 0, sizeof(token_t)); 865 //start of the white space 866 script->whitespace_p = script->script_p; 867 token->whitespace_p = script->script_p; 868 //read unusefull stuff 869 if (!PS_ReadWhiteSpace(script)) return 0; 870 //end of the white space 871 script->endwhitespace_p = script->script_p; 872 token->endwhitespace_p = script->script_p; 873 //line the token is on 874 token->line = script->line; 875 //number of lines crossed before token 876 token->linescrossed = script->line - script->lastline; 877 //if there is a leading double quote 878 if (*script->script_p == '\"') 879 { 880 if (!PS_ReadString(script, token, '\"')) return 0; 881 } //end if 882 //if an literal 883 else if (*script->script_p == '\'') 884 { 885 //if (!PS_ReadLiteral(script, token)) return 0; 886 if (!PS_ReadString(script, token, '\'')) return 0; 887 } //end if 888 //if there is a number 889 else if ((*script->script_p >= '0' && *script->script_p <= '9') || 890 (*script->script_p == '.' && 891 (*(script->script_p + 1) >= '0' && *(script->script_p + 1) <= '9'))) 892 { 893 if (!PS_ReadNumber(script, token)) return 0; 894 } //end if 895 //if this is a primitive script 896 else if (script->flags & SCFL_PRIMITIVE) 897 { 898 return PS_ReadPrimitive(script, token); 899 } //end else if 900 //if there is a name 901 else if ((*script->script_p >= 'a' && *script->script_p <= 'z') || 902 (*script->script_p >= 'A' && *script->script_p <= 'Z') || 903 *script->script_p == '_') 904 { 905 if (!PS_ReadName(script, token)) return 0; 906 } //end if 907 //check for punctuations 908 else if (!PS_ReadPunctuation(script, token)) 909 { 910 ScriptError(script, "can't read token"); 911 return 0; 912 } //end if 913 //copy the token into the script structure 914 Com_Memcpy(&script->token, token, sizeof(token_t)); 915 //succesfully read a token 916 return 1; 917 } //end of the function PS_ReadToken 918 //============================================================================ 919 // 920 // Parameter: - 921 // Returns: - 922 // Changes Globals: - 923 //============================================================================ 924 int PS_ExpectTokenString(script_t *script, char *string) 925 { 926 token_t token; 927 928 if (!PS_ReadToken(script, &token)) 929 { 930 ScriptError(script, "couldn't find expected %s", string); 931 return 0; 932 } //end if 933 934 if (strcmp(token.string, string)) 935 { 936 ScriptError(script, "expected %s, found %s", string, token.string); 937 return 0; 938 } //end if 939 return 1; 940 } //end of the function PS_ExpectToken 941 //============================================================================ 942 // 943 // Parameter: - 944 // Returns: - 945 // Changes Globals: - 946 //============================================================================ 947 int PS_ExpectTokenType(script_t *script, int type, int subtype, token_t *token) 948 { 949 char str[MAX_TOKEN]; 950 951 if (!PS_ReadToken(script, token)) 952 { 953 ScriptError(script, "couldn't read expected token"); 954 return 0; 955 } //end if 956 957 if (token->type != type) 958 { 959 if (type == TT_STRING) strcpy(str, "string"); 960 if (type == TT_LITERAL) strcpy(str, "literal"); 961 if (type == TT_NUMBER) strcpy(str, "number"); 962 if (type == TT_NAME) strcpy(str, "name"); 963 if (type == TT_PUNCTUATION) strcpy(str, "punctuation"); 964 ScriptError(script, "expected a %s, found %s", str, token->string); 965 return 0; 966 } //end if 967 if (token->type == TT_NUMBER) 968 { 969 if ((token->subtype & subtype) != subtype) 970 { 971 if (subtype & TT_DECIMAL) strcpy(str, "decimal"); 972 if (subtype & TT_HEX) strcpy(str, "hex"); 973 if (subtype & TT_OCTAL) strcpy(str, "octal"); 974 if (subtype & TT_BINARY) strcpy(str, "binary"); 975 if (subtype & TT_LONG) strcat(str, " long"); 976 if (subtype & TT_UNSIGNED) strcat(str, " unsigned"); 977 if (subtype & TT_FLOAT) strcat(str, " float"); 978 if (subtype & TT_INTEGER) strcat(str, " integer"); 979 ScriptError(script, "expected %s, found %s", str, token->string); 980 return 0; 981 } //end if 982 } //end if 983 else if (token->type == TT_PUNCTUATION) 984 { 985 if (subtype < 0) 986 { 987 ScriptError(script, "BUG: wrong punctuation subtype"); 988 return 0; 989 } //end if 990 if (token->subtype != subtype) 991 { 992 ScriptError(script, "expected %s, found %s", 993 script->punctuations[subtype], token->string); 994 return 0; 995 } //end if 996 } //end else if 997 return 1; 998 } //end of the function PS_ExpectTokenType 999 //============================================================================ 1000 // 1001 // Parameter: - 1002 // Returns: - 1003 // Changes Globals: - 1004 //============================================================================ 1005 int PS_ExpectAnyToken(script_t *script, token_t *token) 1006 { 1007 if (!PS_ReadToken(script, token)) 1008 { 1009 ScriptError(script, "couldn't read expected token"); 1010 return 0; 1011 } //end if 1012 else 1013 { 1014 return 1; 1015 } //end else 1016 } //end of the function PS_ExpectAnyToken 1017 //============================================================================ 1018 // 1019 // Parameter: - 1020 // Returns: - 1021 // Changes Globals: - 1022 //============================================================================ 1023 int PS_CheckTokenString(script_t *script, char *string) 1024 { 1025 token_t tok; 1026 1027 if (!PS_ReadToken(script, &tok)) return 0; 1028 //if the token is available 1029 if (!strcmp(tok.string, string)) return 1; 1030 //token not available 1031 script->script_p = script->lastscript_p; 1032 return 0; 1033 } //end of the function PS_CheckTokenString 1034 //============================================================================ 1035 // 1036 // Parameter: - 1037 // Returns: - 1038 // Changes Globals: - 1039 //============================================================================ 1040 int PS_CheckTokenType(script_t *script, int type, int subtype, token_t *token) 1041 { 1042 token_t tok; 1043 1044 if (!PS_ReadToken(script, &tok)) return 0; 1045 //if the type matches 1046 if (tok.type == type && 1047 (tok.subtype & subtype) == subtype) 1048 { 1049 Com_Memcpy(token, &tok, sizeof(token_t)); 1050 return 1; 1051 } //end if 1052 //token is not available 1053 script->script_p = script->lastscript_p; 1054 return 0; 1055 } //end of the function PS_CheckTokenType 1056 //============================================================================ 1057 // 1058 // Parameter: - 1059 // Returns: - 1060 // Changes Globals: - 1061 //============================================================================ 1062 int PS_SkipUntilString(script_t *script, char *string) 1063 { 1064 token_t token; 1065 1066 while(PS_ReadToken(script, &token)) 1067 { 1068 if (!strcmp(token.string, string)) return 1; 1069 } //end while 1070 return 0; 1071 } //end of the function PS_SkipUntilString 1072 //============================================================================ 1073 // 1074 // Parameter: - 1075 // Returns: - 1076 // Changes Globals: - 1077 //============================================================================ 1078 void PS_UnreadLastToken(script_t *script) 1079 { 1080 script->tokenavailable = 1; 1081 } //end of the function UnreadLastToken 1082 //============================================================================ 1083 // 1084 // Parameter: - 1085 // Returns: - 1086 // Changes Globals: - 1087 //============================================================================ 1088 void PS_UnreadToken(script_t *script, token_t *token) 1089 { 1090 Com_Memcpy(&script->token, token, sizeof(token_t)); 1091 script->tokenavailable = 1; 1092 } //end of the function UnreadToken 1093 //============================================================================ 1094 // returns the next character of the read white space, returns NULL if none 1095 // 1096 // Parameter: - 1097 // Returns: - 1098 // Changes Globals: - 1099 //============================================================================ 1100 char PS_NextWhiteSpaceChar(script_t *script) 1101 { 1102 if (script->whitespace_p != script->endwhitespace_p) 1103 { 1104 return *script->whitespace_p++; 1105 } //end if 1106 else 1107 { 1108 return 0; 1109 } //end else 1110 } //end of the function PS_NextWhiteSpaceChar 1111 //============================================================================ 1112 // 1113 // Parameter: - 1114 // Returns: - 1115 // Changes Globals: - 1116 //============================================================================ 1117 void StripDoubleQuotes(char *string) 1118 { 1119 if (*string == '\"') 1120 { 1121 strcpy(string, string+1); 1122 } //end if 1123 if (string[strlen(string)-1] == '\"') 1124 { 1125 string[strlen(string)-1] = '\0'; 1126 } //end if 1127 } //end of the function StripDoubleQuotes 1128 //============================================================================ 1129 // 1130 // Parameter: - 1131 // Returns: - 1132 // Changes Globals: - 1133 //============================================================================ 1134 void StripSingleQuotes(char *string) 1135 { 1136 if (*string == '\'') 1137 { 1138 strcpy(string, string+1); 1139 } //end if 1140 if (string[strlen(string)-1] == '\'') 1141 { 1142 string[strlen(string)-1] = '\0'; 1143 } //end if 1144 } //end of the function StripSingleQuotes 1145 //============================================================================ 1146 // 1147 // Parameter: - 1148 // Returns: - 1149 // Changes Globals: - 1150 //============================================================================ 1151 long double ReadSignedFloat(script_t *script) 1152 { 1153 token_t token; 1154 long double sign = 1; 1155 1156 PS_ExpectAnyToken(script, &token); 1157 if (!strcmp(token.string, "-")) 1158 { 1159 sign = -1; 1160 PS_ExpectTokenType(script, TT_NUMBER, 0, &token); 1161 } //end if 1162 else if (token.type != TT_NUMBER) 1163 { 1164 ScriptError(script, "expected float value, found %s\n", token.string); 1165 } //end else if 1166 return sign * token.floatvalue; 1167 } //end of the function ReadSignedFloat 1168 //============================================================================ 1169 // 1170 // Parameter: - 1171 // Returns: - 1172 // Changes Globals: - 1173 //============================================================================ 1174 signed long int ReadSignedInt(script_t *script) 1175 { 1176 token_t token; 1177 signed long int sign = 1; 1178 1179 PS_ExpectAnyToken(script, &token); 1180 if (!strcmp(token.string, "-")) 1181 { 1182 sign = -1; 1183 PS_ExpectTokenType(script, TT_NUMBER, TT_INTEGER, &token); 1184 } //end if 1185 else if (token.type != TT_NUMBER || token.subtype == TT_FLOAT) 1186 { 1187 ScriptError(script, "expected integer value, found %s\n", token.string); 1188 } //end else if 1189 return sign * token.intvalue; 1190 } //end of the function ReadSignedInt 1191 //============================================================================ 1192 // 1193 // Parameter: - 1194 // Returns: - 1195 // Changes Globals: - 1196 //============================================================================ 1197 void SetScriptFlags(script_t *script, int flags) 1198 { 1199 script->flags = flags; 1200 } //end of the function SetScriptFlags 1201 //============================================================================ 1202 // 1203 // Parameter: - 1204 // Returns: - 1205 // Changes Globals: - 1206 //============================================================================ 1207 int GetScriptFlags(script_t *script) 1208 { 1209 return script->flags; 1210 } //end of the function GetScriptFlags 1211 //============================================================================ 1212 // 1213 // Parameter: - 1214 // Returns: - 1215 // Changes Globals: - 1216 //============================================================================ 1217 void ResetScript(script_t *script) 1218 { 1219 //pointer in script buffer 1220 script->script_p = script->buffer; 1221 //pointer in script buffer before reading token 1222 script->lastscript_p = script->buffer; 1223 //begin of white space 1224 script->whitespace_p = NULL; 1225 //end of white space 1226 script->endwhitespace_p = NULL; 1227 //set if there's a token available in script->token 1228 script->tokenavailable = 0; 1229 // 1230 script->line = 1; 1231 script->lastline = 1; 1232 //clear the saved token 1233 Com_Memset(&script->token, 0, sizeof(token_t)); 1234 } //end of the function ResetScript 1235 //============================================================================ 1236 // returns true if at the end of the script 1237 // 1238 // Parameter: - 1239 // Returns: - 1240 // Changes Globals: - 1241 //============================================================================ 1242 int EndOfScript(script_t *script) 1243 { 1244 return script->script_p >= script->end_p; 1245 } //end of the function EndOfScript 1246 //============================================================================ 1247 // 1248 // Parameter: - 1249 // Returns: - 1250 // Changes Globals: - 1251 //============================================================================ 1252 int NumLinesCrossed(script_t *script) 1253 { 1254 return script->line - script->lastline; 1255 } //end of the function NumLinesCrossed 1256 //============================================================================ 1257 // 1258 // Parameter: - 1259 // Returns: - 1260 // Changes Globals: - 1261 //============================================================================ 1262 int ScriptSkipTo(script_t *script, char *value) 1263 { 1264 int len; 1265 char firstchar; 1266 1267 firstchar = *value; 1268 len = strlen(value); 1269 do 1270 { 1271 if (!PS_ReadWhiteSpace(script)) return 0; 1272 if (*script->script_p == firstchar) 1273 { 1274 if (!strncmp(script->script_p, value, len)) 1275 { 1276 return 1; 1277 } //end if 1278 } //end if 1279 script->script_p++; 1280 } while(1); 1281 } //end of the function ScriptSkipTo 1282 #ifndef BOTLIB 1283 //============================================================================ 1284 // 1285 // Parameter: - 1286 // Returns: - 1287 // Changes Globals: - 1288 //============================================================================ 1289 int FileLength(FILE *fp) 1290 { 1291 int pos; 1292 int end; 1293 1294 pos = ftell(fp); 1295 fseek(fp, 0, SEEK_END); 1296 end = ftell(fp); 1297 fseek(fp, pos, SEEK_SET); 1298 1299 return end; 1300 } //end of the function FileLength 1301 #endif 1302 //============================================================================ 1303 // 1304 // Parameter: - 1305 // Returns: - 1306 // Changes Globals: - 1307 //============================================================================ 1308 script_t *LoadScriptFile(const char *filename) 1309 { 1310 #ifdef BOTLIB 1311 fileHandle_t fp; 1312 char pathname[MAX_QPATH]; 1313 #else 1314 FILE *fp; 1315 #endif 1316 int length; 1317 void *buffer; 1318 script_t *script; 1319 1320 #ifdef BOTLIB 1321 if (strlen(basefolder)) 1322 Com_sprintf(pathname, sizeof(pathname), "%s/%s", basefolder, filename); 1323 else 1324 Com_sprintf(pathname, sizeof(pathname), "%s", filename); 1325 length = botimport.FS_FOpenFile( pathname, &fp, FS_READ ); 1326 if (!fp) return NULL; 1327 #else 1328 fp = fopen(filename, "rb"); 1329 if (!fp) return NULL; 1330 1331 length = FileLength(fp); 1332 #endif 1333 1334 buffer = GetClearedMemory(sizeof(script_t) + length + 1); 1335 script = (script_t *) buffer; 1336 Com_Memset(script, 0, sizeof(script_t)); 1337 strcpy(script->filename, filename); 1338 script->buffer = (char *) buffer + sizeof(script_t); 1339 script->buffer[length] = 0; 1340 script->length = length; 1341 //pointer in script buffer 1342 script->script_p = script->buffer; 1343 //pointer in script buffer before reading token 1344 script->lastscript_p = script->buffer; 1345 //pointer to end of script buffer 1346 script->end_p = &script->buffer[length]; 1347 //set if there's a token available in script->token 1348 script->tokenavailable = 0; 1349 // 1350 script->line = 1; 1351 script->lastline = 1; 1352 // 1353 SetScriptPunctuations(script, NULL); 1354 // 1355 #ifdef BOTLIB 1356 botimport.FS_Read(script->buffer, length, fp); 1357 botimport.FS_FCloseFile(fp); 1358 #else 1359 if (fread(script->buffer, length, 1, fp) != 1) 1360 { 1361 FreeMemory(buffer); 1362 script = NULL; 1363 } //end if 1364 fclose(fp); 1365 #endif 1366 // 1367 script->length = COM_Compress(script->buffer); 1368 1369 return script; 1370 } //end of the function LoadScriptFile 1371 //============================================================================ 1372 // 1373 // Parameter: - 1374 // Returns: - 1375 // Changes Globals: - 1376 //============================================================================ 1377 script_t *LoadScriptMemory(char *ptr, int length, char *name) 1378 { 1379 void *buffer; 1380 script_t *script; 1381 1382 buffer = GetClearedMemory(sizeof(script_t) + length + 1); 1383 script = (script_t *) buffer; 1384 Com_Memset(script, 0, sizeof(script_t)); 1385 strcpy(script->filename, name); 1386 script->buffer = (char *) buffer + sizeof(script_t); 1387 script->buffer[length] = 0; 1388 script->length = length; 1389 //pointer in script buffer 1390 script->script_p = script->buffer; 1391 //pointer in script buffer before reading token 1392 script->lastscript_p = script->buffer; 1393 //pointer to end of script buffer 1394 script->end_p = &script->buffer[length]; 1395 //set if there's a token available in script->token 1396 script->tokenavailable = 0; 1397 // 1398 script->line = 1; 1399 script->lastline = 1; 1400 // 1401 SetScriptPunctuations(script, NULL); 1402 // 1403 Com_Memcpy(script->buffer, ptr, length); 1404 // 1405 return script; 1406 } //end of the function LoadScriptMemory 1407 //============================================================================ 1408 // 1409 // Parameter: - 1410 // Returns: - 1411 // Changes Globals: - 1412 //============================================================================ 1413 void FreeScript(script_t *script) 1414 { 1415 #ifdef PUNCTABLE 1416 if (script->punctuationtable) FreeMemory(script->punctuationtable); 1417 #endif //PUNCTABLE 1418 FreeMemory(script); 1419 } //end of the function FreeScript 1420 //============================================================================ 1421 // 1422 // Parameter: - 1423 // Returns: - 1424 // Changes Globals: - 1425 //============================================================================ 1426 void PS_SetBaseFolder(char *path) 1427 { 1428 #ifdef BSPC 1429 sprintf(basefolder, path); 1430 #else 1431 Com_sprintf(basefolder, sizeof(basefolder), path); 1432 #endif 1433 } //end of the function PS_SetBaseFolder