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