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