1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 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 Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 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 Doom 3 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 #include "sys/platform.h"
30 #include "idlib/Heap.h"
31 #include "framework/Common.h"
32 #include "framework/FileSystem.h"
33
34 #include "idlib/Lexer.h"
35
36 #define PUNCTABLE
37
38 //longer punctuations first
39 static const punctuation_t default_punctuations[] = {
40 //binary operators
41 {">>=",P_RSHIFT_ASSIGN},
42 {"<<=",P_LSHIFT_ASSIGN},
43 //
44 {"...",P_PARMS},
45 //define merge operator
46 {"##",P_PRECOMPMERGE}, // pre-compiler
47 //logic operators
48 {"&&",P_LOGIC_AND}, // pre-compiler
49 {"||",P_LOGIC_OR}, // pre-compiler
50 {">=",P_LOGIC_GEQ}, // pre-compiler
51 {"<=",P_LOGIC_LEQ}, // pre-compiler
52 {"==",P_LOGIC_EQ}, // pre-compiler
53 {"!=",P_LOGIC_UNEQ}, // pre-compiler
54 //arithmatic operators
55 {"*=",P_MUL_ASSIGN},
56 {"/=",P_DIV_ASSIGN},
57 {"%=",P_MOD_ASSIGN},
58 {"+=",P_ADD_ASSIGN},
59 {"-=",P_SUB_ASSIGN},
60 {"++",P_INC},
61 {"--",P_DEC},
62 //binary operators
63 {"&=",P_BIN_AND_ASSIGN},
64 {"|=",P_BIN_OR_ASSIGN},
65 {"^=",P_BIN_XOR_ASSIGN},
66 {">>",P_RSHIFT}, // pre-compiler
67 {"<<",P_LSHIFT}, // pre-compiler
68 //reference operators
69 {"->",P_POINTERREF},
70 //C++
71 {"::",P_CPP1},
72 {".*",P_CPP2},
73 //arithmatic operators
74 {"*",P_MUL}, // pre-compiler
75 {"/",P_DIV}, // pre-compiler
76 {"%",P_MOD}, // pre-compiler
77 {"+",P_ADD}, // pre-compiler
78 {"-",P_SUB}, // pre-compiler
79 {"=",P_ASSIGN},
80 //binary operators
81 {"&",P_BIN_AND}, // pre-compiler
82 {"|",P_BIN_OR}, // pre-compiler
83 {"^",P_BIN_XOR}, // pre-compiler
84 {"~",P_BIN_NOT}, // pre-compiler
85 //logic operators
86 {"!",P_LOGIC_NOT}, // pre-compiler
87 {">",P_LOGIC_GREATER}, // pre-compiler
88 {"<",P_LOGIC_LESS}, // pre-compiler
89 //reference operator
90 {".",P_REF},
91 //seperators
92 {",",P_COMMA}, // pre-compiler
93 {";",P_SEMICOLON},
94 //label indication
95 {":",P_COLON}, // pre-compiler
96 //if statement
97 {"?",P_QUESTIONMARK}, // pre-compiler
98 //embracements
99 {"(",P_PARENTHESESOPEN}, // pre-compiler
100 {")",P_PARENTHESESCLOSE}, // pre-compiler
101 {"{",P_BRACEOPEN}, // pre-compiler
102 {"}",P_BRACECLOSE}, // pre-compiler
103 {"[",P_SQBRACKETOPEN},
104 {"]",P_SQBRACKETCLOSE},
105 //
106 {"\\",P_BACKSLASH},
107 //precompiler operator
108 {"#",P_PRECOMP}, // pre-compiler
109 {"$",P_DOLLAR},
110 {NULL, 0}
111 };
112
113 int default_punctuationtable[256];
114 int default_nextpunctuation[sizeof(default_punctuations) / sizeof(punctuation_t)];
115 int default_setup;
116
117 char idLexer::baseFolder[ 256 ];
118
119 /*
120 ================
121 idLexer::CreatePunctuationTable
122 ================
123 */
CreatePunctuationTable(const punctuation_t * punctuations)124 void idLexer::CreatePunctuationTable( const punctuation_t *punctuations ) {
125 int i, n, lastp;
126 const punctuation_t *p, *newp;
127
128 //get memory for the table
129 if ( punctuations == default_punctuations ) {
130 idLexer::punctuationtable = default_punctuationtable;
131 idLexer::nextpunctuation = default_nextpunctuation;
132 if ( default_setup ) {
133 return;
134 }
135 default_setup = true;
136 i = sizeof(default_punctuations) / sizeof(punctuation_t);
137 }
138 else {
139 if ( !idLexer::punctuationtable || idLexer::punctuationtable == default_punctuationtable ) {
140 idLexer::punctuationtable = (int *) Mem_Alloc(256 * sizeof(int));
141 }
142 if ( idLexer::nextpunctuation && idLexer::nextpunctuation != default_nextpunctuation ) {
143 Mem_Free( idLexer::nextpunctuation );
144 }
145 for (i = 0; punctuations[i].p; i++) {
146 }
147 idLexer::nextpunctuation = (int *) Mem_Alloc(i * sizeof(int));
148 }
149 memset(idLexer::punctuationtable, 0xFF, 256 * sizeof(int));
150 memset(idLexer::nextpunctuation, 0xFF, i * sizeof(int));
151 //add the punctuations in the list to the punctuation table
152 for (i = 0; punctuations[i].p; i++) {
153 newp = &punctuations[i];
154 lastp = -1;
155 //sort the punctuations in this table entry on length (longer punctuations first)
156 for (n = idLexer::punctuationtable[(unsigned int) newp->p[0]]; n >= 0; n = idLexer::nextpunctuation[n] ) {
157 p = &punctuations[n];
158 if (strlen(p->p) < strlen(newp->p)) {
159 idLexer::nextpunctuation[i] = n;
160 if (lastp >= 0) {
161 idLexer::nextpunctuation[lastp] = i;
162 }
163 else {
164 idLexer::punctuationtable[(unsigned int) newp->p[0]] = i;
165 }
166 break;
167 }
168 lastp = n;
169 }
170 if (n < 0) {
171 idLexer::nextpunctuation[i] = -1;
172 if (lastp >= 0) {
173 idLexer::nextpunctuation[lastp] = i;
174 }
175 else {
176 idLexer::punctuationtable[(unsigned int) newp->p[0]] = i;
177 }
178 }
179 }
180 }
181
182 /*
183 ================
184 idLexer::GetPunctuationFromId
185 ================
186 */
GetPunctuationFromId(int id)187 const char *idLexer::GetPunctuationFromId( int id ) {
188 int i;
189
190 for (i = 0; idLexer::punctuations[i].p; i++) {
191 if ( idLexer::punctuations[i].n == id ) {
192 return idLexer::punctuations[i].p;
193 }
194 }
195 return "unknown punctuation";
196 }
197
198 /*
199 ================
200 idLexer::GetPunctuationId
201 ================
202 */
GetPunctuationId(const char * p)203 int idLexer::GetPunctuationId( const char *p ) {
204 int i;
205
206 for (i = 0; idLexer::punctuations[i].p; i++) {
207 if ( !strcmp(idLexer::punctuations[i].p, p) ) {
208 return idLexer::punctuations[i].n;
209 }
210 }
211 return 0;
212 }
213
214 /*
215 ================
216 idLexer::Error
217 ================
218 */
Error(const char * str,...)219 void idLexer::Error( const char *str, ... ) {
220 char text[MAX_STRING_CHARS];
221 va_list ap;
222
223 hadError = true;
224
225 if ( idLexer::flags & LEXFL_NOERRORS ) {
226 return;
227 }
228
229 va_start(ap, str);
230 vsprintf(text, str, ap);
231 va_end(ap);
232
233 if ( idLexer::flags & LEXFL_NOFATALERRORS ) {
234 idLib::common->Warning( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
235 } else {
236 idLib::common->Error( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
237 }
238 }
239
240 /*
241 ================
242 idLexer::Warning
243 ================
244 */
Warning(const char * str,...)245 void idLexer::Warning( const char *str, ... ) {
246 char text[MAX_STRING_CHARS];
247 va_list ap;
248
249 if ( idLexer::flags & LEXFL_NOWARNINGS ) {
250 return;
251 }
252
253 va_start( ap, str );
254 vsprintf( text, str, ap );
255 va_end( ap );
256 idLib::common->Warning( "file %s, line %d: %s", idLexer::filename.c_str(), idLexer::line, text );
257 }
258
259 /*
260 ================
261 idLexer::SetPunctuations
262 ================
263 */
SetPunctuations(const punctuation_t * p)264 void idLexer::SetPunctuations( const punctuation_t *p ) {
265 #ifdef PUNCTABLE
266 if (p) {
267 idLexer::CreatePunctuationTable( p );
268 }
269 else {
270 idLexer::CreatePunctuationTable( default_punctuations );
271 }
272 #endif //PUNCTABLE
273 if (p) {
274 idLexer::punctuations = p;
275 }
276 else {
277 idLexer::punctuations = default_punctuations;
278 }
279 }
280
281 /*
282 ================
283 idLexer::ReadWhiteSpace
284
285 Reads spaces, tabs, C-like comments etc.
286 When a newline character is found the scripts line counter is increased.
287 ================
288 */
ReadWhiteSpace(void)289 int idLexer::ReadWhiteSpace( void ) {
290 while(1) {
291 // skip white space
292 while(*idLexer::script_p <= ' ') {
293 if (!*idLexer::script_p) {
294 return 0;
295 }
296 if (*idLexer::script_p == '\n') {
297 idLexer::line++;
298 }
299 idLexer::script_p++;
300 }
301 // skip comments
302 if (*idLexer::script_p == '/') {
303 // comments //
304 if (*(idLexer::script_p+1) == '/') {
305 idLexer::script_p++;
306 do {
307 idLexer::script_p++;
308 if ( !*idLexer::script_p ) {
309 return 0;
310 }
311 }
312 while( *idLexer::script_p != '\n' );
313 idLexer::line++;
314 idLexer::script_p++;
315 if ( !*idLexer::script_p ) {
316 return 0;
317 }
318 continue;
319 }
320 // comments /* */
321 else if (*(idLexer::script_p+1) == '*') {
322 idLexer::script_p++;
323 while( 1 ) {
324 idLexer::script_p++;
325 if ( !*idLexer::script_p ) {
326 return 0;
327 }
328 if ( *idLexer::script_p == '\n' ) {
329 idLexer::line++;
330 }
331 else if ( *idLexer::script_p == '/' ) {
332 if ( *(idLexer::script_p-1) == '*' ) {
333 break;
334 }
335 if ( *(idLexer::script_p+1) == '*' ) {
336 idLexer::Warning( "nested comment" );
337 }
338 }
339 }
340 idLexer::script_p++;
341 if ( !*idLexer::script_p ) {
342 return 0;
343 }
344 idLexer::script_p++;
345 if ( !*idLexer::script_p ) {
346 return 0;
347 }
348 continue;
349 }
350 }
351 break;
352 }
353 return 1;
354 }
355
356 /*
357 ================
358 idLexer::ReadEscapeCharacter
359 ================
360 */
ReadEscapeCharacter(char * ch)361 int idLexer::ReadEscapeCharacter( char *ch ) {
362 int c, val, i;
363
364 // step over the leading '\\'
365 idLexer::script_p++;
366 // determine the escape character
367 switch(*idLexer::script_p) {
368 case '\\': c = '\\'; break;
369 case 'n': c = '\n'; break;
370 case 'r': c = '\r'; break;
371 case 't': c = '\t'; break;
372 case 'v': c = '\v'; break;
373 case 'b': c = '\b'; break;
374 case 'f': c = '\f'; break;
375 case 'a': c = '\a'; break;
376 case '\'': c = '\''; break;
377 case '\"': c = '\"'; break;
378 case '\?': c = '\?'; break;
379 case 'x':
380 {
381 idLexer::script_p++;
382 for (i = 0, val = 0; ; i++, idLexer::script_p++) {
383 c = *idLexer::script_p;
384 if (c >= '0' && c <= '9')
385 c = c - '0';
386 else if (c >= 'A' && c <= 'Z')
387 c = c - 'A' + 10;
388 else if (c >= 'a' && c <= 'z')
389 c = c - 'a' + 10;
390 else
391 break;
392 val = (val << 4) + c;
393 }
394 idLexer::script_p--;
395 if (val > 0xFF) {
396 idLexer::Warning( "too large value in escape character" );
397 val = 0xFF;
398 }
399 c = val;
400 break;
401 }
402 default: //NOTE: decimal ASCII code, NOT octal
403 {
404 if (*idLexer::script_p < '0' || *idLexer::script_p > '9') {
405 idLexer::Error("unknown escape char");
406 }
407 for (i = 0, val = 0; ; i++, idLexer::script_p++) {
408 c = *idLexer::script_p;
409 if (c >= '0' && c <= '9')
410 c = c - '0';
411 else
412 break;
413 val = val * 10 + c;
414 }
415 idLexer::script_p--;
416 if (val > 0xFF) {
417 idLexer::Warning( "too large value in escape character" );
418 val = 0xFF;
419 }
420 c = val;
421 break;
422 }
423 }
424 // step over the escape character or the last digit of the number
425 idLexer::script_p++;
426 // store the escape character
427 *ch = c;
428 // succesfully read escape character
429 return 1;
430 }
431
432 /*
433 ================
434 idLexer::ReadString
435
436 Escape characters are interpretted.
437 Reads two strings with only a white space between them as one string.
438 ================
439 */
ReadString(idToken * token,int quote)440 int idLexer::ReadString( idToken *token, int quote ) {
441 int tmpline;
442 const char *tmpscript_p;
443 char ch;
444
445 if ( quote == '\"' ) {
446 token->type = TT_STRING;
447 } else {
448 token->type = TT_LITERAL;
449 }
450
451 // leading quote
452 idLexer::script_p++;
453
454 while(1) {
455 // if there is an escape character and escape characters are allowed
456 if (*idLexer::script_p == '\\' && !(idLexer::flags & LEXFL_NOSTRINGESCAPECHARS)) {
457 if ( !idLexer::ReadEscapeCharacter( &ch ) ) {
458 return 0;
459 }
460 token->AppendDirty( ch );
461 }
462 // if a trailing quote
463 else if (*idLexer::script_p == quote) {
464 // step over the quote
465 idLexer::script_p++;
466 // if consecutive strings should not be concatenated
467 if ( (idLexer::flags & LEXFL_NOSTRINGCONCAT) &&
468 (!(idLexer::flags & LEXFL_ALLOWBACKSLASHSTRINGCONCAT) || (quote != '\"')) ) {
469 break;
470 }
471
472 tmpscript_p = idLexer::script_p;
473 tmpline = idLexer::line;
474 // read white space between possible two consecutive strings
475 if ( !idLexer::ReadWhiteSpace() ) {
476 idLexer::script_p = tmpscript_p;
477 idLexer::line = tmpline;
478 break;
479 }
480
481 if ( idLexer::flags & LEXFL_NOSTRINGCONCAT ) {
482 if ( *idLexer::script_p != '\\' ) {
483 idLexer::script_p = tmpscript_p;
484 idLexer::line = tmpline;
485 break;
486 }
487 // step over the '\\'
488 idLexer::script_p++;
489 if ( !idLexer::ReadWhiteSpace() || ( *idLexer::script_p != quote ) ) {
490 idLexer::Error( "expecting string after '\' terminated line" );
491 return 0;
492 }
493 }
494
495 // if there's no leading qoute
496 if ( *idLexer::script_p != quote ) {
497 idLexer::script_p = tmpscript_p;
498 idLexer::line = tmpline;
499 break;
500 }
501 // step over the new leading quote
502 idLexer::script_p++;
503 }
504 else {
505 if (*idLexer::script_p == '\0') {
506 idLexer::Error( "missing trailing quote" );
507 return 0;
508 }
509 if (*idLexer::script_p == '\n') {
510 idLexer::Error( "newline inside string" );
511 return 0;
512 }
513 token->AppendDirty( *idLexer::script_p++ );
514 }
515 }
516 token->data[token->len] = '\0';
517
518 if ( token->type == TT_LITERAL ) {
519 if ( !(idLexer::flags & LEXFL_ALLOWMULTICHARLITERALS) ) {
520 if ( token->Length() != 1 ) {
521 idLexer::Warning( "literal is not one character long" );
522 }
523 }
524 token->subtype = (*token)[0];
525 }
526 else {
527 // the sub type is the length of the string
528 token->subtype = token->Length();
529 }
530 return 1;
531 }
532
533 /*
534 ================
535 idLexer::ReadName
536 ================
537 */
ReadName(idToken * token)538 int idLexer::ReadName( idToken *token ) {
539 char c;
540
541 token->type = TT_NAME;
542 do {
543 token->AppendDirty( *idLexer::script_p++ );
544 c = *idLexer::script_p;
545 } while ((c >= 'a' && c <= 'z') ||
546 (c >= 'A' && c <= 'Z') ||
547 (c >= '0' && c <= '9') ||
548 c == '_' ||
549 // if treating all tokens as strings, don't parse '-' as a seperate token
550 ((idLexer::flags & LEXFL_ONLYSTRINGS) && (c == '-')) ||
551 // if special path name characters are allowed
552 ((idLexer::flags & LEXFL_ALLOWPATHNAMES) && (c == '/' || c == '\\' || c == ':' || c == '.')) );
553 token->data[token->len] = '\0';
554 //the sub type is the length of the name
555 token->subtype = token->Length();
556 return 1;
557 }
558
559 /*
560 ================
561 idLexer::CheckString
562 ================
563 */
CheckString(const char * str) const564 ID_INLINE int idLexer::CheckString( const char *str ) const {
565 int i;
566
567 for ( i = 0; str[i]; i++ ) {
568 if ( idLexer::script_p[i] != str[i] ) {
569 return false;
570 }
571 }
572 return true;
573 }
574
575 /*
576 ================
577 idLexer::ReadNumber
578 ================
579 */
ReadNumber(idToken * token)580 int idLexer::ReadNumber( idToken *token ) {
581 int i;
582 int dot;
583 char c, c2;
584
585 token->type = TT_NUMBER;
586 token->subtype = 0;
587 token->intvalue = 0;
588 token->floatvalue = 0;
589
590 c = *idLexer::script_p;
591 c2 = *(idLexer::script_p + 1);
592
593 if ( c == '0' && c2 != '.' ) {
594 // check for a hexadecimal number
595 if ( c2 == 'x' || c2 == 'X' ) {
596 token->AppendDirty( *idLexer::script_p++ );
597 token->AppendDirty( *idLexer::script_p++ );
598 c = *idLexer::script_p;
599 while((c >= '0' && c <= '9') ||
600 (c >= 'a' && c <= 'f') ||
601 (c >= 'A' && c <= 'F')) {
602 token->AppendDirty( c );
603 c = *(++idLexer::script_p);
604 }
605 token->subtype = TT_HEX | TT_INTEGER;
606 }
607 // check for a binary number
608 else if ( c2 == 'b' || c2 == 'B' ) {
609 token->AppendDirty( *idLexer::script_p++ );
610 token->AppendDirty( *idLexer::script_p++ );
611 c = *idLexer::script_p;
612 while( c == '0' || c == '1' ) {
613 token->AppendDirty( c );
614 c = *(++idLexer::script_p);
615 }
616 token->subtype = TT_BINARY | TT_INTEGER;
617 }
618 // its an octal number
619 else {
620 token->AppendDirty( *idLexer::script_p++ );
621 c = *idLexer::script_p;
622 while( c >= '0' && c <= '7' ) {
623 token->AppendDirty( c );
624 c = *(++idLexer::script_p);
625 }
626 token->subtype = TT_OCTAL | TT_INTEGER;
627 }
628 }
629 else {
630 // decimal integer or floating point number or ip address
631 dot = 0;
632 while( 1 ) {
633 if ( c >= '0' && c <= '9' ) {
634 }
635 else if ( c == '.' ) {
636 dot++;
637 }
638 else {
639 break;
640 }
641 token->AppendDirty( c );
642 c = *(++idLexer::script_p);
643 }
644 if( c == 'e' && dot == 0) {
645 //We have scientific notation without a decimal point
646 dot++;
647 }
648 // if a floating point number
649 if ( dot == 1 ) {
650 token->subtype = TT_DECIMAL | TT_FLOAT;
651 // check for floating point exponent
652 if ( c == 'e' ) {
653 //Append the e so that GetFloatValue code works
654 token->AppendDirty( c );
655 c = *(++idLexer::script_p);
656 if ( c == '-' ) {
657 token->AppendDirty( c );
658 c = *(++idLexer::script_p);
659 }
660 else if ( c == '+' ) {
661 token->AppendDirty( c );
662 c = *(++idLexer::script_p);
663 }
664 while( c >= '0' && c <= '9' ) {
665 token->AppendDirty( c );
666 c = *(++idLexer::script_p);
667 }
668 }
669 // check for floating point exception infinite 1.#INF or indefinite 1.#IND or NaN
670 else if ( c == '#' ) {
671 c2 = 4;
672 if ( CheckString( "INF" ) ) {
673 token->subtype |= TT_INFINITE;
674 }
675 else if ( CheckString( "IND" ) ) {
676 token->subtype |= TT_INDEFINITE;
677 }
678 else if ( CheckString( "NAN" ) ) {
679 token->subtype |= TT_NAN;
680 }
681 else if ( CheckString( "QNAN" ) ) {
682 token->subtype |= TT_NAN;
683 c2++;
684 }
685 else if ( CheckString( "SNAN" ) ) {
686 token->subtype |= TT_NAN;
687 c2++;
688 }
689 for ( i = 0; i < c2; i++ ) {
690 token->AppendDirty( c );
691 c = *(++idLexer::script_p);
692 }
693 while( c >= '0' && c <= '9' ) {
694 token->AppendDirty( c );
695 c = *(++idLexer::script_p);
696 }
697 if ( !(idLexer::flags & LEXFL_ALLOWFLOATEXCEPTIONS) ) {
698 token->AppendDirty( 0 ); // zero terminate for c_str
699 idLexer::Error( "parsed %s", token->c_str() );
700 }
701 }
702 }
703 else if ( dot > 1 ) {
704 if ( !( idLexer::flags & LEXFL_ALLOWIPADDRESSES ) ) {
705 idLexer::Error( "more than one dot in number" );
706 return 0;
707 }
708 if ( dot != 3 ) {
709 idLexer::Error( "ip address should have three dots" );
710 return 0;
711 }
712 token->subtype = TT_IPADDRESS;
713 }
714 else {
715 token->subtype = TT_DECIMAL | TT_INTEGER;
716 }
717 }
718
719 if ( token->subtype & TT_FLOAT ) {
720 if ( c > ' ' ) {
721 // single-precision: float
722 if ( c == 'f' || c == 'F' ) {
723 token->subtype |= TT_SINGLE_PRECISION;
724 idLexer::script_p++;
725 }
726 // extended-precision: long double
727 else if ( c == 'l' || c == 'L' ) {
728 token->subtype |= TT_EXTENDED_PRECISION;
729 idLexer::script_p++;
730 }
731 // default is double-precision: double
732 else {
733 token->subtype |= TT_DOUBLE_PRECISION;
734 }
735 }
736 else {
737 token->subtype |= TT_DOUBLE_PRECISION;
738 }
739 }
740 else if ( token->subtype & TT_INTEGER ) {
741 if ( c > ' ' ) {
742 // default: signed long
743 for ( i = 0; i < 2; i++ ) {
744 // long integer
745 if ( c == 'l' || c == 'L' ) {
746 token->subtype |= TT_LONG;
747 }
748 // unsigned integer
749 else if ( c == 'u' || c == 'U' ) {
750 token->subtype |= TT_UNSIGNED;
751 }
752 else {
753 break;
754 }
755 c = *(++idLexer::script_p);
756 }
757 }
758 }
759 else if ( token->subtype & TT_IPADDRESS ) {
760 if ( c == ':' ) {
761 token->AppendDirty( c );
762 c = *(++idLexer::script_p);
763 while( c >= '0' && c <= '9' ) {
764 token->AppendDirty( c );
765 c = *(++idLexer::script_p);
766 }
767 token->subtype |= TT_IPPORT;
768 }
769 }
770 token->data[token->len] = '\0';
771 return 1;
772 }
773
774 /*
775 ================
776 idLexer::ReadPunctuation
777 ================
778 */
ReadPunctuation(idToken * token)779 int idLexer::ReadPunctuation( idToken *token ) {
780 int l, n, i;
781 const char *p;
782 const punctuation_t *punc;
783
784 #ifdef PUNCTABLE
785 for (n = idLexer::punctuationtable[(unsigned int)*(idLexer::script_p)]; n >= 0; n = idLexer::nextpunctuation[n])
786 {
787 punc = &(idLexer::punctuations[n]);
788 #else
789 int i;
790
791 for (i = 0; idLexer::punctuations[i].p; i++) {
792 punc = &idLexer::punctuations[i];
793 #endif
794 p = punc->p;
795 // check for this punctuation in the script
796 for ( l = 0; p[l] && idLexer::script_p[l]; l++ ) {
797 if ( idLexer::script_p[l] != p[l] ) {
798 break;
799 }
800 }
801 if ( !p[l] ) {
802 //
803 token->EnsureAlloced( l+1, false );
804 for ( i = 0; i <= l; i++ ) {
805 token->data[i] = p[i];
806 }
807 token->len = l;
808 //
809 idLexer::script_p += l;
810 token->type = TT_PUNCTUATION;
811 // sub type is the punctuation id
812 token->subtype = punc->n;
813 return 1;
814 }
815 }
816 return 0;
817 }
818
819 /*
820 ================
821 idLexer::ReadToken
822 ================
823 */
824 int idLexer::ReadToken( idToken *token ) {
825 int c;
826
827 if ( !loaded ) {
828 idLib::common->Error( "idLexer::ReadToken: no file loaded" );
829 return 0;
830 }
831
832 // if there is a token available (from unreadToken)
833 if ( tokenavailable ) {
834 tokenavailable = 0;
835 *token = idLexer::token;
836 return 1;
837 }
838 // save script pointer
839 lastScript_p = script_p;
840 // save line counter
841 lastline = line;
842 // clear the token stuff
843 token->data[0] = '\0';
844 token->len = 0;
845 // start of the white space
846 whiteSpaceStart_p = script_p;
847 token->whiteSpaceStart_p = script_p;
848 // read white space before token
849 if ( !ReadWhiteSpace() ) {
850 return 0;
851 }
852 // end of the white space
853 idLexer::whiteSpaceEnd_p = script_p;
854 token->whiteSpaceEnd_p = script_p;
855 // line the token is on
856 token->line = line;
857 // number of lines crossed before token
858 token->linesCrossed = line - lastline;
859 // clear token flags
860 token->flags = 0;
861
862 c = *idLexer::script_p;
863
864 // if we're keeping everything as whitespace deliminated strings
865 if ( idLexer::flags & LEXFL_ONLYSTRINGS ) {
866 // if there is a leading quote
867 if ( c == '\"' || c == '\'' ) {
868 if (!idLexer::ReadString( token, c )) {
869 return 0;
870 }
871 } else if ( !idLexer::ReadName( token ) ) {
872 return 0;
873 }
874 }
875 // if there is a number
876 else if ( (c >= '0' && c <= '9') ||
877 (c == '.' && (*(idLexer::script_p + 1) >= '0' && *(idLexer::script_p + 1) <= '9')) ) {
878 if ( !idLexer::ReadNumber( token ) ) {
879 return 0;
880 }
881 // if names are allowed to start with a number
882 if ( idLexer::flags & LEXFL_ALLOWNUMBERNAMES ) {
883 c = *idLexer::script_p;
884 if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ) {
885 if ( !idLexer::ReadName( token ) ) {
886 return 0;
887 }
888 }
889 }
890 }
891 // if there is a leading quote
892 else if ( c == '\"' || c == '\'' ) {
893 if (!idLexer::ReadString( token, c )) {
894 return 0;
895 }
896 }
897 // if there is a name
898 else if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ) {
899 if ( !idLexer::ReadName( token ) ) {
900 return 0;
901 }
902 }
903 // names may also start with a slash when pathnames are allowed
904 else if ( ( idLexer::flags & LEXFL_ALLOWPATHNAMES ) && ( (c == '/' || c == '\\') || c == '.' ) ) {
905 if ( !idLexer::ReadName( token ) ) {
906 return 0;
907 }
908 }
909 // check for punctuations
910 else if ( !idLexer::ReadPunctuation( token ) ) {
911 idLexer::Error( "unknown punctuation %c", c );
912 return 0;
913 }
914 // succesfully read a token
915 return 1;
916 }
917
918 /*
919 ================
920 idLexer::ExpectTokenString
921 ================
922 */
923 int idLexer::ExpectTokenString( const char *string ) {
924 idToken token;
925
926 if (!idLexer::ReadToken( &token )) {
927 idLexer::Error( "couldn't find expected '%s'", string );
928 return 0;
929 }
930 if ( token != string ) {
931 idLexer::Error( "expected '%s' but found '%s'", string, token.c_str() );
932 return 0;
933 }
934 return 1;
935 }
936
937 /*
938 ================
939 idLexer::ExpectTokenType
940 ================
941 */
942 int idLexer::ExpectTokenType( int type, int subtype, idToken *token ) {
943 idStr str;
944
945 if ( !idLexer::ReadToken( token ) ) {
946 idLexer::Error( "couldn't read expected token" );
947 return 0;
948 }
949
950 if ( token->type != type ) {
951 switch( type ) {
952 case TT_STRING: str = "string"; break;
953 case TT_LITERAL: str = "literal"; break;
954 case TT_NUMBER: str = "number"; break;
955 case TT_NAME: str = "name"; break;
956 case TT_PUNCTUATION: str = "punctuation"; break;
957 default: str = "unknown type"; break;
958 }
959 idLexer::Error( "expected a %s but found '%s'", str.c_str(), token->c_str() );
960 return 0;
961 }
962 if ( token->type == TT_NUMBER ) {
963 if ( (token->subtype & subtype) != subtype ) {
964 str.Clear();
965 if ( subtype & TT_DECIMAL ) str = "decimal ";
966 if ( subtype & TT_HEX ) str = "hex ";
967 if ( subtype & TT_OCTAL ) str = "octal ";
968 if ( subtype & TT_BINARY ) str = "binary ";
969 if ( subtype & TT_UNSIGNED ) str += "unsigned ";
970 if ( subtype & TT_LONG ) str += "long ";
971 if ( subtype & TT_FLOAT ) str += "float ";
972 if ( subtype & TT_INTEGER ) str += "integer ";
973 str.StripTrailing( ' ' );
974 idLexer::Error( "expected %s but found '%s'", str.c_str(), token->c_str() );
975 return 0;
976 }
977 }
978 else if ( token->type == TT_PUNCTUATION ) {
979 if ( subtype < 0 ) {
980 idLexer::Error( "BUG: wrong punctuation subtype" );
981 return 0;
982 }
983 if ( token->subtype != subtype ) {
984 idLexer::Error( "expected '%s' but found '%s'", GetPunctuationFromId( subtype ), token->c_str() );
985 return 0;
986 }
987 }
988 return 1;
989 }
990
991 /*
992 ================
993 idLexer::ExpectAnyToken
994 ================
995 */
996 int idLexer::ExpectAnyToken( idToken *token ) {
997 if (!idLexer::ReadToken( token )) {
998 idLexer::Error( "couldn't read expected token" );
999 return 0;
1000 }
1001 else {
1002 return 1;
1003 }
1004 }
1005
1006 /*
1007 ================
1008 idLexer::CheckTokenString
1009 ================
1010 */
1011 int idLexer::CheckTokenString( const char *string ) {
1012 idToken tok;
1013
1014 if ( !ReadToken( &tok ) ) {
1015 return 0;
1016 }
1017 // if the given string is available
1018 if ( tok == string ) {
1019 return 1;
1020 }
1021 // unread token
1022 script_p = lastScript_p;
1023 line = lastline;
1024 return 0;
1025 }
1026
1027 /*
1028 ================
1029 idLexer::CheckTokenType
1030 ================
1031 */
1032 int idLexer::CheckTokenType( int type, int subtype, idToken *token ) {
1033 idToken tok;
1034
1035 if ( !ReadToken( &tok ) ) {
1036 return 0;
1037 }
1038 // if the type matches
1039 if (tok.type == type && (tok.subtype & subtype) == subtype) {
1040 *token = tok;
1041 return 1;
1042 }
1043 // unread token
1044 script_p = lastScript_p;
1045 line = lastline;
1046 return 0;
1047 }
1048
1049 /*
1050 ================
1051 idLexer::PeekTokenString
1052 ================
1053 */
1054 int idLexer::PeekTokenString( const char *string ) {
1055 idToken tok;
1056
1057 if ( !ReadToken( &tok ) ) {
1058 return 0;
1059 }
1060
1061 // unread token
1062 script_p = lastScript_p;
1063 line = lastline;
1064
1065 // if the given string is available
1066 if ( tok == string ) {
1067 return 1;
1068 }
1069 return 0;
1070 }
1071
1072 /*
1073 ================
1074 idLexer::PeekTokenType
1075 ================
1076 */
1077 int idLexer::PeekTokenType( int type, int subtype, idToken *token ) {
1078 idToken tok;
1079
1080 if ( !ReadToken( &tok ) ) {
1081 return 0;
1082 }
1083
1084 // unread token
1085 script_p = lastScript_p;
1086 line = lastline;
1087
1088 // if the type matches
1089 if ( tok.type == type && ( tok.subtype & subtype ) == subtype ) {
1090 *token = tok;
1091 return 1;
1092 }
1093 return 0;
1094 }
1095
1096 /*
1097 ================
1098 idLexer::SkipUntilString
1099 ================
1100 */
1101 int idLexer::SkipUntilString( const char *string ) {
1102 idToken token;
1103
1104 while(idLexer::ReadToken( &token )) {
1105 if ( token == string ) {
1106 return 1;
1107 }
1108 }
1109 return 0;
1110 }
1111
1112 /*
1113 ================
1114 idLexer::SkipRestOfLine
1115 ================
1116 */
1117 int idLexer::SkipRestOfLine( void ) {
1118 idToken token;
1119
1120 while(idLexer::ReadToken( &token )) {
1121 if ( token.linesCrossed ) {
1122 idLexer::script_p = lastScript_p;
1123 idLexer::line = lastline;
1124 return 1;
1125 }
1126 }
1127 return 0;
1128 }
1129
1130 /*
1131 =================
1132 idLexer::SkipBracedSection
1133
1134 Skips until a matching close brace is found.
1135 Internal brace depths are properly skipped.
1136 =================
1137 */
1138 int idLexer::SkipBracedSection( bool parseFirstBrace ) {
1139 idToken token;
1140 int depth;
1141
1142 depth = parseFirstBrace ? 0 : 1;
1143 do {
1144 if ( !ReadToken( &token ) ) {
1145 return false;
1146 }
1147 if ( token.type == TT_PUNCTUATION ) {
1148 if ( token == "{" ) {
1149 depth++;
1150 } else if ( token == "}" ) {
1151 depth--;
1152 }
1153 }
1154 } while( depth );
1155 return true;
1156 }
1157
1158 /*
1159 ================
1160 idLexer::UnreadToken
1161 ================
1162 */
1163 void idLexer::UnreadToken( const idToken *token ) {
1164 if ( idLexer::tokenavailable ) {
1165 idLib::common->FatalError( "idLexer::unreadToken, unread token twice\n" );
1166 }
1167 idLexer::token = *token;
1168 idLexer::tokenavailable = 1;
1169 }
1170
1171 /*
1172 ================
1173 idLexer::ReadTokenOnLine
1174 ================
1175 */
1176 int idLexer::ReadTokenOnLine( idToken *token ) {
1177 idToken tok;
1178
1179 if (!idLexer::ReadToken( &tok )) {
1180 idLexer::script_p = lastScript_p;
1181 idLexer::line = lastline;
1182 return false;
1183 }
1184 // if no lines were crossed before this token
1185 if ( !tok.linesCrossed ) {
1186 *token = tok;
1187 return true;
1188 }
1189 // restore our position
1190 idLexer::script_p = lastScript_p;
1191 idLexer::line = lastline;
1192 token->Clear();
1193 return false;
1194 }
1195
1196 /*
1197 ================
1198 idLexer::ReadRestOfLine
1199 ================
1200 */
1201 const char* idLexer::ReadRestOfLine(idStr& out) {
1202 while(1) {
1203
1204 if(*idLexer::script_p == '\n') {
1205 idLexer::line++;
1206 break;
1207 }
1208
1209 if(!*idLexer::script_p) {
1210 break;
1211 }
1212
1213 if(*idLexer::script_p <= ' ') {
1214 out += " ";
1215 } else {
1216 out += *idLexer::script_p;
1217 }
1218 idLexer::script_p++;
1219
1220 }
1221
1222 out.Strip(' ');
1223 return out.c_str();
1224 }
1225
1226 /*
1227 ================
1228 idLexer::ParseInt
1229 ================
1230 */
1231 int idLexer::ParseInt( void ) {
1232 idToken token;
1233
1234 if ( !idLexer::ReadToken( &token ) ) {
1235 idLexer::Error( "couldn't read expected integer" );
1236 return 0;
1237 }
1238 if ( token.type == TT_PUNCTUATION && token == "-" ) {
1239 idLexer::ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
1240 return -((signed int) token.GetIntValue());
1241 }
1242 else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
1243 idLexer::Error( "expected integer value, found '%s'", token.c_str() );
1244 }
1245 return token.GetIntValue();
1246 }
1247
1248 /*
1249 ================
1250 idLexer::ParseBool
1251 ================
1252 */
1253 bool idLexer::ParseBool( void ) {
1254 idToken token;
1255
1256 if ( !idLexer::ExpectTokenType( TT_NUMBER, 0, &token ) ) {
1257 idLexer::Error( "couldn't read expected boolean" );
1258 return false;
1259 }
1260 return ( token.GetIntValue() != 0 );
1261 }
1262
1263 /*
1264 ================
1265 idLexer::ParseFloat
1266 ================
1267 */
1268 float idLexer::ParseFloat( bool *errorFlag ) {
1269 idToken token;
1270
1271 if ( errorFlag ) {
1272 *errorFlag = false;
1273 }
1274
1275 if ( !idLexer::ReadToken( &token ) ) {
1276 if ( errorFlag ) {
1277 idLexer::Warning( "couldn't read expected floating point number" );
1278 *errorFlag = true;
1279 } else {
1280 idLexer::Error( "couldn't read expected floating point number" );
1281 }
1282 return 0;
1283 }
1284 if ( token.type == TT_PUNCTUATION && token == "-" ) {
1285 idLexer::ExpectTokenType( TT_NUMBER, 0, &token );
1286 return -token.GetFloatValue();
1287 }
1288 else if ( token.type != TT_NUMBER ) {
1289 if ( errorFlag ) {
1290 idLexer::Warning( "expected float value, found '%s'", token.c_str() );
1291 *errorFlag = true;
1292 } else {
1293 idLexer::Error( "expected float value, found '%s'", token.c_str() );
1294 }
1295 }
1296 return token.GetFloatValue();
1297 }
1298
1299 /*
1300 ================
1301 idLexer::Parse1DMatrix
1302 ================
1303 */
1304 int idLexer::Parse1DMatrix( int x, float *m ) {
1305 int i;
1306
1307 if ( !idLexer::ExpectTokenString( "(" ) ) {
1308 return false;
1309 }
1310
1311 for ( i = 0; i < x; i++ ) {
1312 m[i] = idLexer::ParseFloat();
1313 }
1314
1315 if ( !idLexer::ExpectTokenString( ")" ) ) {
1316 return false;
1317 }
1318 return true;
1319 }
1320
1321 /*
1322 ================
1323 idLexer::Parse2DMatrix
1324 ================
1325 */
1326 int idLexer::Parse2DMatrix( int y, int x, float *m ) {
1327 int i;
1328
1329 if ( !idLexer::ExpectTokenString( "(" ) ) {
1330 return false;
1331 }
1332
1333 for ( i = 0; i < y; i++ ) {
1334 if ( !idLexer::Parse1DMatrix( x, m + i * x ) ) {
1335 return false;
1336 }
1337 }
1338
1339 if ( !idLexer::ExpectTokenString( ")" ) ) {
1340 return false;
1341 }
1342 return true;
1343 }
1344
1345 /*
1346 ================
1347 idLexer::Parse3DMatrix
1348 ================
1349 */
1350 int idLexer::Parse3DMatrix( int z, int y, int x, float *m ) {
1351 int i;
1352
1353 if ( !idLexer::ExpectTokenString( "(" ) ) {
1354 return false;
1355 }
1356
1357 for ( i = 0 ; i < z; i++ ) {
1358 if ( !idLexer::Parse2DMatrix( y, x, m + i * x*y ) ) {
1359 return false;
1360 }
1361 }
1362
1363 if ( !idLexer::ExpectTokenString( ")" ) ) {
1364 return false;
1365 }
1366 return true;
1367 }
1368
1369 /*
1370 =================
1371 idParser::ParseBracedSection
1372
1373 The next token should be an open brace.
1374 Parses until a matching close brace is found.
1375 Maintains exact characters between braces.
1376
1377 FIXME: this should use ReadToken and replace the token white space with correct indents and newlines
1378 =================
1379 */
1380 const char *idLexer::ParseBracedSectionExact( idStr &out, int tabs ) {
1381 int depth;
1382 bool doTabs;
1383 bool skipWhite;
1384
1385 out.Empty();
1386
1387 if ( !idLexer::ExpectTokenString( "{" ) ) {
1388 return out.c_str( );
1389 }
1390
1391 out = "{";
1392 depth = 1;
1393 skipWhite = false;
1394 doTabs = tabs >= 0;
1395
1396 while( depth && *idLexer::script_p ) {
1397 char c = *(idLexer::script_p++);
1398
1399 switch ( c ) {
1400 case '\t':
1401 case ' ': {
1402 if ( skipWhite ) {
1403 continue;
1404 }
1405 break;
1406 }
1407 case '\n': {
1408 if ( doTabs ) {
1409 skipWhite = true;
1410 out += c;
1411 continue;
1412 }
1413 break;
1414 }
1415 case '{': {
1416 depth++;
1417 tabs++;
1418 break;
1419 }
1420 case '}': {
1421 depth--;
1422 tabs--;
1423 break;
1424 }
1425 }
1426
1427 if ( skipWhite ) {
1428 int i = tabs;
1429 if ( c == '{' ) {
1430 i--;
1431 }
1432 skipWhite = false;
1433 for ( ; i > 0; i-- ) {
1434 out += '\t';
1435 }
1436 }
1437 out += c;
1438 }
1439 return out.c_str();
1440 }
1441
1442 /*
1443 =================
1444 idLexer::ParseBracedSection
1445
1446 The next token should be an open brace.
1447 Parses until a matching close brace is found.
1448 Internal brace depths are properly skipped.
1449 =================
1450 */
1451 const char *idLexer::ParseBracedSection( idStr &out ) {
1452 idToken token;
1453 int i, depth;
1454
1455 out.Empty();
1456 if ( !idLexer::ExpectTokenString( "{" ) ) {
1457 return out.c_str();
1458 }
1459 out = "{";
1460 depth = 1;
1461 do {
1462 if ( !idLexer::ReadToken( &token ) ) {
1463 Error( "missing closing brace" );
1464 return out.c_str();
1465 }
1466
1467 // if the token is on a new line
1468 for ( i = 0; i < token.linesCrossed; i++ ) {
1469 out += "\r\n";
1470 }
1471
1472 if ( token.type == TT_PUNCTUATION ) {
1473 if ( token[0] == '{' ) {
1474 depth++;
1475 }
1476 else if ( token[0] == '}' ) {
1477 depth--;
1478 }
1479 }
1480
1481 if ( token.type == TT_STRING ) {
1482 out += "\"" + token + "\"";
1483 }
1484 else {
1485 out += token;
1486 }
1487 out += " ";
1488 } while( depth );
1489
1490 return out.c_str();
1491 }
1492
1493 /*
1494 =================
1495 idLexer::ParseRestOfLine
1496
1497 parse the rest of the line
1498 =================
1499 */
1500 const char *idLexer::ParseRestOfLine( idStr &out ) {
1501 idToken token;
1502
1503 out.Empty();
1504 while(idLexer::ReadToken( &token )) {
1505 if ( token.linesCrossed ) {
1506 idLexer::script_p = lastScript_p;
1507 idLexer::line = lastline;
1508 break;
1509 }
1510 if ( out.Length() ) {
1511 out += " ";
1512 }
1513 out += token;
1514 }
1515 return out.c_str();
1516 }
1517
1518 /*
1519 ================
1520 idLexer::GetLastWhiteSpace
1521 ================
1522 */
1523 int idLexer::GetLastWhiteSpace( idStr &whiteSpace ) const {
1524 whiteSpace.Clear();
1525 for ( const char *p = whiteSpaceStart_p; p < whiteSpaceEnd_p; p++ ) {
1526 whiteSpace.Append( *p );
1527 }
1528 return whiteSpace.Length();
1529 }
1530
1531 /*
1532 ================
1533 idLexer::GetLastWhiteSpaceStart
1534 ================
1535 */
1536 int idLexer::GetLastWhiteSpaceStart( void ) const {
1537 return whiteSpaceStart_p - buffer;
1538 }
1539
1540 /*
1541 ================
1542 idLexer::GetLastWhiteSpaceEnd
1543 ================
1544 */
1545 int idLexer::GetLastWhiteSpaceEnd( void ) const {
1546 return whiteSpaceEnd_p - buffer;
1547 }
1548
1549 /*
1550 ================
1551 idLexer::Reset
1552 ================
1553 */
1554 void idLexer::Reset( void ) {
1555 // pointer in script buffer
1556 idLexer::script_p = idLexer::buffer;
1557 // pointer in script buffer before reading token
1558 idLexer::lastScript_p = idLexer::buffer;
1559 // begin of white space
1560 idLexer::whiteSpaceStart_p = NULL;
1561 // end of white space
1562 idLexer::whiteSpaceEnd_p = NULL;
1563 // set if there's a token available in idLexer::token
1564 idLexer::tokenavailable = 0;
1565
1566 idLexer::line = 1;
1567 idLexer::lastline = 1;
1568 // clear the saved token
1569 idLexer::token = "";
1570 }
1571
1572 /*
1573 ================
1574 idLexer::EndOfFile
1575 ================
1576 */
1577 int idLexer::EndOfFile( void ) {
1578 return idLexer::script_p >= idLexer::end_p;
1579 }
1580
1581 /*
1582 ================
1583 idLexer::NumLinesCrossed
1584 ================
1585 */
1586 int idLexer::NumLinesCrossed( void ) {
1587 return idLexer::line - idLexer::lastline;
1588 }
1589
1590 /*
1591 ================
1592 idLexer::LoadFile
1593 ================
1594 */
1595 int idLexer::LoadFile( const char *filename, bool OSPath ) {
1596 idFile *fp;
1597 idStr pathname;
1598 int length;
1599 char *buf;
1600
1601 if ( idLexer::loaded ) {
1602 idLib::common->Error("idLexer::LoadFile: another script already loaded");
1603 return false;
1604 }
1605
1606 if ( !OSPath && ( baseFolder[0] != '\0' ) ) {
1607 pathname = va( "%s/%s", baseFolder, filename );
1608 } else {
1609 pathname = filename;
1610 }
1611 if ( OSPath ) {
1612 fp = idLib::fileSystem->OpenExplicitFileRead( pathname );
1613 } else {
1614 fp = idLib::fileSystem->OpenFileRead( pathname );
1615 }
1616 if ( !fp ) {
1617 return false;
1618 }
1619 length = fp->Length();
1620 buf = (char *) Mem_Alloc( length + 1 );
1621 buf[length] = '\0';
1622 fp->Read( buf, length );
1623 idLexer::fileTime = fp->Timestamp();
1624 idLexer::filename = fp->GetFullPath();
1625 idLib::fileSystem->CloseFile( fp );
1626
1627 idLexer::buffer = buf;
1628 idLexer::length = length;
1629 // pointer in script buffer
1630 idLexer::script_p = idLexer::buffer;
1631 // pointer in script buffer before reading token
1632 idLexer::lastScript_p = idLexer::buffer;
1633 // pointer to end of script buffer
1634 idLexer::end_p = &(idLexer::buffer[length]);
1635
1636 idLexer::tokenavailable = 0;
1637 idLexer::line = 1;
1638 idLexer::lastline = 1;
1639 idLexer::allocated = true;
1640 idLexer::loaded = true;
1641
1642 return true;
1643 }
1644
1645 /*
1646 ================
1647 idLexer::LoadMemory
1648 ================
1649 */
1650 int idLexer::LoadMemory( const char *ptr, int length, const char *name, int startLine ) {
1651 if ( idLexer::loaded ) {
1652 idLib::common->Error("idLexer::LoadMemory: another script already loaded");
1653 return false;
1654 }
1655 idLexer::filename = name;
1656 idLexer::buffer = ptr;
1657 idLexer::fileTime = 0;
1658 idLexer::length = length;
1659 // pointer in script buffer
1660 idLexer::script_p = idLexer::buffer;
1661 // pointer in script buffer before reading token
1662 idLexer::lastScript_p = idLexer::buffer;
1663 // pointer to end of script buffer
1664 idLexer::end_p = &(idLexer::buffer[length]);
1665
1666 idLexer::tokenavailable = 0;
1667 idLexer::line = startLine;
1668 idLexer::lastline = startLine;
1669 idLexer::allocated = false;
1670 idLexer::loaded = true;
1671
1672 return true;
1673 }
1674
1675 /*
1676 ================
1677 idLexer::FreeSource
1678 ================
1679 */
1680 void idLexer::FreeSource( void ) {
1681 #ifdef PUNCTABLE
1682 if ( idLexer::punctuationtable && idLexer::punctuationtable != default_punctuationtable ) {
1683 Mem_Free( (void *) idLexer::punctuationtable );
1684 idLexer::punctuationtable = NULL;
1685 }
1686 if ( idLexer::nextpunctuation && idLexer::nextpunctuation != default_nextpunctuation ) {
1687 Mem_Free( (void *) idLexer::nextpunctuation );
1688 idLexer::nextpunctuation = NULL;
1689 }
1690 #endif //PUNCTABLE
1691 if ( idLexer::allocated ) {
1692 Mem_Free( (void *) idLexer::buffer );
1693 idLexer::buffer = NULL;
1694 idLexer::allocated = false;
1695 }
1696 idLexer::tokenavailable = 0;
1697 idLexer::token = "";
1698 idLexer::loaded = false;
1699 }
1700
1701 /*
1702 ================
1703 idLexer::idLexer
1704 ================
1705 */
1706 idLexer::idLexer( void ) {
1707 idLexer::loaded = false;
1708 idLexer::filename = "";
1709 idLexer::flags = 0;
1710 idLexer::SetPunctuations( NULL );
1711 idLexer::allocated = false;
1712 idLexer::fileTime = 0;
1713 idLexer::length = 0;
1714 idLexer::line = 0;
1715 idLexer::lastline = 0;
1716 idLexer::tokenavailable = 0;
1717 idLexer::token = "";
1718 idLexer::next = NULL;
1719 idLexer::hadError = false;
1720 }
1721
1722 /*
1723 ================
1724 idLexer::idLexer
1725 ================
1726 */
1727 idLexer::idLexer( int flags ) {
1728 idLexer::loaded = false;
1729 idLexer::filename = "";
1730 idLexer::flags = flags;
1731 idLexer::SetPunctuations( NULL );
1732 idLexer::allocated = false;
1733 idLexer::fileTime = 0;
1734 idLexer::length = 0;
1735 idLexer::line = 0;
1736 idLexer::lastline = 0;
1737 idLexer::tokenavailable = 0;
1738 idLexer::token = "";
1739 idLexer::next = NULL;
1740 idLexer::hadError = false;
1741 }
1742
1743 /*
1744 ================
1745 idLexer::idLexer
1746 ================
1747 */
1748 idLexer::idLexer( const char *filename, int flags, bool OSPath ) {
1749 idLexer::loaded = false;
1750 idLexer::flags = flags;
1751 idLexer::SetPunctuations( NULL );
1752 idLexer::allocated = false;
1753 idLexer::token = "";
1754 idLexer::next = NULL;
1755 idLexer::hadError = false;
1756 idLexer::LoadFile( filename, OSPath );
1757 }
1758
1759 /*
1760 ================
1761 idLexer::idLexer
1762 ================
1763 */
1764 idLexer::idLexer( const char *ptr, int length, const char *name, int flags ) {
1765 idLexer::loaded = false;
1766 idLexer::flags = flags;
1767 idLexer::SetPunctuations( NULL );
1768 idLexer::allocated = false;
1769 idLexer::token = "";
1770 idLexer::next = NULL;
1771 idLexer::hadError = false;
1772 idLexer::LoadMemory( ptr, length, name );
1773 }
1774
1775 /*
1776 ================
1777 idLexer::~idLexer
1778 ================
1779 */
1780 idLexer::~idLexer( void ) {
1781 idLexer::FreeSource();
1782 }
1783
1784 /*
1785 ================
1786 idLexer::SetBaseFolder
1787 ================
1788 */
1789 void idLexer::SetBaseFolder( const char *path ) {
1790 idStr::Copynz( baseFolder, path, sizeof( baseFolder ) );
1791 }
1792
1793 /*
1794 ================
1795 idLexer::HadError
1796 ================
1797 */
1798 bool idLexer::HadError( void ) const {
1799 return hadError;
1800 }
1801