]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/idlib/Parser.cpp
hello world
[icculus/iodoom3.git] / neo / idlib / Parser.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 DEBUG_EVAL
33 #define MAX_DEFINEPARMS                         128
34 #define DEFINEHASHSIZE                          2048
35
36 #define TOKEN_FL_RECURSIVE_DEFINE       1
37
38 define_t * idParser::globaldefines;
39
40 /*
41 ================
42 idParser::SetBaseFolder
43 ================
44 */
45 void idParser::SetBaseFolder( const char *path) {
46         idLexer::SetBaseFolder(path);
47 }
48
49 /*
50 ================
51 idParser::AddGlobalDefine
52 ================
53 */
54 int idParser::AddGlobalDefine( const char *string ) {
55         define_t *define;
56
57         define = idParser::DefineFromString(string);
58         if (!define) {
59                 return false;
60         }
61         define->next = globaldefines;
62         globaldefines = define;
63         return true;
64 }
65
66 /*
67 ================
68 idParser::RemoveGlobalDefine
69 ================
70 */
71 int idParser::RemoveGlobalDefine( const char *name ) {
72         define_t *d, *prev;
73
74         for ( prev = NULL, d = idParser::globaldefines; d; prev = d, d = d->next ) {
75                 if ( !strcmp( d->name, name ) ) {
76                         break;
77                 }
78         }
79         if ( d ) {
80                 if ( prev ) {
81                         prev->next = d->next;
82                 }
83                 else {
84                         idParser::globaldefines = d->next;
85                 }
86                 idParser::FreeDefine( d );
87                 return true;
88         }
89         return false;
90 }
91
92 /*
93 ================
94 idParser::RemoveAllGlobalDefines
95 ================
96 */
97 void idParser::RemoveAllGlobalDefines( void ) {
98         define_t *define;
99
100         for ( define = globaldefines; define; define = globaldefines ) {
101                 globaldefines = globaldefines->next;
102                 idParser::FreeDefine(define);
103         }
104 }
105
106
107 /*
108 ===============================================================================
109
110 idParser
111
112 ===============================================================================
113 */
114
115 /*
116 ================
117 idParser::PrintDefine
118 ================
119 */
120 void idParser::PrintDefine( define_t *define ) {
121         idLib::common->Printf("define->name = %s\n", define->name);
122         idLib::common->Printf("define->flags = %d\n", define->flags);
123         idLib::common->Printf("define->builtin = %d\n", define->builtin);
124         idLib::common->Printf("define->numparms = %d\n", define->numparms);
125 }
126
127 /*
128 ================
129 PC_PrintDefineHashTable
130 ================
131 * /
132 static void PC_PrintDefineHashTable(define_t **definehash) {
133         int i;
134         define_t *d;
135
136         for (i = 0; i < DEFINEHASHSIZE; i++) {
137                 Log_Write("%4d:", i);
138                 for (d = definehash[i]; d; d = d->hashnext) {
139                         Log_Write(" %s", d->name);
140                 }
141                 Log_Write("\n");
142         }
143 }
144 */
145
146 /*
147 ================
148 PC_NameHash
149 ================
150 */
151 ID_INLINE int PC_NameHash( const char *name ) {
152         int hash, i;
153
154         hash = 0;
155         for ( i = 0; name[i] != '\0'; i++ ) {
156                 hash += name[i] * (119 + i);
157         }
158         hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
159         return hash;
160 }
161
162 /*
163 ================
164 idParser::AddDefineToHash
165 ================
166 */
167 void idParser::AddDefineToHash( define_t *define, define_t **definehash ) {
168         int hash;
169
170         hash = PC_NameHash(define->name);
171         define->hashnext = definehash[hash];
172         definehash[hash] = define;
173 }
174
175 /*
176 ================
177 FindHashedDefine
178 ================
179 */
180 define_t *idParser::FindHashedDefine( define_t **definehash, const char *name ) {
181         define_t *d;
182         int hash;
183
184         hash = PC_NameHash(name);
185         for ( d = definehash[hash]; d; d = d->hashnext ) {
186                 if ( !strcmp(d->name, name) ) {
187                         return d;
188                 }
189         }
190         return NULL;
191 }
192
193 /*
194 ================
195 idParser::FindDefine
196 ================
197 */
198 define_t *idParser::FindDefine( define_t *defines, const char *name ) {
199         define_t *d;
200
201         for ( d = defines; d; d = d->next ) {
202                 if ( !strcmp(d->name, name) ) {
203                         return d;
204                 }
205         }
206         return NULL;
207 }
208
209 /*
210 ================
211 idParser::FindDefineParm
212 ================
213 */
214 int idParser::FindDefineParm( define_t *define, const char *name ) {
215         idToken *p;
216         int i;
217
218         i = 0;
219         for ( p = define->parms; p; p = p->next ) {
220                 if ( (*p) == name ) {
221                         return i;
222                 }
223                 i++;
224         }
225         return -1;
226 }
227
228 /*
229 ================
230 idParser::CopyDefine
231 ================
232 */
233 define_t *idParser::CopyDefine( define_t *define ) {
234         define_t *newdefine;
235         idToken *token, *newtoken, *lasttoken;
236
237         newdefine = (define_t *) Mem_Alloc(sizeof(define_t) + strlen(define->name) + 1);
238         //copy the define name
239         newdefine->name = (char *) newdefine + sizeof(define_t);
240         strcpy(newdefine->name, define->name);
241         newdefine->flags = define->flags;
242         newdefine->builtin = define->builtin;
243         newdefine->numparms = define->numparms;
244         //the define is not linked
245         newdefine->next = NULL;
246         newdefine->hashnext = NULL;
247         //copy the define tokens
248         newdefine->tokens = NULL;
249         for (lasttoken = NULL, token = define->tokens; token; token = token->next) {
250                 newtoken = new idToken(token);
251                 newtoken->next = NULL;
252                 if (lasttoken) lasttoken->next = newtoken;
253                 else newdefine->tokens = newtoken;
254                 lasttoken = newtoken;
255         }
256         //copy the define parameters
257         newdefine->parms = NULL;
258         for (lasttoken = NULL, token = define->parms; token; token = token->next) {
259                 newtoken = new idToken(token);
260                 newtoken->next = NULL;
261                 if (lasttoken) lasttoken->next = newtoken;
262                 else newdefine->parms = newtoken;
263                 lasttoken = newtoken;
264         }
265         return newdefine;
266 }
267
268 /*
269 ================
270 idParser::FreeDefine
271 ================
272 */
273 void idParser::FreeDefine( define_t *define ) {
274         idToken *t, *next;
275
276         //free the define parameters
277         for (t = define->parms; t; t = next) {
278                 next = t->next;
279                 delete t;
280         }
281         //free the define tokens
282         for (t = define->tokens; t; t = next) {
283                 next = t->next;
284                 delete t;
285         }
286         //free the define
287         Mem_Free( define );
288 }
289
290 /*
291 ================
292 idParser::DefineFromString
293 ================
294 */
295 define_t *idParser::DefineFromString( const char *string ) {
296         idParser src;
297         define_t *def;
298
299         if ( !src.LoadMemory(string, strlen(string), "*defineString") ) {
300                 return NULL;
301         }
302         // create a define from the source
303         if ( !src.Directive_define() ) {
304                 src.FreeSource();
305                 return NULL;
306         }
307         def = src.CopyFirstDefine();
308         src.FreeSource();
309         //if the define was created succesfully
310         return def;
311 }
312
313 /*
314 ================
315 idParser::Error
316 ================
317 */
318 void idParser::Error( const char *str, ... ) const {
319         char text[MAX_STRING_CHARS];
320         va_list ap;
321
322         va_start(ap, str);
323         vsprintf(text, str, ap);
324         va_end(ap);
325         if ( idParser::scriptstack ) {
326                 idParser::scriptstack->Error( text );
327         }
328 }
329
330 /*
331 ================
332 idParser::Warning
333 ================
334 */
335 void idParser::Warning( const char *str, ... ) const {
336         char text[MAX_STRING_CHARS];
337         va_list ap;
338
339         va_start(ap, str);
340         vsprintf(text, str, ap);
341         va_end(ap);
342         if ( idParser::scriptstack ) {
343                 idParser::scriptstack->Warning( text );
344         }
345 }
346
347 /*
348 ================
349 idParser::PushIndent
350 ================
351 */
352 void idParser::PushIndent( int type, int skip ) {
353         indent_t *indent;
354
355         indent = (indent_t *) Mem_Alloc(sizeof(indent_t));
356         indent->type = type;
357         indent->script = idParser::scriptstack;
358         indent->skip = (skip != 0);
359         idParser::skip += indent->skip;
360         indent->next = idParser::indentstack;
361         idParser::indentstack = indent;
362 }
363
364 /*
365 ================
366 idParser::PopIndent
367 ================
368 */
369 void idParser::PopIndent( int *type, int *skip ) {
370         indent_t *indent;
371
372         *type = 0;
373         *skip = 0;
374
375         indent = idParser::indentstack;
376         if (!indent) return;
377
378         // must be an indent from the current script
379         if (idParser::indentstack->script != idParser::scriptstack) {
380                 return;
381         }
382
383         *type = indent->type;
384         *skip = indent->skip;
385         idParser::indentstack = idParser::indentstack->next;
386         idParser::skip -= indent->skip;
387         Mem_Free( indent );
388 }
389
390 /*
391 ================
392 idParser::PushScript
393 ================
394 */
395 void idParser::PushScript( idLexer *script ) {
396         idLexer *s;
397
398         for ( s = idParser::scriptstack; s; s = s->next ) {
399                 if ( !idStr::Icmp(s->GetFileName(), script->GetFileName()) ) {
400                         idParser::Warning( "'%s' recursively included", script->GetFileName() );
401                         return;
402                 }
403         }
404         //push the script on the script stack
405         script->next = idParser::scriptstack;
406         idParser::scriptstack = script;
407 }
408
409 /*
410 ================
411 idParser::ReadSourceToken
412 ================
413 */
414 int idParser::ReadSourceToken( idToken *token ) {
415         idToken *t;
416         idLexer *script;
417         int type, skip, changedScript;
418
419         if ( !idParser::scriptstack ) {
420                 idLib::common->FatalError( "idParser::ReadSourceToken: not loaded" );
421                 return false;
422         }
423         changedScript = 0;
424         // if there's no token already available
425         while( !idParser::tokens ) {
426                 // if there's a token to read from the script
427                 if ( idParser::scriptstack->ReadToken( token ) ) {
428                         token->linesCrossed += changedScript;
429
430                         // set the marker based on the start of the token read in
431                         if ( !marker_p ) {
432                                 marker_p = token->whiteSpaceEnd_p;
433                         }
434                         return true;
435                 }
436                 // if at the end of the script
437                 if ( idParser::scriptstack->EndOfFile() ) {
438                         // remove all indents of the script
439                         while( idParser::indentstack && idParser::indentstack->script == idParser::scriptstack ) {
440                                 idParser::Warning( "missing #endif" );
441                                 idParser::PopIndent( &type, &skip );
442                         }
443                         changedScript = 1;
444                 }
445                 // if this was the initial script
446                 if ( !idParser::scriptstack->next ) {
447                         return false;
448                 }
449                 // remove the script and return to the previous one
450                 script = idParser::scriptstack;
451                 idParser::scriptstack = idParser::scriptstack->next;
452                 delete script;
453         }
454         // copy the already available token
455         *token = idParser::tokens;
456         // remove the token from the source
457         t = idParser::tokens;
458         idParser::tokens = idParser::tokens->next;
459         delete t;
460         return true;
461 }
462
463 /*
464 ================
465 idParser::UnreadSourceToken
466 ================
467 */
468 int idParser::UnreadSourceToken( idToken *token ) {
469         idToken *t;
470
471         t = new idToken(token);
472         t->next = idParser::tokens;
473         idParser::tokens = t;
474         return true;
475 }
476
477 /*
478 ================
479 idParser::ReadDefineParms
480 ================
481 */
482 int idParser::ReadDefineParms( define_t *define, idToken **parms, int maxparms ) {
483         define_t *newdefine;
484         idToken token, *t, *last;
485         int i, done, lastcomma, numparms, indent;
486
487         if ( !idParser::ReadSourceToken( &token ) ) {
488                 idParser::Error( "define '%s' missing parameters", define->name );
489                 return false;
490         }
491
492         if ( define->numparms > maxparms ) {
493                 idParser::Error( "define with more than %d parameters", maxparms );
494                 return false;
495         }
496
497         for ( i = 0; i < define->numparms; i++ ) {
498                 parms[i] = NULL;
499         }
500         // if no leading "("
501         if ( token != "(" ) {
502                 idParser::UnreadSourceToken( &token );
503                 idParser::Error( "define '%s' missing parameters", define->name );
504                 return false;
505         }
506         // read the define parameters
507         for ( done = 0, numparms = 0, indent = 1; !done; ) {
508                 if ( numparms >= maxparms ) {
509                         idParser::Error( "define '%s' with too many parameters", define->name );
510                         return false;
511                 }
512                 parms[numparms] = NULL;
513                 lastcomma = 1;
514                 last = NULL;
515                 while( !done ) {
516
517                         if ( !idParser::ReadSourceToken( &token ) ) {
518                                 idParser::Error( "define '%s' incomplete", define->name );
519                                 return false;
520                         }
521
522                         if ( token == "," ) {
523                                 if ( indent <= 1 ) {
524                                         if ( lastcomma ) {
525                                                 idParser::Warning( "too many comma's" );
526                                         }
527                                         if ( numparms >= define->numparms ) {
528                                                 idParser::Warning( "too many define parameters" );
529                                         }
530                                         lastcomma = 1;
531                                         break;
532                                 }
533                         }
534                         else if ( token == "(" ) {
535                                 indent++;
536                         }
537                         else if ( token == ")" ) {
538                                 indent--;
539                                 if ( indent <= 0 ) {
540                                         if ( !parms[define->numparms-1] ) {
541                                                 idParser::Warning( "too few define parameters" );
542                                         }
543                                         done = 1;
544                                         break;
545                                 }
546                         }
547                         else if ( token.type == TT_NAME ) {
548                                 newdefine = FindHashedDefine( idParser::definehash, token.c_str() );
549                                 if ( newdefine ) {
550                                         if ( !idParser::ExpandDefineIntoSource( &token, newdefine ) ) {
551                                                 return false;
552                                         }
553                                         continue;
554                                 }
555                         }
556
557                         lastcomma = 0;
558
559                         if ( numparms < define->numparms ) {
560
561                                 t = new idToken( token );
562                                 t->next = NULL;
563                                 if (last) last->next = t;
564                                 else parms[numparms] = t;
565                                 last = t;
566                         }
567                 }
568                 numparms++;
569         }
570         return true;
571 }
572
573 /*
574 ================
575 idParser::StringizeTokens
576 ================
577 */
578 int idParser::StringizeTokens( idToken *tokens, idToken *token ) {
579         idToken *t;
580
581         token->type = TT_STRING;
582         token->whiteSpaceStart_p = NULL;
583         token->whiteSpaceEnd_p = NULL;
584         (*token) = "";
585         for ( t = tokens; t; t = t->next ) {
586                 token->Append( t->c_str() );
587         }
588         return true;
589 }
590
591 /*
592 ================
593 idParser::MergeTokens
594 ================
595 */
596 int idParser::MergeTokens( idToken *t1, idToken *t2 ) {
597         // merging of a name with a name or number
598         if ( t1->type == TT_NAME && (t2->type == TT_NAME || (t2->type == TT_NUMBER && !(t2->subtype & TT_FLOAT))) ) {
599                 t1->Append( t2->c_str() );
600                 return true;
601         }
602         // merging of two strings
603         if (t1->type == TT_STRING && t2->type == TT_STRING) {
604                 t1->Append( t2->c_str() );
605                 return true;
606         }
607         // merging of two numbers
608         if ( t1->type == TT_NUMBER && t2->type == TT_NUMBER &&
609                         !(t1->subtype & (TT_HEX|TT_BINARY)) && !(t2->subtype & (TT_HEX|TT_BINARY)) &&
610                         (!(t1->subtype & TT_FLOAT) || !(t2->subtype & TT_FLOAT)) ) {
611                 t1->Append( t2->c_str() );
612                 return true;
613         }
614
615         return false;
616 }
617
618 /*
619 ================
620 idParser::AddBuiltinDefines
621 ================
622 */
623 void idParser::AddBuiltinDefines( void ) {
624         int i;
625         define_t *define;
626         struct builtin
627         {
628                 char *string;
629                 int id;
630         } builtin[] = {
631                 { "__LINE__",   BUILTIN_LINE }, 
632                 { "__FILE__",   BUILTIN_FILE },
633                 { "__DATE__",   BUILTIN_DATE },
634                 { "__TIME__",   BUILTIN_TIME },
635                 { "__STDC__", BUILTIN_STDC },
636                 { NULL, 0 }
637         };
638
639         for (i = 0; builtin[i].string; i++) {
640                 define = (define_t *) Mem_Alloc(sizeof(define_t) + strlen(builtin[i].string) + 1);
641                 define->name = (char *) define + sizeof(define_t);
642                 strcpy(define->name, builtin[i].string);
643                 define->flags = DEFINE_FIXED;
644                 define->builtin = builtin[i].id;
645                 define->numparms = 0;
646                 define->parms = NULL;
647                 define->tokens = NULL;
648                 // add the define to the source
649                 AddDefineToHash(define, idParser::definehash);
650         }
651 }
652
653 /*
654 ================
655 idParser::CopyFirstDefine
656 ================
657 */
658 define_t *idParser::CopyFirstDefine( void ) {
659         int i;
660
661         for ( i = 0; i < DEFINEHASHSIZE; i++ ) {
662                 if ( idParser::definehash[i] ) {
663                         return CopyDefine(idParser::definehash[i]);
664                 }
665         }
666         return NULL;
667 }
668
669 /*
670 ================
671 idParser::ExpandBuiltinDefine
672 ================
673 */
674 int idParser::ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken ) {
675         idToken *token;
676         ID_TIME_T t;
677         char *curtime;
678         char buf[MAX_STRING_CHARS];
679
680         token = new idToken(deftoken);
681         switch( define->builtin ) {
682                 case BUILTIN_LINE: {
683                         sprintf( buf, "%d", deftoken->line );
684                         (*token) = buf;
685                         token->intvalue = deftoken->line;
686                         token->floatvalue = deftoken->line;
687                         token->type = TT_NUMBER;
688                         token->subtype = TT_DECIMAL | TT_INTEGER | TT_VALUESVALID;
689                         token->line = deftoken->line;
690                         token->linesCrossed = deftoken->linesCrossed;
691                         token->flags = 0;
692                         *firsttoken = token;
693                         *lasttoken = token;
694                         break;
695                 }
696                 case BUILTIN_FILE: {
697                         (*token) = idParser::scriptstack->GetFileName();
698                         token->type = TT_NAME;
699                         token->subtype = token->Length();
700                         token->line = deftoken->line;
701                         token->linesCrossed = deftoken->linesCrossed;
702                         token->flags = 0;
703                         *firsttoken = token;
704                         *lasttoken = token;
705                         break;
706                 }
707                 case BUILTIN_DATE: {
708                         t = time(NULL);
709                         curtime = ctime(&t);
710                         (*token) = "\"";
711                         token->Append( curtime+4 );
712                         token[7] = '\0';
713                         token->Append( curtime+20 );
714                         token[10] = '\0';
715                         token->Append( "\"" );
716                         free(curtime);
717                         token->type = TT_STRING;
718                         token->subtype = token->Length();
719                         token->line = deftoken->line;
720                         token->linesCrossed = deftoken->linesCrossed;
721                         token->flags = 0;
722                         *firsttoken = token;
723                         *lasttoken = token;
724                         break;
725                 }
726                 case BUILTIN_TIME: {
727                         t = time(NULL);
728                         curtime = ctime(&t);
729                         (*token) = "\"";
730                         token->Append( curtime+11 );
731                         token[8] = '\0';
732                         token->Append( "\"" );
733                         free(curtime);
734                         token->type = TT_STRING;
735                         token->subtype = token->Length();
736                         token->line = deftoken->line;
737                         token->linesCrossed = deftoken->linesCrossed;
738                         token->flags = 0;
739                         *firsttoken = token;
740                         *lasttoken = token;
741                         break;
742                 }
743                 case BUILTIN_STDC: {
744                         idParser::Warning( "__STDC__ not supported\n" );
745                         *firsttoken = NULL;
746                         *lasttoken = NULL;
747                         break;
748                 }
749                 default: {
750                         *firsttoken = NULL;
751                         *lasttoken = NULL;
752                         break;
753                 }
754         }
755         return true;
756 }
757
758 /*
759 ================
760 idParser::ExpandDefine
761 ================
762 */
763 int idParser::ExpandDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken ) {
764         idToken *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
765         idToken *t1, *t2, *first, *last, *nextpt, token;
766         int parmnum, i;
767
768         // if it is a builtin define
769         if ( define->builtin ) {
770                 return idParser::ExpandBuiltinDefine( deftoken, define, firsttoken, lasttoken );
771         }
772         // if the define has parameters
773         if ( define->numparms ) {
774                 if ( !idParser::ReadDefineParms( define, parms, MAX_DEFINEPARMS ) ) {
775                         return false;
776                 }
777 #ifdef DEBUG_EVAL
778                 for ( i = 0; i < define->numparms; i++ ) {
779                         Log_Write("define parms %d:", i);
780                         for ( pt = parms[i]; pt; pt = pt->next ) {
781                                 Log_Write( "%s", pt->c_str() );
782                         }
783                 }
784 #endif //DEBUG_EVAL
785         }
786         // empty list at first
787         first = NULL;
788         last = NULL;
789         // create a list with tokens of the expanded define
790         for ( dt = define->tokens; dt; dt = dt->next ) {
791                 parmnum = -1;
792                 // if the token is a name, it could be a define parameter
793                 if ( dt->type == TT_NAME ) {
794                         parmnum = FindDefineParm( define, dt->c_str() );
795                 }
796                 // if it is a define parameter
797                 if ( parmnum >= 0 ) {
798                         for ( pt = parms[parmnum]; pt; pt = pt->next ) {
799                                 t = new idToken(pt);
800                                 //add the token to the list
801                                 t->next = NULL;
802                                 if (last) last->next = t;
803                                 else first = t;
804                                 last = t;
805                         }
806                 }
807                 else {
808                         // if stringizing operator
809                         if ( (*dt) == "#" ) {
810                                 // the stringizing operator must be followed by a define parameter
811                                 if ( dt->next ) {
812                                         parmnum = FindDefineParm( define, dt->next->c_str() );
813                                 }
814                                 else {
815                                         parmnum = -1;
816                                 }
817
818                                 if ( parmnum >= 0 ) {
819                                         // step over the stringizing operator
820                                         dt = dt->next;
821                                         // stringize the define parameter tokens
822                                         if ( !idParser::StringizeTokens( parms[parmnum], &token ) ) {
823                                                 idParser::Error( "can't stringize tokens" );
824                                                 return false;
825                                         }
826                                         t = new idToken(token);
827                                         t->line = deftoken->line;
828                                 }
829                                 else {
830                                         idParser::Warning( "stringizing operator without define parameter" );
831                                         continue;
832                                 }
833                         }
834                         else {
835                                 t = new idToken(dt);
836                                 t->line = deftoken->line;
837                         }
838                         // add the token to the list
839                         t->next = NULL;
840 // the token being read from the define list should use the line number of
841 // the original file, not the header file                       
842                         t->line = deftoken->line;
843
844                         if ( last ) last->next = t;
845                         else first = t;
846                         last = t;
847                 }
848         }
849         // check for the merging operator
850         for ( t = first; t; ) {
851                 if ( t->next ) {
852                         // if the merging operator
853                         if ( (*t->next) == "##" ) {
854                                 t1 = t;
855                                 t2 = t->next->next;
856                                 if ( t2 ) {
857                                         if ( !idParser::MergeTokens( t1, t2 ) ) {
858                                                 idParser::Error( "can't merge '%s' with '%s'", t1->c_str(), t2->c_str() );
859                                                 return false;
860                                         }
861                                         delete t1->next;
862                                         t1->next = t2->next;
863                                         if ( t2 == last ) last = t1;
864                                         delete t2;
865                                         continue;
866                                 }
867                         }
868                 }
869                 t = t->next;
870         }
871         // store the first and last token of the list
872         *firsttoken = first;
873         *lasttoken = last;
874         // free all the parameter tokens
875         for ( i = 0; i < define->numparms; i++ ) {
876                 for ( pt = parms[i]; pt; pt = nextpt ) {
877                         nextpt = pt->next;
878                         delete pt;
879                 }
880         }
881
882         return true;
883 }
884
885 /*
886 ================
887 idParser::ExpandDefineIntoSource
888 ================
889 */
890 int idParser::ExpandDefineIntoSource( idToken *deftoken, define_t *define ) {
891         idToken *firsttoken, *lasttoken;
892
893         if ( !idParser::ExpandDefine( deftoken, define, &firsttoken, &lasttoken ) ) {
894                 return false;
895         }
896         // if the define is not empty
897         if ( firsttoken && lasttoken ) {
898                 firsttoken->linesCrossed += deftoken->linesCrossed;
899                 lasttoken->next = idParser::tokens;
900                 idParser::tokens = firsttoken;
901         }
902         return true;
903 }
904
905 /*
906 ================
907 idParser::ReadLine
908
909 reads a token from the current line, continues reading on the next
910 line only if a backslash '\' is found
911 ================
912 */
913 int idParser::ReadLine( idToken *token ) {
914         int crossline;
915
916         crossline = 0;
917         do {
918                 if (!idParser::ReadSourceToken( token )) {
919                         return false;
920                 }
921                 
922                 if (token->linesCrossed > crossline) {
923                         idParser::UnreadSourceToken( token );
924                         return false;
925                 }
926                 crossline = 1;
927         } while( (*token) == "\\" );
928         return true;
929 }
930
931 /*
932 ================
933 idParser::Directive_include
934 ================
935 */
936 int idParser::Directive_include( void ) {
937         idLexer *script;
938         idToken token;
939         idStr path;
940
941         if ( !idParser::ReadSourceToken( &token ) ) {
942                 idParser::Error( "#include without file name" );
943                 return false;
944         }
945         if ( token.linesCrossed > 0 ) {
946                 idParser::Error( "#include without file name" );
947                 return false;
948         }
949         if ( token.type == TT_STRING ) {
950                 script = new idLexer;
951                 // try relative to the current file
952                 path = scriptstack->GetFileName();
953                 path.StripFilename();
954                 path += "/";
955                 path += token;
956                 if ( !script->LoadFile( path, OSPath ) ) {
957                         // try absolute path
958                         path = token;
959                         if ( !script->LoadFile( path, OSPath ) ) {
960                                 // try from the include path
961                                 path = includepath + token;
962                                 if ( !script->LoadFile( path, OSPath ) ) {
963                                         delete script;
964                                         script = NULL;
965                                 }
966                         }
967                 }
968         }
969         else if ( token.type == TT_PUNCTUATION && token == "<" ) {
970                 path = idParser::includepath;
971                 while( idParser::ReadSourceToken( &token ) ) {
972                         if ( token.linesCrossed > 0 ) {
973                                 idParser::UnreadSourceToken( &token );
974                                 break;
975                         }
976                         if ( token.type == TT_PUNCTUATION && token == ">" ) {
977                                 break;
978                         }
979                         path += token;
980                 }
981                 if ( token != ">" ) {
982                         idParser::Warning( "#include missing trailing >" );
983                 }
984                 if ( !path.Length() ) {
985                         idParser::Error( "#include without file name between < >" );
986                         return false;
987                 }
988                 if ( idParser::flags & LEXFL_NOBASEINCLUDES ) {
989                         return true;
990                 }
991                 script = new idLexer;
992                 if ( !script->LoadFile( includepath + path, OSPath ) ) {
993                         delete script;
994                         script = NULL;
995                 }
996         }
997         else {
998                 idParser::Error( "#include without file name" );
999                 return false;
1000         }
1001         if (!script) {
1002                 idParser::Error( "file '%s' not found", path.c_str() );
1003                 return false;
1004         }
1005         script->SetFlags( idParser::flags );
1006         script->SetPunctuations( idParser::punctuations );
1007         idParser::PushScript( script );
1008         return true;
1009 }
1010
1011 /*
1012 ================
1013 idParser::Directive_undef
1014 ================
1015 */
1016 int idParser::Directive_undef( void ) {
1017         idToken token;
1018         define_t *define, *lastdefine;
1019         int hash;
1020
1021         //
1022         if (!idParser::ReadLine( &token )) {
1023                 idParser::Error( "undef without name" );
1024                 return false;
1025         }
1026         if (token.type != TT_NAME) {
1027                 idParser::UnreadSourceToken( &token );
1028                 idParser::Error( "expected name but found '%s'", token.c_str() );
1029                 return false;
1030         }
1031
1032         hash = PC_NameHash( token.c_str() );
1033         for (lastdefine = NULL, define = idParser::definehash[hash]; define; define = define->hashnext) {
1034                 if (!strcmp(define->name, token.c_str()))
1035                 {
1036                         if (define->flags & DEFINE_FIXED) {
1037                                 idParser::Warning( "can't undef '%s'", token.c_str() );
1038                         }
1039                         else {
1040                                 if (lastdefine) {
1041                                         lastdefine->hashnext = define->hashnext;
1042                                 }
1043                                 else {
1044                                         idParser::definehash[hash] = define->hashnext;
1045                                 }
1046                                 FreeDefine(define);
1047                         }
1048                         break;
1049                 }
1050                 lastdefine = define;
1051         }
1052         return true;
1053 }
1054
1055 /*
1056 ================
1057 idParser::Directive_define
1058 ================
1059 */
1060 int idParser::Directive_define( void ) {
1061         idToken token, *t, *last;
1062         define_t *define;
1063
1064         if (!idParser::ReadLine( &token )) {
1065                 idParser::Error( "#define without name" );
1066                 return false;
1067         }
1068         if (token.type != TT_NAME) {
1069                 idParser::UnreadSourceToken( &token );
1070                 idParser::Error( "expected name after #define, found '%s'", token.c_str() );
1071                 return false;
1072         }
1073         // check if the define already exists
1074         define = FindHashedDefine(idParser::definehash, token.c_str());
1075         if (define) {
1076                 if (define->flags & DEFINE_FIXED) {
1077                         idParser::Error( "can't redefine '%s'", token.c_str() );
1078                         return false;
1079                 }
1080                 idParser::Warning( "redefinition of '%s'", token.c_str() );
1081                 // unread the define name before executing the #undef directive
1082                 idParser::UnreadSourceToken( &token );
1083                 if (!idParser::Directive_undef())
1084                         return false;
1085                 // if the define was not removed (define->flags & DEFINE_FIXED)
1086                 define = FindHashedDefine(idParser::definehash, token.c_str());
1087         }
1088         // allocate define
1089         define = (define_t *) Mem_ClearedAlloc(sizeof(define_t) + token.Length() + 1);
1090         define->name = (char *) define + sizeof(define_t);
1091         strcpy(define->name, token.c_str());
1092         // add the define to the source
1093         AddDefineToHash(define, idParser::definehash);
1094         // if nothing is defined, just return
1095         if ( !idParser::ReadLine( &token ) ) {
1096                 return true;
1097         }
1098         // if it is a define with parameters
1099         if ( token.WhiteSpaceBeforeToken() == 0 && token == "(" ) {
1100                 // read the define parameters
1101                 last = NULL;
1102                 if ( !idParser::CheckTokenString(")") ) {
1103                         while(1) {
1104                                 if ( !idParser::ReadLine( &token ) ) {
1105                                         idParser::Error( "expected define parameter" );
1106                                         return false;
1107                                 }
1108                                 // if it isn't a name
1109                                 if (token.type != TT_NAME) {
1110                                         idParser::Error( "invalid define parameter" );
1111                                         return false;
1112                                 }
1113
1114                                 if (FindDefineParm(define, token.c_str()) >= 0) {
1115                                         idParser::Error( "two the same define parameters" );
1116                                         return false;
1117                                 }
1118                                 // add the define parm
1119                                 t = new idToken(token);
1120                                 t->ClearTokenWhiteSpace();
1121                                 t->next = NULL;
1122                                 if (last) last->next = t;
1123                                 else define->parms = t;
1124                                 last = t;
1125                                 define->numparms++;
1126                                 // read next token
1127                                 if (!idParser::ReadLine( &token )) {
1128                                         idParser::Error( "define parameters not terminated" );
1129                                         return false;
1130                                 }
1131
1132                                 if ( token == ")" ) {
1133                                         break;
1134                                 }
1135                                 // then it must be a comma
1136                                 if ( token != "," ) {
1137                                         idParser::Error( "define not terminated" );
1138                                         return false;
1139                                 }
1140                         }
1141                 }
1142                 if ( !idParser::ReadLine( &token ) ) {
1143                         return true;
1144                 }
1145         }
1146         // read the defined stuff
1147         last = NULL;
1148         do
1149         {
1150                 t = new idToken(token);
1151                 if ( t->type == TT_NAME && !strcmp( t->c_str(), define->name ) ) {
1152                         t->flags |= TOKEN_FL_RECURSIVE_DEFINE;
1153                         idParser::Warning( "recursive define (removed recursion)" );
1154                 }
1155                 t->ClearTokenWhiteSpace();
1156                 t->next = NULL;
1157                 if ( last ) last->next = t;
1158                 else define->tokens = t;
1159                 last = t;
1160         } while( idParser::ReadLine( &token ) );
1161
1162         if ( last ) {
1163                 // check for merge operators at the beginning or end
1164                 if ( (*define->tokens) == "##" || (*last) == "##" ) {
1165                         idParser::Error( "define with misplaced ##" );
1166                         return false;
1167                 }
1168         }
1169         return true;
1170 }
1171
1172 /*
1173 ================
1174 idParser::AddDefine
1175 ================
1176 */
1177 int idParser::AddDefine( const char *string ) {
1178         define_t *define;
1179
1180         define = DefineFromString( string );
1181         if (!define) {
1182                 return false;
1183         }
1184         AddDefineToHash(define, idParser::definehash);
1185         return true;
1186 }
1187
1188 /*
1189 ================
1190 idParser::AddGlobalDefinesToSource
1191 ================
1192 */
1193 void idParser::AddGlobalDefinesToSource( void ) {
1194         define_t *define, *newdefine;
1195
1196         for (define = globaldefines; define; define = define->next) {
1197                 newdefine = CopyDefine( define );
1198                 AddDefineToHash(newdefine, idParser::definehash);
1199         }
1200 }
1201
1202 /*
1203 ================
1204 idParser::Directive_if_def
1205 ================
1206 */
1207 int idParser::Directive_if_def( int type ) {
1208         idToken token;
1209         define_t *d;
1210         int skip;
1211
1212         if ( !idParser::ReadLine( &token ) ) {
1213                 idParser::Error( "#ifdef without name" );
1214                 return false;
1215         }
1216         if (token.type != TT_NAME) {
1217                 idParser::UnreadSourceToken( &token );
1218                 idParser::Error( "expected name after #ifdef, found '%s'", token.c_str() );
1219                 return false;
1220         }
1221         d = FindHashedDefine(idParser::definehash, token.c_str());
1222         skip = (type == INDENT_IFDEF) == (d == NULL);
1223         idParser::PushIndent( type, skip );
1224         return true;
1225 }
1226
1227 /*
1228 ================
1229 idParser::Directive_ifdef
1230 ================
1231 */
1232 int idParser::Directive_ifdef( void ) {
1233         return idParser::Directive_if_def( INDENT_IFDEF );
1234 }
1235
1236 /*
1237 ================
1238 idParser::Directive_ifndef
1239 ================
1240 */
1241 int idParser::Directive_ifndef( void ) {
1242         return idParser::Directive_if_def( INDENT_IFNDEF );
1243 }
1244
1245 /*
1246 ================
1247 idParser::Directive_else
1248 ================
1249 */
1250 int idParser::Directive_else( void ) {
1251         int type, skip;
1252
1253         idParser::PopIndent( &type, &skip );
1254         if (!type) {
1255                 idParser::Error( "misplaced #else" );
1256                 return false;
1257         }
1258         if (type == INDENT_ELSE) {
1259                 idParser::Error( "#else after #else" );
1260                 return false;
1261         }
1262         idParser::PushIndent( INDENT_ELSE, !skip );
1263         return true;
1264 }
1265
1266 /*
1267 ================
1268 idParser::Directive_endif
1269 ================
1270 */
1271 int idParser::Directive_endif( void ) {
1272         int type, skip;
1273
1274         idParser::PopIndent( &type, &skip );
1275         if (!type) {
1276                 idParser::Error( "misplaced #endif" );
1277                 return false;
1278         }
1279         return true;
1280 }
1281
1282 /*
1283 ================
1284 idParser::EvaluateTokens
1285 ================
1286 */
1287 typedef struct operator_s
1288 {
1289         int op;
1290         int priority;
1291         int parentheses;
1292         struct operator_s *prev, *next;
1293 } operator_t;
1294
1295 typedef struct value_s
1296 {
1297         signed long int intvalue;
1298         double floatvalue;
1299         int parentheses;
1300         struct value_s *prev, *next;
1301 } value_t;
1302
1303 int PC_OperatorPriority(int op) {
1304         switch(op) {
1305                 case P_MUL: return 15;
1306                 case P_DIV: return 15;
1307                 case P_MOD: return 15;
1308                 case P_ADD: return 14;
1309                 case P_SUB: return 14;
1310
1311                 case P_LOGIC_AND: return 7;
1312                 case P_LOGIC_OR: return 6;
1313                 case P_LOGIC_GEQ: return 12;
1314                 case P_LOGIC_LEQ: return 12;
1315                 case P_LOGIC_EQ: return 11;
1316                 case P_LOGIC_UNEQ: return 11;
1317
1318                 case P_LOGIC_NOT: return 16;
1319                 case P_LOGIC_GREATER: return 12;
1320                 case P_LOGIC_LESS: return 12;
1321
1322                 case P_RSHIFT: return 13;
1323                 case P_LSHIFT: return 13;
1324
1325                 case P_BIN_AND: return 10;
1326                 case P_BIN_OR: return 8;
1327                 case P_BIN_XOR: return 9;
1328                 case P_BIN_NOT: return 16;
1329
1330                 case P_COLON: return 5;
1331                 case P_QUESTIONMARK: return 5;
1332         }
1333         return false;
1334 }
1335
1336 //#define AllocValue()                  GetClearedMemory(sizeof(value_t));
1337 //#define FreeValue(val)                FreeMemory(val)
1338 //#define AllocOperator(op)             op = (operator_t *) GetClearedMemory(sizeof(operator_t));
1339 //#define FreeOperator(op)              FreeMemory(op);
1340
1341 #define MAX_VALUES              64
1342 #define MAX_OPERATORS   64
1343
1344 #define AllocValue(val)                                                                 \
1345         if ( numvalues >= MAX_VALUES ) {                                        \
1346                 idParser::Error( "out of value space\n" );              \
1347                 error = 1;                                                                              \
1348                 break;                                                                                  \
1349         }                                                                                                       \
1350         else {                                                                                          \
1351                 val = &value_heap[numvalues++];                                 \
1352         }
1353
1354 #define FreeValue(val)
1355
1356 #define AllocOperator(op)                                                               \
1357         if ( numoperators >= MAX_OPERATORS ) {                          \
1358                 idParser::Error( "out of operator space\n" );   \
1359                 error = 1;                                                                              \
1360                 break;                                                                                  \
1361         }                                                                                                       \
1362         else {                                                                                          \
1363                 op = &operator_heap[numoperators++];                    \
1364         }
1365
1366 #define FreeOperator(op)
1367
1368 int idParser::EvaluateTokens( idToken *tokens, signed long int *intvalue, double *floatvalue, int integer ) {
1369         operator_t *o, *firstoperator, *lastoperator;
1370         value_t *v, *firstvalue, *lastvalue, *v1, *v2;
1371         idToken *t;
1372         int brace = 0;
1373         int parentheses = 0;
1374         int error = 0;
1375         int lastwasvalue = 0;
1376         int negativevalue = 0;
1377         int questmarkintvalue = 0;
1378         double questmarkfloatvalue = 0;
1379         int gotquestmarkvalue = false;
1380         int lastoperatortype = 0;
1381         //
1382         operator_t operator_heap[MAX_OPERATORS];
1383         int numoperators = 0;
1384         value_t value_heap[MAX_VALUES];
1385         int numvalues = 0;
1386
1387         firstoperator = lastoperator = NULL;
1388         firstvalue = lastvalue = NULL;
1389         if (intvalue) *intvalue = 0;
1390         if (floatvalue) *floatvalue = 0;
1391         for ( t = tokens; t; t = t->next ) {
1392                 switch( t->type ) {
1393                         case TT_NAME:
1394                         {
1395                                 if ( lastwasvalue || negativevalue ) {
1396                                         idParser::Error( "syntax error in #if/#elif" );
1397                                         error = 1;
1398                                         break;
1399                                 }
1400                                 if ( (*t) != "defined" ) {
1401                                         idParser::Error( "undefined name '%s' in #if/#elif", t->c_str() );
1402                                         error = 1;
1403                                         break;
1404                                 }
1405                                 t = t->next;
1406                                 if ( (*t) == "(" ) {
1407                                         brace = true;
1408                                         t = t->next;
1409                                 }
1410                                 if (!t || t->type != TT_NAME) {
1411                                         idParser::Error( "defined() without name in #if/#elif" );
1412                                         error = 1;
1413                                         break;
1414                                 }
1415                                 //v = (value_t *) GetClearedMemory(sizeof(value_t));
1416                                 AllocValue(v);
1417                                 if (FindHashedDefine(idParser::definehash, t->c_str())) {
1418                                         v->intvalue = 1;
1419                                         v->floatvalue = 1;
1420                                 }
1421                                 else {
1422                                         v->intvalue = 0;
1423                                         v->floatvalue = 0;
1424                                 }
1425                                 v->parentheses = parentheses;
1426                                 v->next = NULL;
1427                                 v->prev = lastvalue;
1428                                 if (lastvalue) lastvalue->next = v;
1429                                 else firstvalue = v;
1430                                 lastvalue = v;
1431                                 if (brace) {
1432                                         t = t->next;
1433                                         if (!t || (*t) != ")" ) {
1434                                                 idParser::Error( "defined missing ) in #if/#elif" );
1435                                                 error = 1;
1436                                                 break;
1437                                         }
1438                                 }
1439                                 brace = false;
1440                                 // defined() creates a value
1441                                 lastwasvalue = 1;
1442                                 break;
1443                         }
1444                         case TT_NUMBER:
1445                         {
1446                                 if (lastwasvalue) {
1447                                         idParser::Error( "syntax error in #if/#elif" );
1448                                         error = 1;
1449                                         break;
1450                                 }
1451                                 //v = (value_t *) GetClearedMemory(sizeof(value_t));
1452                                 AllocValue(v);
1453                                 if (negativevalue) {
1454                                         v->intvalue = - t->GetIntValue();
1455                                         v->floatvalue = - t->GetFloatValue();
1456                                 }
1457                                 else {
1458                                         v->intvalue = t->GetIntValue();
1459                                         v->floatvalue = t->GetFloatValue();
1460                                 }
1461                                 v->parentheses = parentheses;
1462                                 v->next = NULL;
1463                                 v->prev = lastvalue;
1464                                 if (lastvalue) lastvalue->next = v;
1465                                 else firstvalue = v;
1466                                 lastvalue = v;
1467                                 //last token was a value
1468                                 lastwasvalue = 1;
1469                                 //
1470                                 negativevalue = 0;
1471                                 break;
1472                         }
1473                         case TT_PUNCTUATION:
1474                         {
1475                                 if (negativevalue) {
1476                                         idParser::Error( "misplaced minus sign in #if/#elif" );
1477                                         error = 1;
1478                                         break;
1479                                 }
1480                                 if (t->subtype == P_PARENTHESESOPEN) {
1481                                         parentheses++;
1482                                         break;
1483                                 }
1484                                 else if (t->subtype == P_PARENTHESESCLOSE) {
1485                                         parentheses--;
1486                                         if (parentheses < 0) {
1487                                                 idParser::Error( "too many ) in #if/#elsif" );
1488                                                 error = 1;
1489                                         }
1490                                         break;
1491                                 }
1492                                 //check for invalid operators on floating point values
1493                                 if ( !integer ) {
1494                                         if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
1495                                                 t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
1496                                                 t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
1497                                                 t->subtype == P_BIN_XOR) {
1498                                                 idParser::Error( "illigal operator '%s' on floating point operands\n", t->c_str() );
1499                                                 error = 1;
1500                                                 break;
1501                                         }
1502                                 }
1503                                 switch( t->subtype ) {
1504                                         case P_LOGIC_NOT:
1505                                         case P_BIN_NOT:
1506                                         {
1507                                                 if (lastwasvalue) {
1508                                                         idParser::Error( "! or ~ after value in #if/#elif" );
1509                                                         error = 1;
1510                                                         break;
1511                                                 }
1512                                                 break;
1513                                         }
1514                                         case P_INC:
1515                                         case P_DEC:
1516                                         {
1517                                                 idParser::Error( "++ or -- used in #if/#elif" );
1518                                                 break;
1519                                         }
1520                                         case P_SUB:
1521                                         {
1522                                                 if (!lastwasvalue) {
1523                                                         negativevalue = 1;
1524                                                         break;
1525                                                 }
1526                                         }
1527                                         
1528                                         case P_MUL:
1529                                         case P_DIV:
1530                                         case P_MOD:
1531                                         case P_ADD:
1532
1533                                         case P_LOGIC_AND:
1534                                         case P_LOGIC_OR:
1535                                         case P_LOGIC_GEQ:
1536                                         case P_LOGIC_LEQ:
1537                                         case P_LOGIC_EQ:
1538                                         case P_LOGIC_UNEQ:
1539
1540                                         case P_LOGIC_GREATER:
1541                                         case P_LOGIC_LESS:
1542
1543                                         case P_RSHIFT:
1544                                         case P_LSHIFT:
1545
1546                                         case P_BIN_AND:
1547                                         case P_BIN_OR:
1548                                         case P_BIN_XOR:
1549
1550                                         case P_COLON:
1551                                         case P_QUESTIONMARK:
1552                                         {
1553                                                 if (!lastwasvalue) {
1554                                                         idParser::Error( "operator '%s' after operator in #if/#elif", t->c_str() );
1555                                                         error = 1;
1556                                                         break;
1557                                                 }
1558                                                 break;
1559                                         }
1560                                         default:
1561                                         {
1562                                                 idParser::Error( "invalid operator '%s' in #if/#elif", t->c_str() );
1563                                                 error = 1;
1564                                                 break;
1565                                         }
1566                                 }
1567                                 if (!error && !negativevalue) {
1568                                         //o = (operator_t *) GetClearedMemory(sizeof(operator_t));
1569                                         AllocOperator(o);
1570                                         o->op = t->subtype;
1571                                         o->priority = PC_OperatorPriority(t->subtype);
1572                                         o->parentheses = parentheses;
1573                                         o->next = NULL;
1574                                         o->prev = lastoperator;
1575                                         if (lastoperator) lastoperator->next = o;
1576                                         else firstoperator = o;
1577                                         lastoperator = o;
1578                                         lastwasvalue = 0;
1579                                 }
1580                                 break;
1581                         }
1582                         default:
1583                         {
1584                                 idParser::Error( "unknown '%s' in #if/#elif", t->c_str() );
1585                                 error = 1;
1586                                 break;
1587                         }
1588                 }
1589                 if (error) {
1590                         break;
1591                 }
1592         }
1593         if (!error) {
1594                 if (!lastwasvalue) {
1595                         idParser::Error( "trailing operator in #if/#elif" );
1596                         error = 1;
1597                 }
1598                 else if (parentheses) {
1599                         idParser::Error( "too many ( in #if/#elif" );
1600                         error = 1;
1601                 }
1602         }
1603         //
1604         gotquestmarkvalue = false;
1605         questmarkintvalue = 0;
1606         questmarkfloatvalue = 0;
1607         //while there are operators
1608         while( !error && firstoperator ) {
1609                 v = firstvalue;
1610                 for (o = firstoperator; o->next; o = o->next) {
1611                         //if the current operator is nested deeper in parentheses
1612                         //than the next operator
1613                         if (o->parentheses > o->next->parentheses) {
1614                                 break;
1615                         }
1616                         //if the current and next operator are nested equally deep in parentheses
1617                         if (o->parentheses == o->next->parentheses) {
1618                                 //if the priority of the current operator is equal or higher
1619                                 //than the priority of the next operator
1620                                 if (o->priority >= o->next->priority) {
1621                                         break;
1622                                 }
1623                         }
1624                         //if the arity of the operator isn't equal to 1
1625                         if (o->op != P_LOGIC_NOT && o->op != P_BIN_NOT) {
1626                                 v = v->next;
1627                         }
1628                         //if there's no value or no next value
1629                         if (!v) {
1630                                 idParser::Error( "mising values in #if/#elif" );
1631                                 error = 1;
1632                                 break;
1633                         }
1634                 }
1635                 if (error) {
1636                         break;
1637                 }
1638                 v1 = v;
1639                 v2 = v->next;
1640 #ifdef DEBUG_EVAL
1641                 if (integer) {
1642                         Log_Write("operator %s, value1 = %d", idParser::scriptstack->getPunctuationFromId(o->op), v1->intvalue);
1643                         if (v2) Log_Write("value2 = %d", v2->intvalue);
1644                 }
1645                 else {
1646                         Log_Write("operator %s, value1 = %f", idParser::scriptstack->getPunctuationFromId(o->op), v1->floatvalue);
1647                         if (v2) Log_Write("value2 = %f", v2->floatvalue);
1648                 }
1649 #endif //DEBUG_EVAL
1650                 switch(o->op) {
1651                         case P_LOGIC_NOT:               v1->intvalue = !v1->intvalue;
1652                                                                         v1->floatvalue = !v1->floatvalue; break;
1653                         case P_BIN_NOT:                 v1->intvalue = ~v1->intvalue;
1654                                                                         break;
1655                         case P_MUL:                             v1->intvalue *= v2->intvalue;
1656                                                                         v1->floatvalue *= v2->floatvalue; break;
1657                         case P_DIV:                             if (!v2->intvalue || !v2->floatvalue)
1658                                                                         {
1659                                                                                 idParser::Error( "divide by zero in #if/#elif\n" );
1660                                                                                 error = 1;
1661                                                                                 break;
1662                                                                         }
1663                                                                         v1->intvalue /= v2->intvalue;
1664                                                                         v1->floatvalue /= v2->floatvalue; break;
1665                         case P_MOD:                             if (!v2->intvalue)
1666                                                                         {
1667                                                                                 idParser::Error( "divide by zero in #if/#elif\n" );
1668                                                                                 error = 1;
1669                                                                                 break;
1670                                                                         }
1671                                                                         v1->intvalue %= v2->intvalue; break;
1672                         case P_ADD:                             v1->intvalue += v2->intvalue;
1673                                                                         v1->floatvalue += v2->floatvalue; break;
1674                         case P_SUB:                             v1->intvalue -= v2->intvalue;
1675                                                                         v1->floatvalue -= v2->floatvalue; break;
1676                         case P_LOGIC_AND:               v1->intvalue = v1->intvalue && v2->intvalue;
1677                                                                         v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
1678                         case P_LOGIC_OR:                v1->intvalue = v1->intvalue || v2->intvalue;
1679                                                                         v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
1680                         case P_LOGIC_GEQ:               v1->intvalue = v1->intvalue >= v2->intvalue;
1681                                                                         v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
1682                         case P_LOGIC_LEQ:               v1->intvalue = v1->intvalue <= v2->intvalue;
1683                                                                         v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
1684                         case P_LOGIC_EQ:                v1->intvalue = v1->intvalue == v2->intvalue;
1685                                                                         v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
1686                         case P_LOGIC_UNEQ:              v1->intvalue = v1->intvalue != v2->intvalue;
1687                                                                         v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
1688                         case P_LOGIC_GREATER:   v1->intvalue = v1->intvalue > v2->intvalue;
1689                                                                         v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
1690                         case P_LOGIC_LESS:              v1->intvalue = v1->intvalue < v2->intvalue;
1691                                                                         v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
1692                         case P_RSHIFT:                  v1->intvalue >>= v2->intvalue;
1693                                                                         break;
1694                         case P_LSHIFT:                  v1->intvalue <<= v2->intvalue;
1695                                                                         break;
1696                         case P_BIN_AND:                 v1->intvalue &= v2->intvalue;
1697                                                                         break;
1698                         case P_BIN_OR:                  v1->intvalue |= v2->intvalue;
1699                                                                         break;
1700                         case P_BIN_XOR:                 v1->intvalue ^= v2->intvalue;
1701                                                                         break;
1702                         case P_COLON:
1703                         {
1704                                 if (!gotquestmarkvalue) {
1705                                         idParser::Error( ": without ? in #if/#elif" );
1706                                         error = 1;
1707                                         break;
1708                                 }
1709                                 if (integer) {
1710                                         if (!questmarkintvalue)
1711                                                 v1->intvalue = v2->intvalue;
1712                                 }
1713                                 else {
1714                                         if (!questmarkfloatvalue)
1715                                                 v1->floatvalue = v2->floatvalue;
1716                                 }
1717                                 gotquestmarkvalue = false;
1718                                 break;
1719                         }
1720                         case P_QUESTIONMARK:
1721                         {
1722                                 if (gotquestmarkvalue) {
1723                                         idParser::Error( "? after ? in #if/#elif" );
1724                                         error = 1;
1725                                         break;
1726                                 }
1727                                 questmarkintvalue = v1->intvalue;
1728                                 questmarkfloatvalue = v1->floatvalue;
1729                                 gotquestmarkvalue = true;
1730                                 break;
1731                         }
1732                 }
1733 #ifdef DEBUG_EVAL
1734                 if (integer) Log_Write("result value = %d", v1->intvalue);
1735                 else Log_Write("result value = %f", v1->floatvalue);
1736 #endif //DEBUG_EVAL
1737                 if (error)
1738                         break;
1739                 lastoperatortype = o->op;
1740                 //if not an operator with arity 1
1741                 if (o->op != P_LOGIC_NOT && o->op != P_BIN_NOT) {
1742                         //remove the second value if not question mark operator
1743                         if (o->op != P_QUESTIONMARK) {
1744                                 v = v->next;
1745                         }
1746                         //
1747                         if (v->prev) v->prev->next = v->next;
1748                         else firstvalue = v->next;
1749                         if (v->next) v->next->prev = v->prev;
1750                         else lastvalue = v->prev;
1751                         //FreeMemory(v);
1752                         FreeValue(v);
1753                 }
1754                 //remove the operator
1755                 if (o->prev) o->prev->next = o->next;
1756                 else firstoperator = o->next;
1757                 if (o->next) o->next->prev = o->prev;
1758                 else lastoperator = o->prev;
1759                 //FreeMemory(o);
1760                 FreeOperator(o);
1761         }
1762         if (firstvalue) {
1763                 if (intvalue) *intvalue = firstvalue->intvalue;
1764                 if (floatvalue) *floatvalue = firstvalue->floatvalue;
1765         }
1766         for (o = firstoperator; o; o = lastoperator) {
1767                 lastoperator = o->next;
1768                 //FreeMemory(o);
1769                 FreeOperator(o);
1770         }
1771         for (v = firstvalue; v; v = lastvalue) {
1772                 lastvalue = v->next;
1773                 //FreeMemory(v);
1774                 FreeValue(v);
1775         }
1776         if (!error) {
1777                 return true;
1778         }
1779         if (intvalue) {
1780                 *intvalue = 0;
1781         }
1782         if (floatvalue) {
1783                 *floatvalue = 0;
1784         }
1785         return false;
1786 }
1787
1788 /*
1789 ================
1790 idParser::Evaluate
1791 ================
1792 */
1793 int idParser::Evaluate( signed long int *intvalue, double *floatvalue, int integer ) {
1794         idToken token, *firsttoken, *lasttoken;
1795         idToken *t, *nexttoken;
1796         define_t *define;
1797         int defined = false;
1798
1799         if (intvalue) {
1800                 *intvalue = 0;
1801         }
1802         if (floatvalue) {
1803                 *floatvalue = 0;
1804         }
1805         //
1806         if ( !idParser::ReadLine( &token ) ) {
1807                 idParser::Error( "no value after #if/#elif" );
1808                 return false;
1809         }
1810         firsttoken = NULL;
1811         lasttoken = NULL;
1812         do {
1813                 //if the token is a name
1814                 if (token.type == TT_NAME) {
1815                         if (defined) {
1816                                 defined = false;
1817                                 t = new idToken(token);
1818                                 t->next = NULL;
1819                                 if (lasttoken) lasttoken->next = t;
1820                                 else firsttoken = t;
1821                                 lasttoken = t;
1822                         }
1823                         else if ( token == "defined" ) {
1824                                 defined = true;
1825                                 t = new idToken(token);
1826                                 t->next = NULL;
1827                                 if (lasttoken) lasttoken->next = t;
1828                                 else firsttoken = t;
1829                                 lasttoken = t;
1830                         }
1831                         else {
1832                                 //then it must be a define
1833                                 define = FindHashedDefine(idParser::definehash, token.c_str());
1834                                 if (!define) {
1835                                         idParser::Error( "can't Evaluate '%s', not defined", token.c_str() );
1836                                         return false;
1837                                 }
1838                                 if ( !idParser::ExpandDefineIntoSource( &token, define ) ) {
1839                                         return false;
1840                                 }
1841                         }
1842                 }
1843                 //if the token is a number or a punctuation
1844                 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) {
1845                         t = new idToken(token);
1846                         t->next = NULL;
1847                         if (lasttoken) lasttoken->next = t;
1848                         else firsttoken = t;
1849                         lasttoken = t;
1850                 }
1851                 else {
1852                         idParser::Error( "can't Evaluate '%s'", token.c_str() );
1853                         return false;
1854                 }
1855         } while(idParser::ReadLine( &token ));
1856         //
1857         if ( !idParser::EvaluateTokens( firsttoken, intvalue, floatvalue, integer ) ) {
1858                 return false;
1859         }
1860         //
1861 #ifdef DEBUG_EVAL
1862         Log_Write("eval:");
1863 #endif //DEBUG_EVAL
1864         for (t = firsttoken; t; t = nexttoken) {
1865 #ifdef DEBUG_EVAL
1866                 Log_Write(" %s", t->c_str());
1867 #endif //DEBUG_EVAL
1868                 nexttoken = t->next;
1869                 delete t;
1870         } //end for
1871 #ifdef DEBUG_EVAL
1872         if (integer) Log_Write("eval result: %d", *intvalue);
1873         else Log_Write("eval result: %f", *floatvalue);
1874 #endif //DEBUG_EVAL
1875         //
1876         return true;
1877 }
1878
1879 /*
1880 ================
1881 idParser::DollarEvaluate
1882 ================
1883 */
1884 int idParser::DollarEvaluate( signed long int *intvalue, double *floatvalue, int integer) {
1885         int indent, defined = false;
1886         idToken token, *firsttoken, *lasttoken;
1887         idToken *t, *nexttoken;
1888         define_t *define;
1889
1890         if (intvalue) {
1891                 *intvalue = 0;
1892         }
1893         if (floatvalue) {
1894                 *floatvalue = 0;
1895         }
1896         //
1897         if ( !idParser::ReadSourceToken( &token ) ) {
1898                 idParser::Error( "no leading ( after $evalint/$evalfloat" );
1899                 return false;
1900         }
1901         if ( !idParser::ReadSourceToken( &token ) ) {
1902                 idParser::Error( "nothing to Evaluate" );
1903                 return false;
1904         }
1905         indent = 1;
1906         firsttoken = NULL;
1907         lasttoken = NULL;
1908         do {
1909                 //if the token is a name
1910                 if (token.type == TT_NAME) {
1911                         if (defined) {
1912                                 defined = false;
1913                                 t = new idToken(token);
1914                                 t->next = NULL;
1915                                 if (lasttoken) lasttoken->next = t;
1916                                 else firsttoken = t;
1917                                 lasttoken = t;
1918                         }
1919                         else if ( token == "defined" ) {
1920                                 defined = true;
1921                                 t = new idToken(token);
1922                                 t->next = NULL;
1923                                 if (lasttoken) lasttoken->next = t;
1924                                 else firsttoken = t;
1925                                 lasttoken = t;
1926                         }
1927                         else {
1928                                 //then it must be a define
1929                                 define = FindHashedDefine(idParser::definehash, token.c_str());
1930                                 if (!define) {
1931                                         idParser::Warning( "can't Evaluate '%s', not defined", token.c_str() );
1932                                         return false;
1933                                 }
1934                                 if ( !idParser::ExpandDefineIntoSource( &token, define ) ) {
1935                                         return false;
1936                                 }
1937                         }
1938                 }
1939                 //if the token is a number or a punctuation
1940                 else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION) {
1941                         if ( token[0] == '(' ) indent++;
1942                         else if ( token[0] == ')' ) indent--;
1943                         if (indent <= 0) {
1944                                 break;
1945                         }
1946                         t = new idToken(token);
1947                         t->next = NULL;
1948                         if (lasttoken) lasttoken->next = t;
1949                         else firsttoken = t;
1950                         lasttoken = t;
1951                 }
1952                 else {
1953                         idParser::Error( "can't Evaluate '%s'", token.c_str() );
1954                         return false;
1955                 }
1956         } while(idParser::ReadSourceToken( &token ));
1957         //
1958         if (!idParser::EvaluateTokens( firsttoken, intvalue, floatvalue, integer)) {
1959                 return false;
1960         }
1961         //
1962 #ifdef DEBUG_EVAL
1963         Log_Write("$eval:");
1964 #endif //DEBUG_EVAL
1965         for (t = firsttoken; t; t = nexttoken) {
1966 #ifdef DEBUG_EVAL
1967                 Log_Write(" %s", t->c_str());
1968 #endif //DEBUG_EVAL
1969                 nexttoken = t->next;
1970                 delete t;
1971         } //end for
1972 #ifdef DEBUG_EVAL
1973         if (integer) Log_Write("$eval result: %d", *intvalue);
1974         else Log_Write("$eval result: %f", *floatvalue);
1975 #endif //DEBUG_EVAL
1976         //
1977         return true;
1978 }
1979
1980 /*
1981 ================
1982 idParser::Directive_elif
1983 ================
1984 */
1985 int idParser::Directive_elif( void ) {
1986         signed long int value;
1987         int type, skip;
1988
1989         idParser::PopIndent( &type, &skip );
1990         if (!type || type == INDENT_ELSE) {
1991                 idParser::Error( "misplaced #elif" );
1992                 return false;
1993         }
1994         if ( !idParser::Evaluate( &value, NULL, true ) ) {
1995                 return false;
1996         }
1997         skip = (value == 0);
1998         idParser::PushIndent( INDENT_ELIF, skip );
1999         return true;
2000 }
2001
2002 /*
2003 ================
2004 idParser::Directive_if
2005 ================
2006 */
2007 int idParser::Directive_if( void ) {
2008         signed long int value;
2009         int skip;
2010
2011         if ( !idParser::Evaluate( &value, NULL, true ) ) {
2012                 return false;
2013         }
2014         skip = (value == 0);
2015         idParser::PushIndent( INDENT_IF, skip );
2016         return true;
2017 }
2018
2019 /*
2020 ================
2021 idParser::Directive_line
2022 ================
2023 */
2024 int idParser::Directive_line( void ) {
2025         idToken token;
2026
2027         idParser::Error( "#line directive not supported" );
2028         while( idParser::ReadLine( &token ) ) {
2029         }
2030         return true;
2031 }
2032
2033 /*
2034 ================
2035 idParser::Directive_error
2036 ================
2037 */
2038 int idParser::Directive_error( void ) {
2039         idToken token;
2040
2041         if ( !idParser::ReadLine( &token) || token.type != TT_STRING ) {
2042                 idParser::Error( "#error without string" );
2043                 return false;
2044         }
2045         idParser::Error( "#error: %s", token.c_str() );
2046         return true;
2047 }
2048
2049 /*
2050 ================
2051 idParser::Directive_warning
2052 ================
2053 */
2054 int idParser::Directive_warning( void ) {
2055         idToken token;
2056
2057         if ( !idParser::ReadLine( &token) || token.type != TT_STRING ) {
2058                 idParser::Warning( "#warning without string" );
2059                 return false;
2060         }
2061         idParser::Warning( "#warning: %s", token.c_str() );
2062         return true;
2063 }
2064
2065 /*
2066 ================
2067 idParser::Directive_pragma
2068 ================
2069 */
2070 int idParser::Directive_pragma( void ) {
2071         idToken token;
2072
2073         idParser::Warning( "#pragma directive not supported" );
2074         while( idParser::ReadLine( &token ) ) {
2075         }
2076         return true;
2077 }
2078
2079 /*
2080 ================
2081 idParser::UnreadSignToken
2082 ================
2083 */
2084 void idParser::UnreadSignToken( void ) {
2085         idToken token;
2086
2087         token.line = idParser::scriptstack->GetLineNum();
2088         token.whiteSpaceStart_p = NULL;
2089         token.whiteSpaceEnd_p = NULL;
2090         token.linesCrossed = 0;
2091         token.flags = 0;
2092         token = "-";
2093         token.type = TT_PUNCTUATION;
2094         token.subtype = P_SUB;
2095         idParser::UnreadSourceToken( &token );
2096 }
2097
2098 /*
2099 ================
2100 idParser::Directive_eval
2101 ================
2102 */
2103 int idParser::Directive_eval( void ) {
2104         signed long int value;
2105         idToken token;
2106         char buf[128];
2107
2108         if ( !idParser::Evaluate( &value, NULL, true ) ) {
2109                 return false;
2110         }
2111
2112         token.line = idParser::scriptstack->GetLineNum();
2113         token.whiteSpaceStart_p = NULL;
2114         token.whiteSpaceEnd_p = NULL;
2115         token.linesCrossed = 0;
2116         token.flags = 0;
2117         sprintf(buf, "%d", abs(value));
2118         token = buf;
2119         token.type = TT_NUMBER;
2120         token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
2121         idParser::UnreadSourceToken( &token );
2122         if ( value < 0 ) {
2123                 idParser::UnreadSignToken();
2124         }
2125         return true;
2126 }
2127
2128 /*
2129 ================
2130 idParser::Directive_evalfloat
2131 ================
2132 */
2133 int idParser::Directive_evalfloat( void ) {
2134         double value;
2135         idToken token;
2136         char buf[128];
2137
2138         if ( !idParser::Evaluate( NULL, &value, false ) ) {
2139                 return false;
2140         }
2141
2142         token.line = idParser::scriptstack->GetLineNum();
2143         token.whiteSpaceStart_p = NULL;
2144         token.whiteSpaceEnd_p = NULL;
2145         token.linesCrossed = 0;
2146         token.flags = 0;
2147         sprintf(buf, "%1.2f", idMath::Fabs(value));
2148         token = buf;
2149         token.type = TT_NUMBER;
2150         token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
2151         idParser::UnreadSourceToken( &token );
2152         if (value < 0) {
2153                 idParser::UnreadSignToken();
2154         }
2155         return true;
2156 }
2157
2158 /*
2159 ================
2160 idParser::ReadDirective
2161 ================
2162 */
2163 int idParser::ReadDirective( void ) {
2164         idToken token;
2165
2166         //read the directive name
2167         if ( !idParser::ReadSourceToken( &token ) ) {
2168                 idParser::Error( "found '#' without name" );
2169                 return false;
2170         }
2171         //directive name must be on the same line
2172         if (token.linesCrossed > 0) {
2173                 idParser::UnreadSourceToken( &token );
2174                 idParser::Error( "found '#' at end of line" );
2175                 return false;
2176         }
2177         //if if is a name
2178         if (token.type == TT_NAME) {
2179                 if ( token == "if" ) {
2180                         return idParser::Directive_if();
2181                 }
2182                 else if ( token == "ifdef" ) {
2183                         return idParser::Directive_ifdef();
2184                 }
2185                 else if ( token == "ifndef" ) {
2186                         return idParser::Directive_ifndef();
2187                 }
2188                 else if ( token == "elif" ) {
2189                         return idParser::Directive_elif();
2190                 }
2191                 else if ( token == "else" ) {
2192                         return idParser::Directive_else();
2193                 }
2194                 else if ( token == "endif" ) {
2195                         return idParser::Directive_endif();
2196                 }
2197                 else if (idParser::skip > 0) {
2198                         // skip the rest of the line
2199                         while( idParser::ReadLine( &token ) ) {
2200                         }
2201                         return true;
2202                 }
2203                 else {
2204                         if ( token == "include" ) {
2205                                 return idParser::Directive_include();
2206                         }
2207                         else if ( token == "define" ) {
2208                                 return idParser::Directive_define();
2209                         }
2210                         else if ( token == "undef" ) {
2211                                 return idParser::Directive_undef();
2212                         }
2213                         else if ( token == "line" ) {
2214                                 return idParser::Directive_line();
2215                         }
2216                         else if ( token == "error" ) {
2217                                 return idParser::Directive_error();
2218                         }
2219                         else if ( token == "warning" ) {
2220                                 return idParser::Directive_warning();
2221                         }
2222                         else if ( token == "pragma" ) {
2223                                 return idParser::Directive_pragma();
2224                         }
2225                         else if ( token == "eval" ) {
2226                                 return idParser::Directive_eval();
2227                         }
2228                         else if ( token == "evalfloat" ) {
2229                                 return idParser::Directive_evalfloat();
2230                         }
2231                 }
2232         }
2233         idParser::Error( "unknown precompiler directive '%s'", token.c_str() );
2234         return false;
2235 }
2236
2237 /*
2238 ================
2239 idParser::DollarDirective_evalint
2240 ================
2241 */
2242 int idParser::DollarDirective_evalint( void ) {
2243         signed long int value;
2244         idToken token;
2245         char buf[128];
2246
2247         if ( !idParser::DollarEvaluate( &value, NULL, true ) ) {
2248                 return false;
2249         }
2250
2251         token.line = idParser::scriptstack->GetLineNum();
2252         token.whiteSpaceStart_p = NULL;
2253         token.whiteSpaceEnd_p = NULL;
2254         token.linesCrossed = 0;
2255         token.flags = 0;
2256         sprintf( buf, "%d", abs( value ) );
2257         token = buf;
2258         token.type = TT_NUMBER;
2259         token.subtype = TT_INTEGER | TT_LONG | TT_DECIMAL | TT_VALUESVALID;
2260         token.intvalue = abs( value );
2261         token.floatvalue = abs( value );
2262         idParser::UnreadSourceToken( &token );
2263         if ( value < 0 ) {
2264                 idParser::UnreadSignToken();
2265         }
2266         return true;
2267 }
2268
2269 /*
2270 ================
2271 idParser::DollarDirective_evalfloat
2272 ================
2273 */
2274 int idParser::DollarDirective_evalfloat( void ) {
2275         double value;
2276         idToken token;
2277         char buf[128];
2278
2279         if ( !idParser::DollarEvaluate( NULL, &value, false ) ) {
2280                 return false;
2281         }
2282
2283         token.line = idParser::scriptstack->GetLineNum();
2284         token.whiteSpaceStart_p = NULL;
2285         token.whiteSpaceEnd_p = NULL;
2286         token.linesCrossed = 0;
2287         token.flags = 0;
2288         sprintf( buf, "%1.2f", fabs( value ) );
2289         token = buf;
2290         token.type = TT_NUMBER;
2291         token.subtype = TT_FLOAT | TT_LONG | TT_DECIMAL | TT_VALUESVALID;
2292         token.intvalue = (unsigned long) fabs( value );
2293         token.floatvalue = fabs( value );
2294         idParser::UnreadSourceToken( &token );
2295         if ( value < 0 ) {
2296                 idParser::UnreadSignToken();
2297         }
2298         return true;
2299 }
2300
2301 /*
2302 ================
2303 idParser::ReadDollarDirective
2304 ================
2305 */
2306 int idParser::ReadDollarDirective( void ) {
2307         idToken token;
2308
2309         // read the directive name
2310         if ( !idParser::ReadSourceToken( &token ) ) {
2311                 idParser::Error( "found '$' without name" );
2312                 return false;
2313         }
2314         // directive name must be on the same line
2315         if ( token.linesCrossed > 0 ) {
2316                 idParser::UnreadSourceToken( &token );
2317                 idParser::Error( "found '$' at end of line" );
2318                 return false;
2319         }
2320         // if if is a name
2321         if (token.type == TT_NAME) {
2322                 if ( token == "evalint" ) {
2323                         return idParser::DollarDirective_evalint();
2324                 }
2325                 else if ( token == "evalfloat" ) {
2326                         return idParser::DollarDirective_evalfloat();
2327                 }
2328         }
2329         idParser::UnreadSourceToken( &token );
2330         return false;
2331 }
2332
2333 /*
2334 ================
2335 idParser::ReadToken
2336 ================
2337 */
2338 int idParser::ReadToken( idToken *token ) {
2339         define_t *define;
2340
2341         while(1) {
2342                 if ( !idParser::ReadSourceToken( token ) ) {
2343                         return false;
2344                 }
2345                 // check for precompiler directives
2346                 if ( token->type == TT_PUNCTUATION && (*token)[0] == '#' && (*token)[1] == '\0' ) {
2347                         // read the precompiler directive
2348                         if ( !idParser::ReadDirective() ) {
2349                                 return false;
2350                         }
2351                         continue;
2352                 }
2353                 // if skipping source because of conditional compilation
2354                 if ( idParser::skip ) {
2355                         continue;
2356                 }
2357                 // recursively concatenate strings that are behind each other still resolving defines
2358                 if ( token->type == TT_STRING && !(idParser::scriptstack->GetFlags() & LEXFL_NOSTRINGCONCAT) ) {
2359                         idToken newtoken;
2360                         if ( idParser::ReadToken( &newtoken ) ) {
2361                                 if ( newtoken.type == TT_STRING ) {
2362                                         token->Append( newtoken.c_str() );
2363                                 }
2364                                 else {
2365                                         idParser::UnreadSourceToken( &newtoken );
2366                                 }
2367                         }
2368                 }
2369                 //
2370                 if ( !(idParser::scriptstack->GetFlags() & LEXFL_NODOLLARPRECOMPILE) ) {
2371                         // check for special precompiler directives
2372                         if ( token->type == TT_PUNCTUATION && (*token)[0] == '$' && (*token)[1] == '\0' ) {
2373                                 // read the precompiler directive
2374                                 if ( idParser::ReadDollarDirective() ) {
2375                                         continue;
2376                                 }
2377                         }
2378                 }
2379                 // if the token is a name
2380                 if ( token->type == TT_NAME && !( token->flags & TOKEN_FL_RECURSIVE_DEFINE ) ) {
2381                         // check if the name is a define macro
2382                         define = FindHashedDefine( idParser::definehash, token->c_str() );
2383                         // if it is a define macro
2384                         if ( define ) {
2385                                 // expand the defined macro
2386                                 if ( !idParser::ExpandDefineIntoSource( token, define ) ) {
2387                                         return false;
2388                                 }
2389                                 continue;
2390                         }
2391                 }
2392                 // found a token
2393                 return true;
2394         }
2395 }
2396
2397 /*
2398 ================
2399 idParser::ExpectTokenString
2400 ================
2401 */
2402 int idParser::ExpectTokenString( const char *string ) {
2403         idToken token;
2404
2405         if ( !idParser::ReadToken( &token ) ) {
2406                 idParser::Error( "couldn't find expected '%s'", string );
2407                 return false;
2408         }
2409
2410         if ( token != string ) {
2411                 idParser::Error( "expected '%s' but found '%s'", string, token.c_str() );
2412                 return false;
2413         }
2414         return true;
2415 }
2416
2417 /*
2418 ================
2419 idParser::ExpectTokenType
2420 ================
2421 */
2422 int idParser::ExpectTokenType( int type, int subtype, idToken *token ) {
2423         idStr str;
2424
2425         if ( !idParser::ReadToken( token ) ) {
2426                 idParser::Error( "couldn't read expected token" );
2427                 return 0;
2428         }
2429
2430         if ( token->type != type ) {
2431                 switch( type ) {
2432                         case TT_STRING: str = "string"; break;
2433                         case TT_LITERAL: str = "literal"; break;
2434                         case TT_NUMBER: str = "number"; break;
2435                         case TT_NAME: str = "name"; break;
2436                         case TT_PUNCTUATION: str = "punctuation"; break;
2437                         default: str = "unknown type"; break;
2438                 }
2439                 idParser::Error( "expected a %s but found '%s'", str.c_str(), token->c_str() );
2440                 return 0;
2441         }
2442         if ( token->type == TT_NUMBER ) {
2443                 if ( (token->subtype & subtype) != subtype ) {
2444                         str.Clear();
2445                         if ( subtype & TT_DECIMAL ) str = "decimal ";
2446                         if ( subtype & TT_HEX ) str = "hex ";
2447                         if ( subtype & TT_OCTAL ) str = "octal ";
2448                         if ( subtype & TT_BINARY ) str = "binary ";
2449                         if ( subtype & TT_UNSIGNED ) str += "unsigned ";
2450                         if ( subtype & TT_LONG ) str += "long ";
2451                         if ( subtype & TT_FLOAT ) str += "float ";
2452                         if ( subtype & TT_INTEGER ) str += "integer ";
2453                         str.StripTrailing( ' ' );
2454                         idParser::Error( "expected %s but found '%s'", str.c_str(), token->c_str() );
2455                         return 0;
2456                 }
2457         }
2458         else if ( token->type == TT_PUNCTUATION ) {
2459                 if ( subtype < 0 ) {
2460                         idParser::Error( "BUG: wrong punctuation subtype" );
2461                         return 0;
2462                 }
2463                 if ( token->subtype != subtype ) {
2464                         idParser::Error( "expected '%s' but found '%s'", scriptstack->GetPunctuationFromId( subtype ), token->c_str() );
2465                         return 0;
2466                 }
2467         }
2468         return 1;
2469 }
2470
2471 /*
2472 ================
2473 idParser::ExpectAnyToken
2474 ================
2475 */
2476 int idParser::ExpectAnyToken( idToken *token ) {
2477         if (!idParser::ReadToken( token )) {
2478                 idParser::Error( "couldn't read expected token" );
2479                 return false;
2480         }
2481         else {
2482                 return true;
2483         }
2484 }
2485
2486 /*
2487 ================
2488 idParser::CheckTokenString
2489 ================
2490 */
2491 int idParser::CheckTokenString( const char *string ) {
2492         idToken tok;
2493
2494         if ( !ReadToken( &tok ) ) {
2495                 return false;
2496         }
2497         //if the token is available
2498         if ( tok == string ) {
2499                 return true;
2500         }
2501
2502         UnreadSourceToken( &tok );
2503         return false;
2504 }
2505
2506 /*
2507 ================
2508 idParser::CheckTokenType
2509 ================
2510 */
2511 int idParser::CheckTokenType( int type, int subtype, idToken *token ) {
2512         idToken tok;
2513
2514         if ( !ReadToken( &tok ) ) {
2515                 return false;
2516         }
2517         //if the type matches
2518         if (tok.type == type && (tok.subtype & subtype) == subtype) {
2519                 *token = tok;
2520                 return true;
2521         }
2522
2523         UnreadSourceToken( &tok );
2524         return false;
2525 }
2526
2527 /*
2528 ================
2529 idParser::PeekTokenString
2530 ================
2531 */
2532 int idParser::PeekTokenString( const char *string ) {
2533         idToken tok;
2534
2535         if ( !ReadToken( &tok ) ) {
2536                 return false;
2537         }
2538
2539         UnreadSourceToken( &tok );
2540
2541         // if the token is available
2542         if ( tok == string ) {
2543                 return true;
2544         }
2545         return false;
2546 }
2547
2548 /*
2549 ================
2550 idParser::PeekTokenType
2551 ================
2552 */
2553 int idParser::PeekTokenType( int type, int subtype, idToken *token ) {
2554         idToken tok;
2555
2556         if ( !ReadToken( &tok ) ) {
2557                 return false;
2558         }
2559
2560         UnreadSourceToken( &tok );
2561
2562         // if the type matches
2563         if ( tok.type == type && ( tok.subtype & subtype ) == subtype ) {
2564                 *token = tok;
2565                 return true;
2566         }
2567         return false;
2568 }
2569
2570 /*
2571 ================
2572 idParser::SkipUntilString
2573 ================
2574 */
2575 int idParser::SkipUntilString( const char *string ) {
2576         idToken token;
2577
2578         while(idParser::ReadToken( &token )) {
2579                 if ( token == string ) {
2580                         return true;
2581                 }
2582         }
2583         return false;
2584 }
2585
2586 /*
2587 ================
2588 idParser::SkipRestOfLine
2589 ================
2590 */
2591 int idParser::SkipRestOfLine( void ) {
2592         idToken token;
2593
2594         while(idParser::ReadToken( &token )) {
2595                 if ( token.linesCrossed ) {
2596                         idParser::UnreadSourceToken( &token );
2597                         return true;
2598                 }
2599         }
2600         return false;
2601 }
2602
2603 /*
2604 =================
2605 idParser::SkipBracedSection
2606
2607 Skips until a matching close brace is found.
2608 Internal brace depths are properly skipped.
2609 =================
2610 */
2611 int idParser::SkipBracedSection( bool parseFirstBrace ) {
2612         idToken token;
2613         int depth;
2614
2615         depth = parseFirstBrace ? 0 : 1;
2616         do {
2617                 if ( !ReadToken( &token ) ) {
2618                         return false;
2619                 }
2620                 if( token.type == TT_PUNCTUATION ) {
2621                         if( token == "{" ) {
2622                                 depth++;
2623                         } else if ( token == "}" ) {
2624                                 depth--;
2625                         }
2626                 }
2627         } while( depth );
2628         return true;
2629 }
2630
2631 /*
2632 =================
2633 idParser::ParseBracedSectionExact
2634
2635 The next token should be an open brace.
2636 Parses until a matching close brace is found.
2637 Maintains the exact formating of the braced section
2638
2639   FIXME: what about precompilation ?
2640 =================
2641 */
2642 const char *idParser::ParseBracedSectionExact( idStr &out, int tabs ) {
2643         return scriptstack->ParseBracedSectionExact( out, tabs );
2644 }
2645
2646 /*
2647 =================
2648 idParser::ParseBracedSection
2649
2650 The next token should be an open brace.
2651 Parses until a matching close brace is found.
2652 Internal brace depths are properly skipped.
2653 =================
2654 */
2655 const char *idParser::ParseBracedSection( idStr &out, int tabs ) {
2656         idToken token;
2657         int i, depth;
2658         bool doTabs = false;
2659         if (tabs >= 0) {
2660                 doTabs = true;
2661         }
2662
2663         out.Empty();
2664         if ( !idParser::ExpectTokenString( "{" ) ) {
2665                 return out.c_str();
2666         }
2667         out = "{";
2668         depth = 1;
2669         do {
2670                 if ( !idParser::ReadToken( &token ) ) {
2671                         Error( "missing closing brace" );
2672                         return out.c_str();
2673                 }
2674
2675                 // if the token is on a new line
2676                 for ( i = 0; i < token.linesCrossed; i++ ) {
2677                         out += "\r\n";
2678                 }
2679
2680                 if (doTabs && token.linesCrossed) {
2681                         i = tabs;
2682                         if (token[0] == '}' && i > 0) {
2683                                 i--;
2684                         }
2685                         while (i-- > 0) {
2686                                 out += "\t";
2687                         }
2688                 }
2689                 if ( token.type == TT_PUNCTUATION ) {
2690                         if ( token[0] == '{' ) {
2691                                 depth++;
2692                                 if (doTabs) {
2693                                         tabs++;
2694                                 }
2695                         }
2696                         else if ( token[0] == '}' ) {
2697                                 depth--;
2698                                 if (doTabs) {
2699                                         tabs--;
2700                                 }
2701                         }
2702                 }
2703
2704                 if ( token.type == TT_STRING ) {
2705                         out += "\"" + token + "\"";
2706                 }
2707                 else {
2708                         out += token;
2709                 }
2710                 out += " ";
2711         } while( depth );
2712
2713         return out.c_str();
2714 }
2715
2716 /*
2717 =================
2718 idParser::ParseRestOfLine
2719
2720   parse the rest of the line
2721 =================
2722 */
2723 const char *idParser::ParseRestOfLine( idStr &out ) {
2724         idToken token;
2725
2726         out.Empty();
2727         while(idParser::ReadToken( &token )) {
2728                 if ( token.linesCrossed ) {
2729                         idParser::UnreadSourceToken( &token );
2730                         break;
2731                 }
2732                 if ( out.Length() ) {
2733                         out += " ";
2734                 }
2735                 out += token;
2736         }
2737         return out.c_str();
2738 }
2739
2740 /*
2741 ================
2742 idParser::UnreadToken
2743 ================
2744 */
2745 void idParser::UnreadToken( idToken *token ) {
2746         idParser::UnreadSourceToken( token );
2747 }
2748
2749 /*
2750 ================
2751 idParser::ReadTokenOnLine
2752 ================
2753 */
2754 int idParser::ReadTokenOnLine( idToken *token ) {
2755         idToken tok;
2756
2757         if (!idParser::ReadToken( &tok )) {
2758                 return false;
2759         }
2760         // if no lines were crossed before this token
2761         if ( !tok.linesCrossed ) {
2762                 *token = tok;
2763                 return true;
2764         }
2765         //
2766         idParser::UnreadSourceToken( &tok );
2767         return false;
2768 }
2769
2770 /*
2771 ================
2772 idParser::ParseInt
2773 ================
2774 */
2775 int idParser::ParseInt( void ) {
2776         idToken token;
2777
2778         if ( !idParser::ReadToken( &token ) ) {
2779                 idParser::Error( "couldn't read expected integer" );
2780                 return 0;
2781         }
2782         if ( token.type == TT_PUNCTUATION && token == "-" ) {
2783                 idParser::ExpectTokenType( TT_NUMBER, TT_INTEGER, &token );
2784                 return -((signed int) token.GetIntValue());
2785         }
2786         else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
2787                 idParser::Error( "expected integer value, found '%s'", token.c_str() );
2788         }
2789         return token.GetIntValue();
2790 }
2791
2792 /*
2793 ================
2794 idParser::ParseBool
2795 ================
2796 */
2797 bool idParser::ParseBool( void ) {
2798         idToken token;
2799
2800         if ( !idParser::ExpectTokenType( TT_NUMBER, 0, &token ) ) {
2801                 idParser::Error( "couldn't read expected boolean" );
2802                 return false;
2803         }
2804         return ( token.GetIntValue() != 0 );
2805 }
2806
2807 /*
2808 ================
2809 idParser::ParseFloat
2810 ================
2811 */
2812 float idParser::ParseFloat( void ) {
2813         idToken token;
2814
2815         if ( !idParser::ReadToken( &token ) ) {
2816                 idParser::Error( "couldn't read expected floating point number" );
2817                 return 0.0f;
2818         }
2819         if ( token.type == TT_PUNCTUATION && token == "-" ) {
2820                 idParser::ExpectTokenType( TT_NUMBER, 0, &token );
2821                 return -token.GetFloatValue();
2822         }
2823         else if ( token.type != TT_NUMBER ) {
2824                 idParser::Error( "expected float value, found '%s'", token.c_str() );
2825         }
2826         return token.GetFloatValue();
2827 }
2828
2829 /*
2830 ================
2831 idParser::Parse1DMatrix
2832 ================
2833 */
2834 int idParser::Parse1DMatrix( int x, float *m ) {
2835         int i;
2836
2837         if ( !idParser::ExpectTokenString( "(" ) ) {
2838                 return false;
2839         }
2840
2841         for ( i = 0; i < x; i++ ) {
2842                 m[i] = idParser::ParseFloat();
2843         }
2844
2845         if ( !idParser::ExpectTokenString( ")" ) ) {
2846                 return false;
2847         }
2848         return true;
2849 }
2850
2851 /*
2852 ================
2853 idParser::Parse2DMatrix
2854 ================
2855 */
2856 int idParser::Parse2DMatrix( int y, int x, float *m ) {
2857         int i;
2858
2859         if ( !idParser::ExpectTokenString( "(" ) ) {
2860                 return false;
2861         }
2862
2863         for ( i = 0; i < y; i++ ) {
2864                 if ( !idParser::Parse1DMatrix( x, m + i * x ) ) {
2865                         return false;
2866                 }
2867         }
2868
2869         if ( !idParser::ExpectTokenString( ")" ) ) {
2870                 return false;
2871         }
2872         return true;
2873 }
2874
2875 /*
2876 ================
2877 idParser::Parse3DMatrix
2878 ================
2879 */
2880 int idParser::Parse3DMatrix( int z, int y, int x, float *m ) {
2881         int i;
2882
2883         if ( !idParser::ExpectTokenString( "(" ) ) {
2884                 return false;
2885         }
2886
2887         for ( i = 0 ; i < z; i++ ) {
2888                 if ( !idParser::Parse2DMatrix( y, x, m + i * x*y ) ) {
2889                         return false;
2890                 }
2891         }
2892
2893         if ( !idParser::ExpectTokenString( ")" ) ) {
2894                 return false;
2895         }
2896         return true;
2897 }
2898
2899 /*
2900 ================
2901 idParser::GetLastWhiteSpace
2902 ================
2903 */
2904 int idParser::GetLastWhiteSpace( idStr &whiteSpace ) const {
2905         if ( scriptstack ) {
2906                 scriptstack->GetLastWhiteSpace( whiteSpace );
2907         } else {
2908                 whiteSpace.Clear();
2909         }
2910         return whiteSpace.Length();
2911 }
2912
2913 /*
2914 ================
2915 idParser::SetMarker
2916 ================
2917 */
2918 void idParser::SetMarker( void ) {
2919         marker_p = NULL;
2920 }
2921
2922 /*
2923 ================
2924 idParser::GetStringFromMarker
2925
2926   FIXME: this is very bad code, the script isn't even garrenteed to still be around
2927 ================
2928 */
2929 void idParser::GetStringFromMarker( idStr& out, bool clean ) {
2930         char*   p;
2931         char    save;
2932
2933         if ( marker_p == NULL ) {
2934                 marker_p = scriptstack->buffer;
2935         }
2936                 
2937         if ( tokens ) {
2938                 p = (char*)tokens->whiteSpaceStart_p;
2939         } else {
2940                 p = (char*)scriptstack->script_p;
2941         }
2942         
2943         // Set the end character to NULL to give us a complete string
2944         save = *p;
2945         *p = 0;
2946         
2947         // If cleaning then reparse
2948         if ( clean ) {  
2949                 idParser temp( marker_p, strlen( marker_p ), "temp", flags );
2950                 idToken token;
2951                 while ( temp.ReadToken ( &token ) ) {
2952                         out += token;
2953                 }
2954         } else {
2955                 out = marker_p;
2956         }
2957         
2958         // restore the character we set to NULL
2959         *p = save;              
2960 }
2961
2962 /*
2963 ================
2964 idParser::SetIncludePath
2965 ================
2966 */
2967 void idParser::SetIncludePath( const char *path ) {
2968         idParser::includepath = path;
2969         // add trailing path seperator
2970         if (idParser::includepath[idParser::includepath.Length()-1] != '\\' &&
2971                 idParser::includepath[idParser::includepath.Length()-1] != '/') {
2972                 idParser::includepath += PATHSEPERATOR_STR;
2973         }
2974 }
2975
2976 /*
2977 ================
2978 idParser::SetPunctuations
2979 ================
2980 */
2981 void idParser::SetPunctuations( const punctuation_t *p ) {
2982         idParser::punctuations = p;
2983 }
2984
2985 /*
2986 ================
2987 idParser::SetFlags
2988 ================
2989 */
2990 void idParser::SetFlags( int flags ) {
2991         idLexer *s;
2992
2993         idParser::flags = flags;
2994         for ( s = idParser::scriptstack; s; s = s->next ) {
2995                 s->SetFlags( flags );
2996         }
2997 }
2998
2999 /*
3000 ================
3001 idParser::GetFlags
3002 ================
3003 */
3004 int idParser::GetFlags( void ) const {
3005         return idParser::flags;
3006 }
3007
3008 /*
3009 ================
3010 idParser::LoadFile
3011 ================
3012 */
3013 int idParser::LoadFile( const char *filename, bool OSPath ) {
3014         idLexer *script;
3015
3016         if ( idParser::loaded ) {
3017                 idLib::common->FatalError("idParser::loadFile: another source already loaded");
3018                 return false;
3019         }
3020         script = new idLexer( filename, 0, OSPath );
3021         if ( !script->IsLoaded() ) {
3022                 delete script;
3023                 return false;
3024         }
3025         script->SetFlags( idParser::flags );
3026         script->SetPunctuations( idParser::punctuations );
3027         script->next = NULL;
3028         idParser::OSPath = OSPath;
3029         idParser::filename = filename;
3030         idParser::scriptstack = script;
3031         idParser::tokens = NULL;
3032         idParser::indentstack = NULL;
3033         idParser::skip = 0;
3034         idParser::loaded = true;
3035
3036         if ( !idParser::definehash ) {
3037                 idParser::defines = NULL;
3038                 idParser::definehash = (define_t **) Mem_ClearedAlloc( DEFINEHASHSIZE * sizeof(define_t *) );
3039                 idParser::AddGlobalDefinesToSource();
3040         }
3041         return true;
3042 }
3043
3044 /*
3045 ================
3046 idParser::LoadMemory
3047 ================
3048 */
3049 int idParser::LoadMemory(const char *ptr, int length, const char *name ) {
3050         idLexer *script;
3051
3052         if ( idParser::loaded ) {
3053                 idLib::common->FatalError("idParser::loadMemory: another source already loaded");
3054                 return false;
3055         }
3056         script = new idLexer( ptr, length, name );
3057         if ( !script->IsLoaded() ) {
3058                 delete script;
3059                 return false;
3060         }
3061         script->SetFlags( idParser::flags );
3062         script->SetPunctuations( idParser::punctuations );
3063         script->next = NULL;
3064         idParser::filename = name;
3065         idParser::scriptstack = script;
3066         idParser::tokens = NULL;
3067         idParser::indentstack = NULL;
3068         idParser::skip = 0;
3069         idParser::loaded = true;
3070
3071         if ( !idParser::definehash ) {
3072                 idParser::defines = NULL;
3073                 idParser::definehash = (define_t **) Mem_ClearedAlloc( DEFINEHASHSIZE * sizeof(define_t *) );
3074                 idParser::AddGlobalDefinesToSource();
3075         }
3076         return true;
3077 }
3078
3079 /*
3080 ================
3081 idParser::FreeSource
3082 ================
3083 */
3084 void idParser::FreeSource( bool keepDefines ) {
3085         idLexer *script;
3086         idToken *token;
3087         define_t *define;
3088         indent_t *indent;
3089         int i;
3090
3091         // free all the scripts
3092         while( scriptstack ) {
3093                 script = scriptstack;
3094                 scriptstack = scriptstack->next;
3095                 delete script;
3096         }
3097         // free all the tokens
3098         while( tokens ) {
3099                 token = tokens;
3100                 tokens = tokens->next;
3101                 delete token;
3102         }
3103         // free all indents
3104         while( indentstack ) {
3105                 indent = indentstack;
3106                 indentstack = indentstack->next;
3107                 Mem_Free( indent );
3108         }
3109         if ( !keepDefines ) {
3110                 // free hash table
3111                 if ( definehash ) {
3112                         // free defines
3113                         for ( i = 0; i < DEFINEHASHSIZE; i++ ) {
3114                                 while( definehash[i] ) {
3115                                         define = definehash[i];
3116                                         definehash[i] = definehash[i]->hashnext;
3117                                         FreeDefine(define);
3118                                 }
3119                         }
3120                         defines = NULL;
3121                         Mem_Free( idParser::definehash );
3122                         definehash = NULL;
3123                 }
3124         }
3125         loaded = false;
3126 }
3127
3128 /*
3129 ================
3130 idParser::GetPunctuationFromId
3131 ================
3132 */
3133 const char *idParser::GetPunctuationFromId( int id ) {
3134         int i;
3135
3136         if ( !idParser::punctuations ) {
3137                 idLexer lex;
3138                 return lex.GetPunctuationFromId( id );
3139         }
3140
3141         for (i = 0; idParser::punctuations[i].p; i++) {
3142                 if ( idParser::punctuations[i].n == id ) {
3143                         return idParser::punctuations[i].p;
3144                 }
3145         }
3146         return "unkown punctuation";
3147 }
3148
3149 /*
3150 ================
3151 idParser::GetPunctuationId
3152 ================
3153 */
3154 int idParser::GetPunctuationId( const char *p ) {
3155         int i;
3156
3157         if ( !idParser::punctuations ) {
3158                 idLexer lex;
3159                 return lex.GetPunctuationId( p );
3160         }
3161
3162         for (i = 0; idParser::punctuations[i].p; i++) {
3163                 if ( !strcmp(idParser::punctuations[i].p, p) ) {
3164                         return idParser::punctuations[i].n;
3165                 }
3166         }
3167         return 0;
3168 }
3169
3170 /*
3171 ================
3172 idParser::idParser
3173 ================
3174 */
3175 idParser::idParser() {
3176         this->loaded = false;
3177         this->OSPath = false;
3178         this->punctuations = 0;
3179         this->flags = 0;
3180         this->scriptstack = NULL;
3181         this->indentstack = NULL;
3182         this->definehash = NULL;
3183         this->defines = NULL;
3184         this->tokens = NULL;
3185         this->marker_p = NULL;
3186 }
3187
3188 /*
3189 ================
3190 idParser::idParser
3191 ================
3192 */
3193 idParser::idParser( int flags ) {
3194         this->loaded = false;
3195         this->OSPath = false;
3196         this->punctuations = 0;
3197         this->flags = flags;
3198         this->scriptstack = NULL;
3199         this->indentstack = NULL;
3200         this->definehash = NULL;
3201         this->defines = NULL;
3202         this->tokens = NULL;
3203         this->marker_p = NULL;
3204 }
3205
3206 /*
3207 ================
3208 idParser::idParser
3209 ================
3210 */
3211 idParser::idParser( const char *filename, int flags, bool OSPath ) {
3212         this->loaded = false;
3213         this->OSPath = true;
3214         this->punctuations = 0;
3215         this->flags = flags;
3216         this->scriptstack = NULL;
3217         this->indentstack = NULL;
3218         this->definehash = NULL;
3219         this->defines = NULL;
3220         this->tokens = NULL;
3221         this->marker_p = NULL;
3222         LoadFile( filename, OSPath );
3223 }
3224
3225 /*
3226 ================
3227 idParser::idParser
3228 ================
3229 */
3230 idParser::idParser( const char *ptr, int length, const char *name, int flags ) {
3231         this->loaded = false;
3232         this->OSPath = false;
3233         this->punctuations = 0;
3234         this->flags = flags;
3235         this->scriptstack = NULL;
3236         this->indentstack = NULL;
3237         this->definehash = NULL;
3238         this->defines = NULL;
3239         this->tokens = NULL;
3240         this->marker_p = NULL;
3241         LoadMemory( ptr, length, name );
3242 }
3243
3244 /*
3245 ================
3246 idParser::~idParser
3247 ================
3248 */
3249 idParser::~idParser( void ) {
3250         idParser::FreeSource( false );
3251 }
3252