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