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