Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

l_precomp.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 
00024 /*****************************************************************************
00025  * name:        l_precomp.c
00026  *
00027  * desc:        pre compiler
00028  *
00029  * $Archive: /MissionPack/code/botlib/l_precomp.c $
00030  *
00031  *****************************************************************************/
00032 
00033 //Notes:            fix: PC_StringizeTokens
00034 
00035 //#define SCREWUP
00036 //#define BOTLIB
00037 //#define QUAKE
00038 //#define QUAKEC
00039 //#define MEQCC
00040 
00041 #ifdef SCREWUP
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <limits.h>
00045 #include <string.h>
00046 #include <stdarg.h>
00047 #include <time.h>
00048 #include "l_memory.h"
00049 #include "l_script.h"
00050 #include "l_precomp.h"
00051 
00052 typedef enum {qfalse, qtrue}    qboolean;
00053 #endif //SCREWUP
00054 
00055 #ifdef BOTLIB
00056 #include "../game/q_shared.h"
00057 #include "../game/botlib.h"
00058 #include "be_interface.h"
00059 #include "l_memory.h"
00060 #include "l_script.h"
00061 #include "l_precomp.h"
00062 #include "l_log.h"
00063 #endif //BOTLIB
00064 
00065 #ifdef MEQCC
00066 #include "qcc.h"
00067 #include "time.h"   //time & ctime
00068 #include "math.h"   //fabs
00069 #include "l_memory.h"
00070 #include "l_script.h"
00071 #include "l_precomp.h"
00072 #include "l_log.h"
00073 
00074 #define qtrue   true
00075 #define qfalse  false
00076 #endif //MEQCC
00077 
00078 #ifdef BSPC
00079 //include files for usage in the BSP Converter
00080 #include "../bspc/qbsp.h"
00081 #include "../bspc/l_log.h"
00082 #include "../bspc/l_mem.h"
00083 #include "l_precomp.h"
00084 
00085 #define qtrue   true
00086 #define qfalse  false
00087 #define Q_stricmp   stricmp
00088 
00089 #endif //BSPC
00090 
00091 #if defined(QUAKE) && !defined(BSPC)
00092 #include "l_utils.h"
00093 #endif //QUAKE
00094 
00095 //#define DEBUG_EVAL
00096 
00097 #define MAX_DEFINEPARMS         128
00098 
00099 #define DEFINEHASHING           1
00100 
00101 //directive name with parse function
00102 typedef struct directive_s
00103 {
00104     char *name;
00105     int (*func)(source_t *source);
00106 } directive_t;
00107 
00108 #define DEFINEHASHSIZE      1024
00109 
00110 #define TOKEN_HEAP_SIZE     4096
00111 
00112 int numtokens;
00113 /*
00114 int tokenheapinitialized;               //true when the token heap is initialized
00115 token_t token_heap[TOKEN_HEAP_SIZE];    //heap with tokens
00116 token_t *freetokens;                    //free tokens from the heap
00117 */
00118 
00119 //list with global defines added to every source loaded
00120 define_t *globaldefines;
00121 
00122 //============================================================================
00123 //
00124 // Parameter:               -
00125 // Returns:                 -
00126 // Changes Globals:     -
00127 //============================================================================
00128 void QDECL SourceError(source_t *source, char *str, ...)
00129 {
00130     char text[1024];
00131     va_list ap;
00132 
00133     va_start(ap, str);
00134     vsprintf(text, str, ap);
00135     va_end(ap);
00136 #ifdef BOTLIB
00137     botimport.Print(PRT_ERROR, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00138 #endif  //BOTLIB
00139 #ifdef MEQCC
00140     printf("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00141 #endif //MEQCC
00142 #ifdef BSPC
00143     Log_Print("error: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00144 #endif //BSPC
00145 } //end of the function SourceError
00146 //===========================================================================
00147 //
00148 // Parameter:               -
00149 // Returns:                 -
00150 // Changes Globals:     -
00151 //===========================================================================
00152 void QDECL SourceWarning(source_t *source, char *str, ...)
00153 {
00154     char text[1024];
00155     va_list ap;
00156 
00157     va_start(ap, str);
00158     vsprintf(text, str, ap);
00159     va_end(ap);
00160 #ifdef BOTLIB
00161     botimport.Print(PRT_WARNING, "file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00162 #endif //BOTLIB
00163 #ifdef MEQCC
00164     printf("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00165 #endif //MEQCC
00166 #ifdef BSPC
00167     Log_Print("warning: file %s, line %d: %s\n", source->scriptstack->filename, source->scriptstack->line, text);
00168 #endif //BSPC
00169 } //end of the function ScriptWarning
00170 //============================================================================
00171 //
00172 // Parameter:               -
00173 // Returns:                 -
00174 // Changes Globals:     -
00175 //============================================================================
00176 void PC_PushIndent(source_t *source, int type, int skip)
00177 {
00178     indent_t *indent;
00179 
00180     indent = (indent_t *) GetMemory(sizeof(indent_t));
00181     indent->type = type;
00182     indent->script = source->scriptstack;
00183     indent->skip = (skip != 0);
00184     source->skip += indent->skip;
00185     indent->next = source->indentstack;
00186     source->indentstack = indent;
00187 } //end of the function PC_PushIndent
00188 //============================================================================
00189 //
00190 // Parameter:               -
00191 // Returns:                 -
00192 // Changes Globals:     -
00193 //============================================================================
00194 void PC_PopIndent(source_t *source, int *type, int *skip)
00195 {
00196     indent_t *indent;
00197 
00198     *type = 0;
00199     *skip = 0;
00200 
00201     indent = source->indentstack;
00202     if (!indent) return;
00203 
00204     //must be an indent from the current script
00205     if (source->indentstack->script != source->scriptstack) return;
00206 
00207     *type = indent->type;
00208     *skip = indent->skip;
00209     source->indentstack = source->indentstack->next;
00210     source->skip -= indent->skip;
00211     FreeMemory(indent);
00212 } //end of the function PC_PopIndent
00213 //============================================================================
00214 //
00215 // Parameter:               -
00216 // Returns:                 -
00217 // Changes Globals:     -
00218 //============================================================================
00219 void PC_PushScript(source_t *source, script_t *script)
00220 {
00221     script_t *s;
00222 
00223     for (s = source->scriptstack; s; s = s->next)
00224     {
00225         if (!Q_stricmp(s->filename, script->filename))
00226         {
00227             SourceError(source, "%s recursively included", script->filename);
00228             return;
00229         } //end if
00230     } //end for
00231     //push the script on the script stack
00232     script->next = source->scriptstack;
00233     source->scriptstack = script;
00234 } //end of the function PC_PushScript
00235 //============================================================================
00236 //
00237 // Parameter:           -
00238 // Returns:             -
00239 // Changes Globals:     -
00240 //============================================================================
00241 void PC_InitTokenHeap(void)
00242 {
00243     /*
00244     int i;
00245 
00246     if (tokenheapinitialized) return;
00247     freetokens = NULL;
00248     for (i = 0; i < TOKEN_HEAP_SIZE; i++)
00249     {
00250         token_heap[i].next = freetokens;
00251         freetokens = &token_heap[i];
00252     } //end for
00253     tokenheapinitialized = qtrue;
00254     */
00255 } //end of the function PC_InitTokenHeap
00256 //============================================================================
00257 //
00258 // Parameter:           -
00259 // Returns:             -
00260 // Changes Globals:     -
00261 //============================================================================
00262 token_t *PC_CopyToken(token_t *token)
00263 {
00264     token_t *t;
00265 
00266 //  t = (token_t *) malloc(sizeof(token_t));
00267     t = (token_t *) GetMemory(sizeof(token_t));
00268 //  t = freetokens;
00269     if (!t)
00270     {
00271 #ifdef BSPC
00272         Error("out of token space\n");
00273 #else
00274         Com_Error(ERR_FATAL, "out of token space\n");
00275 #endif
00276         return NULL;
00277     } //end if
00278 //  freetokens = freetokens->next;
00279     Com_Memcpy(t, token, sizeof(token_t));
00280     t->next = NULL;
00281     numtokens++;
00282     return t;
00283 } //end of the function PC_CopyToken
00284 //============================================================================
00285 //
00286 // Parameter:               -
00287 // Returns:                 -
00288 // Changes Globals:     -
00289 //============================================================================
00290 void PC_FreeToken(token_t *token)
00291 {
00292     //free(token);
00293     FreeMemory(token);
00294 //  token->next = freetokens;
00295 //  freetokens = token;
00296     numtokens--;
00297 } //end of the function PC_FreeToken
00298 //============================================================================
00299 //
00300 // Parameter:               -
00301 // Returns:                 -
00302 // Changes Globals:     -
00303 //============================================================================
00304 int PC_ReadSourceToken(source_t *source, token_t *token)
00305 {
00306     token_t *t;
00307     script_t *script;
00308     int type, skip;
00309 
00310     //if there's no token already available
00311     while(!source->tokens)
00312     {
00313         //if there's a token to read from the script
00314         if (PS_ReadToken(source->scriptstack, token)) return qtrue;
00315         //if at the end of the script
00316         if (EndOfScript(source->scriptstack))
00317         {
00318             //remove all indents of the script
00319             while(source->indentstack &&
00320                     source->indentstack->script == source->scriptstack)
00321             {
00322                 SourceWarning(source, "missing #endif");
00323                 PC_PopIndent(source, &type, &skip);
00324             } //end if
00325         } //end if
00326         //if this was the initial script
00327         if (!source->scriptstack->next) return qfalse;
00328         //remove the script and return to the last one
00329         script = source->scriptstack;
00330         source->scriptstack = source->scriptstack->next;
00331         FreeScript(script);
00332     } //end while
00333     //copy the already available token
00334     Com_Memcpy(token, source->tokens, sizeof(token_t));
00335     //free the read token
00336     t = source->tokens;
00337     source->tokens = source->tokens->next;
00338     PC_FreeToken(t);
00339     return qtrue;
00340 } //end of the function PC_ReadSourceToken
00341 //============================================================================
00342 //
00343 // Parameter:               -
00344 // Returns:                 -
00345 // Changes Globals:     -
00346 //============================================================================
00347 int PC_UnreadSourceToken(source_t *source, token_t *token)
00348 {
00349     token_t *t;
00350 
00351     t = PC_CopyToken(token);
00352     t->next = source->tokens;
00353     source->tokens = t;
00354     return qtrue;
00355 } //end of the function PC_UnreadSourceToken
00356 //============================================================================
00357 //
00358 // Parameter:               -
00359 // Returns:                 -
00360 // Changes Globals:     -
00361 //============================================================================
00362 int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int maxparms)
00363 {
00364     token_t token, *t, *last;
00365     int i, done, lastcomma, numparms, indent;
00366 
00367     if (!PC_ReadSourceToken(source, &token))
00368     {
00369         SourceError(source, "define %s missing parms", define->name);
00370         return qfalse;
00371     } //end if
00372     //
00373     if (define->numparms > maxparms)
00374     {
00375         SourceError(source, "define with more than %d parameters", maxparms);
00376         return qfalse;
00377     } //end if
00378     //
00379     for (i = 0; i < define->numparms; i++) parms[i] = NULL;
00380     //if no leading "("
00381     if (strcmp(token.string, "("))
00382     {
00383         PC_UnreadSourceToken(source, &token);
00384         SourceError(source, "define %s missing parms", define->name);
00385         return qfalse;
00386     } //end if
00387     //read the define parameters
00388     for (done = 0, numparms = 0, indent = 0; !done;)
00389     {
00390         if (numparms >= maxparms)
00391         {
00392             SourceError(source, "define %s with too many parms", define->name);
00393             return qfalse;
00394         } //end if
00395         if (numparms >= define->numparms)
00396         {
00397             SourceWarning(source, "define %s has too many parms", define->name);
00398             return qfalse;
00399         } //end if
00400         parms[numparms] = NULL;
00401         lastcomma = 1;
00402         last = NULL;
00403         while(!done)
00404         {
00405             //
00406             if (!PC_ReadSourceToken(source, &token))
00407             {
00408                 SourceError(source, "define %s incomplete", define->name);
00409                 return qfalse;
00410             } //end if
00411             //
00412             if (!strcmp(token.string, ","))
00413             {
00414                 if (indent <= 0)
00415                 {
00416                     if (lastcomma) SourceWarning(source, "too many comma's");
00417                     lastcomma = 1;
00418                     break;
00419                 } //end if
00420             } //end if
00421             lastcomma = 0;
00422             //
00423             if (!strcmp(token.string, "("))
00424             {
00425                 indent++;
00426                 continue;
00427             } //end if
00428             else if (!strcmp(token.string, ")"))
00429             {
00430                 if (--indent <= 0)
00431                 {
00432                     if (!parms[define->numparms-1])
00433                     {
00434                         SourceWarning(source, "too few define parms");
00435                     } //end if
00436                     done = 1;
00437                     break;
00438                 } //end if
00439             } //end if
00440             //
00441             if (numparms < define->numparms)
00442             {
00443                 //
00444                 t = PC_CopyToken(&token);
00445                 t->next = NULL;
00446                 if (last) last->next = t;
00447                 else parms[numparms] = t;
00448                 last = t;
00449             } //end if
00450         } //end while
00451         numparms++;
00452     } //end for
00453     return qtrue;
00454 } //end of the function PC_ReadDefineParms
00455 //============================================================================
00456 //
00457 // Parameter:               -
00458 // Returns:                 -
00459 // Changes Globals:     -
00460 //============================================================================
00461 int PC_StringizeTokens(token_t *tokens, token_t *token)
00462 {
00463     token_t *t;
00464 
00465     token->type = TT_STRING;
00466     token->whitespace_p = NULL;
00467     token->endwhitespace_p = NULL;
00468     token->string[0] = '\0';
00469     strcat(token->string, "\"");
00470     for (t = tokens; t; t = t->next)
00471     {
00472         strncat(token->string, t->string, MAX_TOKEN - strlen(token->string));
00473     } //end for
00474     strncat(token->string, "\"", MAX_TOKEN - strlen(token->string));
00475     return qtrue;
00476 } //end of the function PC_StringizeTokens
00477 //============================================================================
00478 //
00479 // Parameter:               -
00480 // Returns:                 -
00481 // Changes Globals:     -
00482 //============================================================================
00483 int PC_MergeTokens(token_t *t1, token_t *t2)
00484 {
00485     //merging of a name with a name or number
00486     if (t1->type == TT_NAME && (t2->type == TT_NAME || t2->type == TT_NUMBER))
00487     {
00488         strcat(t1->string, t2->string);
00489         return qtrue;
00490     } //end if
00491     //merging of two strings
00492     if (t1->type == TT_STRING && t2->type == TT_STRING)
00493     {
00494         //remove trailing double quote
00495         t1->string[strlen(t1->string)-1] = '\0';
00496         //concat without leading double quote
00497         strcat(t1->string, &t2->string[1]);
00498         return qtrue;
00499     } //end if
00500     //FIXME: merging of two number of the same sub type
00501     return qfalse;
00502 } //end of the function PC_MergeTokens
00503 //============================================================================
00504 //
00505 // Parameter:               -
00506 // Returns:                 -
00507 // Changes Globals:     -
00508 //============================================================================
00509 /*
00510 void PC_PrintDefine(define_t *define)
00511 {
00512     printf("define->name = %s\n", define->name);
00513     printf("define->flags = %d\n", define->flags);
00514     printf("define->builtin = %d\n", define->builtin);
00515     printf("define->numparms = %d\n", define->numparms);
00516 //  token_t *parms;                 //define parameters
00517 //  token_t *tokens;                    //macro tokens (possibly containing parm tokens)
00518 //  struct define_s *next;          //next defined macro in a list
00519 } //end of the function PC_PrintDefine*/
00520 #if DEFINEHASHING
00521 //============================================================================
00522 //
00523 // Parameter:               -
00524 // Returns:                 -
00525 // Changes Globals:     -
00526 //============================================================================
00527 void PC_PrintDefineHashTable(define_t **definehash)
00528 {
00529     int i;
00530     define_t *d;
00531 
00532     for (i = 0; i < DEFINEHASHSIZE; i++)
00533     {
00534         Log_Write("%4d:", i);
00535         for (d = definehash[i]; d; d = d->hashnext)
00536         {
00537             Log_Write(" %s", d->name);
00538         } //end for
00539         Log_Write("\n");
00540     } //end for
00541 } //end of the function PC_PrintDefineHashTable
00542 //============================================================================
00543 //
00544 // Parameter:               -
00545 // Returns:                 -
00546 // Changes Globals:     -
00547 //============================================================================
00548 //char primes[16] = {1, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47};
00549 
00550 int PC_NameHash(char *name)
00551 {
00552     int register hash, i;
00553 
00554     hash = 0;
00555     for (i = 0; name[i] != '\0'; i++)
00556     {
00557         hash += name[i] * (119 + i);
00558         //hash += (name[i] << 7) + i;
00559         //hash += (name[i] << (i&15));
00560     } //end while
00561     hash = (hash ^ (hash >> 10) ^ (hash >> 20)) & (DEFINEHASHSIZE-1);
00562     return hash;
00563 } //end of the function PC_NameHash
00564 //============================================================================
00565 //
00566 // Parameter:               -
00567 // Returns:                 -
00568 // Changes Globals:     -
00569 //============================================================================
00570 void PC_AddDefineToHash(define_t *define, define_t **definehash)
00571 {
00572     int hash;
00573 
00574     hash = PC_NameHash(define->name);
00575     define->hashnext = definehash[hash];
00576     definehash[hash] = define;
00577 } //end of the function PC_AddDefineToHash
00578 //============================================================================
00579 //
00580 // Parameter:               -
00581 // Returns:                 -
00582 // Changes Globals:     -
00583 //============================================================================
00584 define_t *PC_FindHashedDefine(define_t **definehash, char *name)
00585 {
00586     define_t *d;
00587     int hash;
00588 
00589     hash = PC_NameHash(name);
00590     for (d = definehash[hash]; d; d = d->hashnext)
00591     {
00592         if (!strcmp(d->name, name)) return d;
00593     } //end for
00594     return NULL;
00595 } //end of the function PC_FindHashedDefine
00596 #endif //DEFINEHASHING
00597 //============================================================================
00598 //
00599 // Parameter:               -
00600 // Returns:                 -
00601 // Changes Globals:     -
00602 //============================================================================
00603 define_t *PC_FindDefine(define_t *defines, char *name)
00604 {
00605     define_t *d;
00606 
00607     for (d = defines; d; d = d->next)
00608     {
00609         if (!strcmp(d->name, name)) return d;
00610     } //end for
00611     return NULL;
00612 } //end of the function PC_FindDefine
00613 //============================================================================
00614 //
00615 // Parameter:               -
00616 // Returns:                 number of the parm
00617 //                              if no parm found with the given name -1 is returned
00618 // Changes Globals:     -
00619 //============================================================================
00620 int PC_FindDefineParm(define_t *define, char *name)
00621 {
00622     token_t *p;
00623     int i;
00624 
00625     i = 0;
00626     for (p = define->parms; p; p = p->next)
00627     {
00628         if (!strcmp(p->string, name)) return i;
00629         i++;
00630     } //end for
00631     return -1;
00632 } //end of the function PC_FindDefineParm
00633 //============================================================================
00634 //
00635 // Parameter:               -
00636 // Returns:                 -
00637 // Changes Globals:     -
00638 //============================================================================
00639 void PC_FreeDefine(define_t *define)
00640 {
00641     token_t *t, *next;
00642 
00643     //free the define parameters
00644     for (t = define->parms; t; t = next)
00645     {
00646         next = t->next;
00647         PC_FreeToken(t);
00648     } //end for
00649     //free the define tokens
00650     for (t = define->tokens; t; t = next)
00651     {
00652         next = t->next;
00653         PC_FreeToken(t);
00654     } //end for
00655     //free the define
00656     FreeMemory(define);
00657 } //end of the function PC_FreeDefine
00658 //============================================================================
00659 //
00660 // Parameter:               -
00661 // Returns:                 -
00662 // Changes Globals:     -
00663 //============================================================================
00664 void PC_AddBuiltinDefines(source_t *source)
00665 {
00666     int i;
00667     define_t *define;
00668     struct builtin
00669     {
00670         char *string;
00671         int builtin;
00672     } builtin[] = { // bk001204 - brackets
00673         { "__LINE__",   BUILTIN_LINE },
00674         { "__FILE__",   BUILTIN_FILE },
00675         { "__DATE__",   BUILTIN_DATE },
00676         { "__TIME__",   BUILTIN_TIME },
00677 //      { "__STDC__", BUILTIN_STDC },
00678         { NULL, 0 }
00679     };
00680 
00681     for (i = 0; builtin[i].string; i++)
00682     {
00683         define = (define_t *) GetMemory(sizeof(define_t) + strlen(builtin[i].string) + 1);
00684         Com_Memset(define, 0, sizeof(define_t));
00685         define->name = (char *) define + sizeof(define_t);
00686         strcpy(define->name, builtin[i].string);
00687         define->flags |= DEFINE_FIXED;
00688         define->builtin = builtin[i].builtin;
00689         //add the define to the source
00690 #if DEFINEHASHING
00691         PC_AddDefineToHash(define, source->definehash);
00692 #else
00693         define->next = source->defines;
00694         source->defines = define;
00695 #endif //DEFINEHASHING
00696     } //end for
00697 } //end of the function PC_AddBuiltinDefines
00698 //============================================================================
00699 //
00700 // Parameter:               -
00701 // Returns:                 -
00702 // Changes Globals:     -
00703 //============================================================================
00704 int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define,
00705                                         token_t **firsttoken, token_t **lasttoken)
00706 {
00707     token_t *token;
00708     unsigned long t;    //  time_t t; //to prevent LCC warning
00709     char *curtime;
00710 
00711     token = PC_CopyToken(deftoken);
00712     switch(define->builtin)
00713     {
00714         case BUILTIN_LINE:
00715         {
00716             sprintf(token->string, "%d", deftoken->line);
00717 #ifdef NUMBERVALUE
00718             token->intvalue = deftoken->line;
00719             token->floatvalue = deftoken->line;
00720 #endif //NUMBERVALUE
00721             token->type = TT_NUMBER;
00722             token->subtype = TT_DECIMAL | TT_INTEGER;
00723             *firsttoken = token;
00724             *lasttoken = token;
00725             break;
00726         } //end case
00727         case BUILTIN_FILE:
00728         {
00729             strcpy(token->string, source->scriptstack->filename);
00730             token->type = TT_NAME;
00731             token->subtype = strlen(token->string);
00732             *firsttoken = token;
00733             *lasttoken = token;
00734             break;
00735         } //end case
00736         case BUILTIN_DATE:
00737         {
00738             t = time(NULL);
00739             curtime = ctime(&t);
00740             strcpy(token->string, "\"");
00741             strncat(token->string, curtime+4, 7);
00742             strncat(token->string+7, curtime+20, 4);
00743             strcat(token->string, "\"");
00744             free(curtime);
00745             token->type = TT_NAME;
00746             token->subtype = strlen(token->string);
00747             *firsttoken = token;
00748             *lasttoken = token;
00749             break;
00750         } //end case
00751         case BUILTIN_TIME:
00752         {
00753             t = time(NULL);
00754             curtime = ctime(&t);
00755             strcpy(token->string, "\"");
00756             strncat(token->string, curtime+11, 8);
00757             strcat(token->string, "\"");
00758             free(curtime);
00759             token->type = TT_NAME;
00760             token->subtype = strlen(token->string);
00761             *firsttoken = token;
00762             *lasttoken = token;
00763             break;
00764         } //end case
00765         case BUILTIN_STDC:
00766         default:
00767         {
00768             *firsttoken = NULL;
00769             *lasttoken = NULL;
00770             break;
00771         } //end case
00772     } //end switch
00773     return qtrue;
00774 } //end of the function PC_ExpandBuiltinDefine
00775 //============================================================================
00776 //
00777 // Parameter:               -
00778 // Returns:                 -
00779 // Changes Globals:     -
00780 //============================================================================
00781 int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define,
00782                                         token_t **firsttoken, token_t **lasttoken)
00783 {
00784     token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t;
00785     token_t *t1, *t2, *first, *last, *nextpt, token;
00786     int parmnum, i;
00787 
00788     //if it is a builtin define
00789     if (define->builtin)
00790     {
00791         return PC_ExpandBuiltinDefine(source, deftoken, define, firsttoken, lasttoken);
00792     } //end if
00793     //if the define has parameters
00794     if (define->numparms)
00795     {
00796         if (!PC_ReadDefineParms(source, define, parms, MAX_DEFINEPARMS)) return qfalse;
00797 #ifdef DEBUG_EVAL
00798         for (i = 0; i < define->numparms; i++)
00799         {
00800             Log_Write("define parms %d:", i);
00801             for (pt = parms[i]; pt; pt = pt->next)
00802             {
00803                 Log_Write("%s", pt->string);
00804             } //end for
00805         } //end for
00806 #endif //DEBUG_EVAL
00807     } //end if
00808     //empty list at first
00809     first = NULL;
00810     last = NULL;
00811     //create a list with tokens of the expanded define
00812     for (dt = define->tokens; dt; dt = dt->next)
00813     {
00814         parmnum = -1;
00815         //if the token is a name, it could be a define parameter
00816         if (dt->type == TT_NAME)
00817         {
00818             parmnum = PC_FindDefineParm(define, dt->string);
00819         } //end if
00820         //if it is a define parameter
00821         if (parmnum >= 0)
00822         {
00823             for (pt = parms[parmnum]; pt; pt = pt->next)
00824             {
00825                 t = PC_CopyToken(pt);
00826                 //add the token to the list
00827                 t->next = NULL;
00828                 if (last) last->next = t;
00829                 else first = t;
00830                 last = t;
00831             } //end for
00832         } //end if
00833         else
00834         {
00835             //if stringizing operator
00836             if (dt->string[0] == '#' && dt->string[1] == '\0')
00837             {
00838                 //the stringizing operator must be followed by a define parameter
00839                 if (dt->next) parmnum = PC_FindDefineParm(define, dt->next->string);
00840                 else parmnum = -1;
00841                 //
00842                 if (parmnum >= 0)
00843                 {
00844                     //step over the stringizing operator
00845                     dt = dt->next;
00846                     //stringize the define parameter tokens
00847                     if (!PC_StringizeTokens(parms[parmnum], &token))
00848                     {
00849                         SourceError(source, "can't stringize tokens");
00850                         return qfalse;
00851                     } //end if
00852                     t = PC_CopyToken(&token);
00853                 } //end if
00854                 else
00855                 {
00856                     SourceWarning(source, "stringizing operator without define parameter");
00857                     continue;
00858                 } //end if
00859             } //end if
00860             else
00861             {
00862                 t = PC_CopyToken(dt);
00863             } //end else
00864             //add the token to the list
00865             t->next = NULL;
00866             if (last) last->next = t;
00867             else first = t;
00868             last = t;
00869         } //end else
00870     } //end for
00871     //check for the merging operator
00872     for (t = first; t; )
00873     {
00874         if (t->next)
00875         {
00876             //if the merging operator
00877             if (t->next->string[0] == '#' && t->next->string[1] == '#')
00878             {
00879                 t1 = t;
00880                 t2 = t->next->next;
00881                 if (t2)
00882                 {
00883                     if (!PC_MergeTokens(t1, t2))
00884                     {
00885                         SourceError(source, "can't merge %s with %s", t1->string, t2->string);
00886                         return qfalse;
00887                     } //end if
00888                     PC_FreeToken(t1->next);
00889                     t1->next = t2->next;
00890                     if (t2 == last) last = t1;
00891                     PC_FreeToken(t2);
00892                     continue;
00893                 } //end if
00894             } //end if
00895         } //end if
00896         t = t->next;
00897     } //end for
00898     //store the first and last token of the list
00899     *firsttoken = first;
00900     *lasttoken = last;
00901     //free all the parameter tokens
00902     for (i = 0; i < define->numparms; i++)
00903     {
00904         for (pt = parms[i]; pt; pt = nextpt)
00905         {
00906             nextpt = pt->next;
00907             PC_FreeToken(pt);
00908         } //end for
00909     } //end for
00910     //
00911     return qtrue;
00912 } //end of the function PC_ExpandDefine
00913 //============================================================================
00914 //
00915 // Parameter:               -
00916 // Returns:                 -
00917 // Changes Globals:     -
00918 //============================================================================
00919 int PC_ExpandDefineIntoSource(source_t *source, token_t *deftoken, define_t *define)
00920 {
00921     token_t *firsttoken, *lasttoken;
00922 
00923     if (!PC_ExpandDefine(source, deftoken, define, &firsttoken, &lasttoken)) return qfalse;
00924 
00925     if (firsttoken && lasttoken)
00926     {
00927         lasttoken->next = source->tokens;
00928         source->tokens = firsttoken;
00929         return qtrue;
00930     } //end if
00931     return qfalse;
00932 } //end of the function PC_ExpandDefineIntoSource
00933 //============================================================================
00934 //
00935 // Parameter:               -
00936 // Returns:                 -
00937 // Changes Globals:     -
00938 //============================================================================
00939 void PC_ConvertPath(char *path)
00940 {
00941     char *ptr;
00942 
00943     //remove double path seperators
00944     for (ptr = path; *ptr;)
00945     {
00946         if ((*ptr == '\\' || *ptr == '/') &&
00947                 (*(ptr+1) == '\\' || *(ptr+1) == '/'))
00948         {
00949             strcpy(ptr, ptr+1);
00950         } //end if
00951         else
00952         {
00953             ptr++;
00954         } //end else
00955     } //end while
00956     //set OS dependent path seperators
00957     for (ptr = path; *ptr;)
00958     {
00959         if (*ptr == '/' || *ptr == '\\') *ptr = PATHSEPERATOR_CHAR;
00960         ptr++;
00961     } //end while
00962 } //end of the function PC_ConvertPath
00963 //============================================================================
00964 //
00965 // Parameter:               -
00966 // Returns:                 -
00967 // Changes Globals:     -
00968 //============================================================================
00969 int PC_Directive_include(source_t *source)
00970 {
00971     script_t *script;
00972     token_t token;
00973     char path[MAX_PATH];
00974 #ifdef QUAKE
00975     foundfile_t file;
00976 #endif //QUAKE
00977 
00978     if (source->skip > 0) return qtrue;
00979     //
00980     if (!PC_ReadSourceToken(source, &token))
00981     {
00982         SourceError(source, "#include without file name");
00983         return qfalse;
00984     } //end if
00985     if (token.linescrossed > 0)
00986     {
00987         SourceError(source, "#include without file name");
00988         return qfalse;
00989     } //end if
00990     if (token.type == TT_STRING)
00991     {
00992         StripDoubleQuotes(token.string);
00993         PC_ConvertPath(token.string);
00994         script = LoadScriptFile(token.string);
00995         if (!script)
00996         {
00997             strcpy(path, source->includepath);
00998             strcat(path, token.string);
00999             script = LoadScriptFile(path);
01000         } //end if
01001     } //end if
01002     else if (token.type == TT_PUNCTUATION && *token.string == '<')
01003     {
01004         strcpy(path, source->includepath);
01005         while(PC_ReadSourceToken(source, &token))
01006         {
01007             if (token.linescrossed > 0)
01008             {
01009                 PC_UnreadSourceToken(source, &token);
01010                 break;
01011             } //end if
01012             if (token.type == TT_PUNCTUATION && *token.string == '>') break;
01013             strncat(path, token.string, MAX_PATH);
01014         } //end while
01015         if (*token.string != '>')
01016         {
01017             SourceWarning(source, "#include missing trailing >");
01018         } //end if
01019         if (!strlen(path))
01020         {
01021             SourceError(source, "#include without file name between < >");
01022             return qfalse;
01023         } //end if
01024         PC_ConvertPath(path);
01025         script = LoadScriptFile(path);
01026     } //end if
01027     else
01028     {
01029         SourceError(source, "#include without file name");
01030         return qfalse;
01031     } //end else
01032 #ifdef QUAKE
01033     if (!script)
01034     {
01035         Com_Memset(&file, 0, sizeof(foundfile_t));
01036         script = LoadScriptFile(path);
01037         if (script) strncpy(script->filename, path, MAX_PATH);
01038     } //end if
01039 #endif //QUAKE
01040     if (!script)
01041     {
01042 #ifdef SCREWUP
01043         SourceWarning(source, "file %s not found", path);
01044         return qtrue;
01045 #else
01046         SourceError(source, "file %s not found", path);
01047         return qfalse;
01048 #endif //SCREWUP
01049     } //end if
01050     PC_PushScript(source, script);
01051     return qtrue;
01052 } //end of the function PC_Directive_include
01053 //============================================================================
01054 // reads a token from the current line, continues reading on the next
01055 // line only if a backslash '\' is encountered.
01056 //
01057 // Parameter:               -
01058 // Returns:                 -
01059 // Changes Globals:     -
01060 //============================================================================
01061 int PC_ReadLine(source_t *source, token_t *token)
01062 {
01063     int crossline;
01064 
01065     crossline = 0;
01066     do
01067     {
01068         if (!PC_ReadSourceToken(source, token)) return qfalse;
01069         
01070         if (token->linescrossed > crossline)
01071         {
01072             PC_UnreadSourceToken(source, token);
01073             return qfalse;
01074         } //end if
01075         crossline = 1;
01076     } while(!strcmp(token->string, "\\"));
01077     return qtrue;
01078 } //end of the function PC_ReadLine
01079 //============================================================================
01080 //
01081 // Parameter:               -
01082 // Returns:                 -
01083 // Changes Globals:     -
01084 //============================================================================
01085 int PC_WhiteSpaceBeforeToken(token_t *token)
01086 {
01087     return token->endwhitespace_p - token->whitespace_p > 0;
01088 } //end of the function PC_WhiteSpaceBeforeToken
01089 //============================================================================
01090 //
01091 // Parameter:               -
01092 // Returns:                 -
01093 // Changes Globals:     -
01094 //============================================================================
01095 void PC_ClearTokenWhiteSpace(token_t *token)
01096 {
01097     token->whitespace_p = NULL;
01098     token->endwhitespace_p = NULL;
01099     token->linescrossed = 0;
01100 } //end of the function PC_ClearTokenWhiteSpace
01101 //============================================================================
01102 //
01103 // Parameter:               -
01104 // Returns:                 -
01105 // Changes Globals:     -
01106 //============================================================================
01107 int PC_Directive_undef(source_t *source)
01108 {
01109     token_t token;
01110     define_t *define, *lastdefine;
01111     int hash;
01112 
01113     if (source->skip > 0) return qtrue;
01114     //
01115     if (!PC_ReadLine(source, &token))
01116     {
01117         SourceError(source, "undef without name");
01118         return qfalse;
01119     } //end if
01120     if (token.type != TT_NAME)
01121     {
01122         PC_UnreadSourceToken(source, &token);
01123         SourceError(source, "expected name, found %s", token.string);
01124         return qfalse;
01125     } //end if
01126 #if DEFINEHASHING
01127 
01128     hash = PC_NameHash(token.string);
01129     for (lastdefine = NULL, define = source->definehash[hash]; define; define = define->hashnext)
01130     {
01131         if (!strcmp(define->name, token.string))
01132         {
01133             if (define->flags & DEFINE_FIXED)
01134             {
01135                 SourceWarning(source, "can't undef %s", token.string);
01136             } //end if
01137             else
01138             {
01139                 if (lastdefine) lastdefine->hashnext = define->hashnext;
01140                 else source->definehash[hash] = define->hashnext;
01141                 PC_FreeDefine(define);
01142             } //end else
01143             break;
01144         } //end if
01145         lastdefine = define;
01146     } //end for
01147 #else //DEFINEHASHING
01148     for (lastdefine = NULL, define = source->defines; define; define = define->next)
01149     {
01150         if (!strcmp(define->name, token.string))
01151         {
01152             if (define->flags & DEFINE_FIXED)
01153             {
01154                 SourceWarning(source, "can't undef %s", token.string);
01155             } //end if
01156             else
01157             {
01158                 if (lastdefine) lastdefine->next = define->next;
01159                 else source->defines = define->next;
01160                 PC_FreeDefine(define);
01161             } //end else
01162             break;
01163         } //end if
01164         lastdefine = define;
01165     } //end for
01166 #endif //DEFINEHASHING
01167     return qtrue;
01168 } //end of the function PC_Directive_undef
01169 //============================================================================
01170 //
01171 // Parameter:               -
01172 // Returns:                 -
01173 // Changes Globals:     -
01174 //============================================================================
01175 int PC_Directive_define(source_t *source)
01176 {
01177     token_t token, *t, *last;
01178     define_t *define;
01179 
01180     if (source->skip > 0) return qtrue;
01181     //
01182     if (!PC_ReadLine(source, &token))
01183     {
01184         SourceError(source, "#define without name");
01185         return qfalse;
01186     } //end if
01187     if (token.type != TT_NAME)
01188     {
01189         PC_UnreadSourceToken(source, &token);
01190         SourceError(source, "expected name after #define, found %s", token.string);
01191         return qfalse;
01192     } //end if
01193     //check if the define already exists
01194 #if DEFINEHASHING
01195     define = PC_FindHashedDefine(source->definehash, token.string);
01196 #else
01197     define = PC_FindDefine(source->defines, token.string);
01198 #endif //DEFINEHASHING
01199     if (define)
01200     {
01201         if (define->flags & DEFINE_FIXED)
01202         {
01203             SourceError(source, "can't redefine %s", token.string);
01204             return qfalse;
01205         } //end if
01206         SourceWarning(source, "redefinition of %s", token.string);
01207         //unread the define name before executing the #undef directive
01208         PC_UnreadSourceToken(source, &token);
01209         if (!PC_Directive_undef(source)) return qfalse;
01210         //if the define was not removed (define->flags & DEFINE_FIXED)
01211 #if DEFINEHASHING
01212         define = PC_FindHashedDefine(source->definehash, token.string);
01213 #else
01214         define = PC_FindDefine(source->defines, token.string);
01215 #endif //DEFINEHASHING
01216     } //end if
01217     //allocate define
01218     define = (define_t *) GetMemory(sizeof(define_t) + strlen(token.string) + 1);
01219     Com_Memset(define, 0, sizeof(define_t));
01220     define->name = (char *) define + sizeof(define_t);
01221     strcpy(define->name, token.string);
01222     //add the define to the source
01223 #if DEFINEHASHING
01224     PC_AddDefineToHash(define, source->definehash);
01225 #else //DEFINEHASHING
01226     define->next = source->defines;
01227     source->defines = define;
01228 #endif //DEFINEHASHING
01229     //if nothing is defined, just return
01230     if (!PC_ReadLine(source, &token)) return qtrue;
01231     //if it is a define with parameters
01232     if (!PC_WhiteSpaceBeforeToken(&token) && !strcmp(token.string, "("))
01233     {
01234         //read the define parameters
01235         last = NULL;
01236         if (!PC_CheckTokenString(source, ")"))
01237         {
01238             while(1)
01239             {
01240                 if (!PC_ReadLine(source, &token))
01241                 {
01242                     SourceError(source, "expected define parameter");
01243                     return qfalse;
01244                 } //end if
01245                 //if it isn't a name
01246                 if (token.type != TT_NAME)
01247                 {
01248                     SourceError(source, "invalid define parameter");
01249                     return qfalse;
01250                 } //end if
01251                 //
01252                 if (PC_FindDefineParm(define, token.string) >= 0)
01253                 {
01254                     SourceError(source, "two the same define parameters");
01255                     return qfalse;
01256                 } //end if
01257                 //add the define parm
01258                 t = PC_CopyToken(&token);
01259                 PC_ClearTokenWhiteSpace(t);
01260                 t->next = NULL;
01261                 if (last) last->next = t;
01262                 else define->parms = t;
01263                 last = t;
01264                 define->numparms++;
01265                 //read next token
01266                 if (!PC_ReadLine(source, &token))
01267                 {
01268                     SourceError(source, "define parameters not terminated");
01269                     return qfalse;
01270                 } //end if
01271                 //
01272                 if (!strcmp(token.string, ")")) break;
01273                 //then it must be a comma
01274                 if (strcmp(token.string, ","))
01275                 {
01276                     SourceError(source, "define not terminated");
01277                     return qfalse;
01278                 } //end if
01279             } //end while
01280         } //end if
01281         if (!PC_ReadLine(source, &token)) return qtrue;
01282     } //end if
01283     //read the defined stuff
01284     last = NULL;
01285     do
01286     {
01287         t = PC_CopyToken(&token);
01288         if (t->type == TT_NAME && !strcmp(t->string, define->name))
01289         {
01290             SourceError(source, "recursive define (removed recursion)");
01291             continue;
01292         } //end if
01293         PC_ClearTokenWhiteSpace(t);
01294         t->next = NULL;
01295         if (last) last->next = t;
01296         else define->tokens = t;
01297         last = t;
01298     } while(PC_ReadLine(source, &token));
01299     //
01300     if (last)
01301     {
01302         //check for merge operators at the beginning or end
01303         if (!strcmp(define->tokens->string, "##") ||
01304                 !strcmp(last->string, "##"))
01305         {
01306             SourceError(source, "define with misplaced ##");
01307             return qfalse;
01308         } //end if
01309     } //end if
01310     return qtrue;
01311 } //end of the function PC_Directive_define
01312 //============================================================================
01313 //
01314 // Parameter:               -
01315 // Returns:                 -
01316 // Changes Globals:     -
01317 //============================================================================
01318 define_t *PC_DefineFromString(char *string)
01319 {
01320     script_t *script;
01321     source_t src;
01322     token_t *t;
01323     int res, i;
01324     define_t *def;
01325 
01326     PC_InitTokenHeap();
01327 
01328     script = LoadScriptMemory(string, strlen(string), "*extern");
01329     //create a new source
01330     Com_Memset(&src, 0, sizeof(source_t));
01331     strncpy(src.filename, "*extern", MAX_PATH);
01332     src.scriptstack = script;
01333 #if DEFINEHASHING
01334     src.definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
01335 #endif //DEFINEHASHING
01336     //create a define from the source
01337     res = PC_Directive_define(&src);
01338     //free any tokens if left
01339     for (t = src.tokens; t; t = src.tokens)
01340     {
01341         src.tokens = src.tokens->next;
01342         PC_FreeToken(t);
01343     } //end for
01344 #ifdef DEFINEHASHING
01345     def = NULL;
01346     for (i = 0; i < DEFINEHASHSIZE; i++)
01347     {
01348         if (src.definehash[i])
01349         {
01350             def = src.definehash[i];
01351             break;
01352         } //end if
01353     } //end for
01354 #else
01355     def = src.defines;
01356 #endif //DEFINEHASHING
01357     //
01358 #if DEFINEHASHING
01359     FreeMemory(src.definehash);
01360 #endif //DEFINEHASHING
01361     //
01362     FreeScript(script);
01363     //if the define was created succesfully
01364     if (res > 0) return def;
01365     //free the define is created
01366     if (src.defines) PC_FreeDefine(def);
01367     //
01368     return NULL;
01369 } //end of the function PC_DefineFromString
01370 //============================================================================
01371 //
01372 // Parameter:               -
01373 // Returns:                 -
01374 // Changes Globals:     -
01375 //============================================================================
01376 int PC_AddDefine(source_t *source, char *string)
01377 {
01378     define_t *define;
01379 
01380     define = PC_DefineFromString(string);
01381     if (!define) return qfalse;
01382 #if DEFINEHASHING
01383     PC_AddDefineToHash(define, source->definehash);
01384 #else //DEFINEHASHING
01385     define->next = source->defines;
01386     source->defines = define;
01387 #endif //DEFINEHASHING
01388     return qtrue;
01389 } //end of the function PC_AddDefine
01390 //============================================================================
01391 // add a globals define that will be added to all opened sources
01392 //
01393 // Parameter:               -
01394 // Returns:                 -
01395 // Changes Globals:     -
01396 //============================================================================
01397 int PC_AddGlobalDefine(char *string)
01398 {
01399     define_t *define;
01400 
01401     define = PC_DefineFromString(string);
01402     if (!define) return qfalse;
01403     define->next = globaldefines;
01404     globaldefines = define;
01405     return qtrue;
01406 } //end of the function PC_AddGlobalDefine
01407 //============================================================================
01408 // remove the given global define
01409 //
01410 // Parameter:               -
01411 // Returns:                 -
01412 // Changes Globals:     -
01413 //============================================================================
01414 int PC_RemoveGlobalDefine(char *name)
01415 {
01416     define_t *define;
01417 
01418     define = PC_FindDefine(globaldefines, name);
01419     if (define)
01420     {
01421         PC_FreeDefine(define);
01422         return qtrue;
01423     } //end if
01424     return qfalse;
01425 } //end of the function PC_RemoveGlobalDefine
01426 //============================================================================
01427 // remove all globals defines
01428 //
01429 // Parameter:               -
01430 // Returns:                 -
01431 // Changes Globals:     -
01432 //============================================================================
01433 void PC_RemoveAllGlobalDefines(void)
01434 {
01435     define_t *define;
01436 
01437     for (define = globaldefines; define; define = globaldefines)
01438     {
01439         globaldefines = globaldefines->next;
01440         PC_FreeDefine(define);
01441     } //end for
01442 } //end of the function PC_RemoveAllGlobalDefines
01443 //============================================================================
01444 //
01445 // Parameter:               -
01446 // Returns:                 -
01447 // Changes Globals:     -
01448 //============================================================================
01449 define_t *PC_CopyDefine(source_t *source, define_t *define)
01450 {
01451     define_t *newdefine;
01452     token_t *token, *newtoken, *lasttoken;
01453 
01454     newdefine = (define_t *) GetMemory(sizeof(define_t) + strlen(define->name) + 1);
01455     //copy the define name
01456     newdefine->name = (char *) newdefine + sizeof(define_t);
01457     strcpy(newdefine->name, define->name);
01458     newdefine->flags = define->flags;
01459     newdefine->builtin = define->builtin;
01460     newdefine->numparms = define->numparms;
01461     //the define is not linked
01462     newdefine->next = NULL;
01463     newdefine->hashnext = NULL;
01464     //copy the define tokens
01465     newdefine->tokens = NULL;
01466     for (lasttoken = NULL, token = define->tokens; token; token = token->next)
01467     {
01468         newtoken = PC_CopyToken(token);
01469         newtoken->next = NULL;
01470         if (lasttoken) lasttoken->next = newtoken;
01471         else newdefine->tokens = newtoken;
01472         lasttoken = newtoken;
01473     } //end for
01474     //copy the define parameters
01475     newdefine->parms = NULL;
01476     for (lasttoken = NULL, token = define->parms; token; token = token->next)
01477     {
01478         newtoken = PC_CopyToken(token);
01479         newtoken->next = NULL;
01480         if (lasttoken) lasttoken->next = newtoken;
01481         else newdefine->parms = newtoken;
01482         lasttoken = newtoken;
01483     } //end for
01484     return newdefine;
01485 } //end of the function PC_CopyDefine
01486 //============================================================================
01487 //
01488 // Parameter:               -
01489 // Returns:                 -
01490 // Changes Globals:     -
01491 //============================================================================
01492 void PC_AddGlobalDefinesToSource(source_t *source)
01493 {
01494     define_t *define, *newdefine;
01495 
01496     for (define = globaldefines; define; define = define->next)
01497     {
01498         newdefine = PC_CopyDefine(source, define);
01499 #if DEFINEHASHING
01500         PC_AddDefineToHash(newdefine, source->definehash);
01501 #else //DEFINEHASHING
01502         newdefine->next = source->defines;
01503         source->defines = newdefine;
01504 #endif //DEFINEHASHING
01505     } //end for
01506 } //end of the function PC_AddGlobalDefinesToSource
01507 //============================================================================
01508 //
01509 // Parameter:               -
01510 // Returns:                 -
01511 // Changes Globals:     -
01512 //============================================================================
01513 int PC_Directive_if_def(source_t *source, int type)
01514 {
01515     token_t token;
01516     define_t *d;
01517     int skip;
01518 
01519     if (!PC_ReadLine(source, &token))
01520     {
01521         SourceError(source, "#ifdef without name");
01522         return qfalse;
01523     } //end if
01524     if (token.type != TT_NAME)
01525     {
01526         PC_UnreadSourceToken(source, &token);
01527         SourceError(source, "expected name after #ifdef, found %s", token.string);
01528         return qfalse;
01529     } //end if
01530 #if DEFINEHASHING
01531     d = PC_FindHashedDefine(source->definehash, token.string);
01532 #else
01533     d = PC_FindDefine(source->defines, token.string);
01534 #endif //DEFINEHASHING
01535     skip = (type == INDENT_IFDEF) == (d == NULL);
01536     PC_PushIndent(source, type, skip);
01537     return qtrue;
01538 } //end of the function PC_Directiveif_def
01539 //============================================================================
01540 //
01541 // Parameter:               -
01542 // Returns:                 -
01543 // Changes Globals:     -
01544 //============================================================================
01545 int PC_Directive_ifdef(source_t *source)
01546 {
01547     return PC_Directive_if_def(source, INDENT_IFDEF);
01548 } //end of the function PC_Directive_ifdef
01549 //============================================================================
01550 //
01551 // Parameter:               -
01552 // Returns:                 -
01553 // Changes Globals:     -
01554 //============================================================================
01555 int PC_Directive_ifndef(source_t *source)
01556 {
01557     return PC_Directive_if_def(source, INDENT_IFNDEF);
01558 } //end of the function PC_Directive_ifndef
01559 //============================================================================
01560 //
01561 // Parameter:               -
01562 // Returns:                 -
01563 // Changes Globals:     -
01564 //============================================================================
01565 int PC_Directive_else(source_t *source)
01566 {
01567     int type, skip;
01568 
01569     PC_PopIndent(source, &type, &skip);
01570     if (!type)
01571     {
01572         SourceError(source, "misplaced #else");
01573         return qfalse;
01574     } //end if
01575     if (type == INDENT_ELSE)
01576     {
01577         SourceError(source, "#else after #else");
01578         return qfalse;
01579     } //end if
01580     PC_PushIndent(source, INDENT_ELSE, !skip);
01581     return qtrue;
01582 } //end of the function PC_Directive_else
01583 //============================================================================
01584 //
01585 // Parameter:               -
01586 // Returns:                 -
01587 // Changes Globals:     -
01588 //============================================================================
01589 int PC_Directive_endif(source_t *source)
01590 {
01591     int type, skip;
01592 
01593     PC_PopIndent(source, &type, &skip);
01594     if (!type)
01595     {
01596         SourceError(source, "misplaced #endif");
01597         return qfalse;
01598     } //end if
01599     return qtrue;
01600 } //end of the function PC_Directive_endif
01601 //============================================================================
01602 //
01603 // Parameter:               -
01604 // Returns:                 -
01605 // Changes Globals:     -
01606 //============================================================================
01607 typedef struct operator_s
01608 {
01609     int operator;
01610     int priority;
01611     int parentheses;
01612     struct operator_s *prev, *next;
01613 } operator_t;
01614 
01615 typedef struct value_s
01616 {
01617     signed long int intvalue;
01618     double floatvalue;
01619     int parentheses;
01620     struct value_s *prev, *next;
01621 } value_t;
01622 
01623 int PC_OperatorPriority(int op)
01624 {
01625     switch(op)
01626     {
01627         case P_MUL: return 15;
01628         case P_DIV: return 15;
01629         case P_MOD: return 15;
01630         case P_ADD: return 14;
01631         case P_SUB: return 14;
01632 
01633         case P_LOGIC_AND: return 7;
01634         case P_LOGIC_OR: return 6;
01635         case P_LOGIC_GEQ: return 12;
01636         case P_LOGIC_LEQ: return 12;
01637         case P_LOGIC_EQ: return 11;
01638         case P_LOGIC_UNEQ: return 11;
01639 
01640         case P_LOGIC_NOT: return 16;
01641         case P_LOGIC_GREATER: return 12;
01642         case P_LOGIC_LESS: return 12;
01643 
01644         case P_RSHIFT: return 13;
01645         case P_LSHIFT: return 13;
01646 
01647         case P_BIN_AND: return 10;
01648         case P_BIN_OR: return 8;
01649         case P_BIN_XOR: return 9;
01650         case P_BIN_NOT: return 16;
01651 
01652         case P_COLON: return 5;
01653         case P_QUESTIONMARK: return 5;
01654     } //end switch
01655     return qfalse;
01656 } //end of the function PC_OperatorPriority
01657 
01658 //#define AllocValue()          GetClearedMemory(sizeof(value_t));
01659 //#define FreeValue(val)        FreeMemory(val)
01660 //#define AllocOperator(op)     op = (operator_t *) GetClearedMemory(sizeof(operator_t));
01661 //#define FreeOperator(op)      FreeMemory(op);
01662 
01663 #define MAX_VALUES      64
01664 #define MAX_OPERATORS   64
01665 #define AllocValue(val)                                 \
01666     if (numvalues >= MAX_VALUES) {                      \
01667         SourceError(source, "out of value space\n");        \
01668         error = 1;                                      \
01669         break;                                          \
01670     }                                                   \
01671     else                                                \
01672         val = &value_heap[numvalues++];
01673 #define FreeValue(val)
01674 //
01675 #define AllocOperator(op)                               \
01676     if (numoperators >= MAX_OPERATORS) {                \
01677         SourceError(source, "out of operator space\n"); \
01678         error = 1;                                      \
01679         break;                                          \
01680     }                                                   \
01681     else                                                \
01682         op = &operator_heap[numoperators++];
01683 #define FreeOperator(op)
01684 
01685 int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intvalue,
01686                                                                     double *floatvalue, int integer)
01687 {
01688     operator_t *o, *firstoperator, *lastoperator;
01689     value_t *v, *firstvalue, *lastvalue, *v1, *v2;
01690     token_t *t;
01691     int brace = 0;
01692     int parentheses = 0;
01693     int error = 0;
01694     int lastwasvalue = 0;
01695     int negativevalue = 0;
01696     int questmarkintvalue = 0;
01697     double questmarkfloatvalue = 0;
01698     int gotquestmarkvalue = qfalse;
01699     int lastoperatortype = 0;
01700     //
01701     operator_t operator_heap[MAX_OPERATORS];
01702     int numoperators = 0;
01703     value_t value_heap[MAX_VALUES];
01704     int numvalues = 0;
01705 
01706     firstoperator = lastoperator = NULL;
01707     firstvalue = lastvalue = NULL;
01708     if (intvalue) *intvalue = 0;
01709     if (floatvalue) *floatvalue = 0;
01710     for (t = tokens; t; t = t->next)
01711     {
01712         switch(t->type)
01713         {
01714             case TT_NAME:
01715             {
01716                 if (lastwasvalue || negativevalue)
01717                 {
01718                     SourceError(source, "syntax error in #if/#elif");
01719                     error = 1;
01720                     break;
01721                 } //end if
01722                 if (strcmp(t->string, "defined"))
01723                 {
01724                     SourceError(source, "undefined name %s in #if/#elif", t->string);
01725                     error = 1;
01726                     break;
01727                 } //end if
01728                 t = t->next;
01729                 if (!strcmp(t->string, "("))
01730                 {
01731                     brace = qtrue;
01732                     t = t->next;
01733                 } //end if
01734                 if (!t || t->type != TT_NAME)
01735                 {
01736                     SourceError(source, "defined without name in #if/#elif");
01737                     error = 1;
01738                     break;
01739                 } //end if
01740                 //v = (value_t *) GetClearedMemory(sizeof(value_t));
01741                 AllocValue(v);
01742 #if DEFINEHASHING
01743                 if (PC_FindHashedDefine(source->definehash, t->string))
01744 #else           
01745                 if (PC_FindDefine(source->defines, t->string))
01746 #endif //DEFINEHASHING
01747                 {
01748                     v->intvalue = 1;
01749                     v->floatvalue = 1;
01750                 } //end if
01751                 else
01752                 {
01753                     v->intvalue = 0;
01754                     v->floatvalue = 0;
01755                 } //end else
01756                 v->parentheses = parentheses;
01757                 v->next = NULL;
01758                 v->prev = lastvalue;
01759                 if (lastvalue) lastvalue->next = v;
01760                 else firstvalue = v;
01761                 lastvalue = v;
01762                 if (brace)
01763                 {
01764                     t = t->next;
01765                     if (!t || strcmp(t->string, ")"))
01766                     {
01767                         SourceError(source, "defined without ) in #if/#elif");
01768                         error = 1;
01769                         break;
01770                     } //end if
01771                 } //end if
01772                 brace = qfalse;
01773                 // defined() creates a value
01774                 lastwasvalue = 1;
01775                 break;
01776             } //end case
01777             case TT_NUMBER:
01778             {
01779                 if (lastwasvalue)
01780                 {
01781                     SourceError(source, "syntax error in #if/#elif");
01782                     error = 1;
01783                     break;
01784                 } //end if
01785                 //v = (value_t *) GetClearedMemory(sizeof(value_t));
01786                 AllocValue(v);
01787                 if (negativevalue)
01788                 {
01789                     v->intvalue = - (signed int) t->intvalue;
01790                     v->floatvalue = - t->floatvalue;
01791                 } //end if
01792                 else
01793                 {
01794                     v->intvalue = t->intvalue;
01795                     v->floatvalue = t->floatvalue;
01796                 } //end else
01797                 v->parentheses = parentheses;
01798                 v->next = NULL;
01799                 v->prev = lastvalue;
01800                 if (lastvalue) lastvalue->next = v;
01801                 else firstvalue = v;
01802                 lastvalue = v;
01803                 //last token was a value
01804                 lastwasvalue = 1;
01805                 //
01806                 negativevalue = 0;
01807                 break;
01808             } //end case
01809             case TT_PUNCTUATION:
01810             {
01811                 if (negativevalue)
01812                 {
01813                     SourceError(source, "misplaced minus sign in #if/#elif");
01814                     error = 1;
01815                     break;
01816                 } //end if
01817                 if (t->subtype == P_PARENTHESESOPEN)
01818                 {
01819                     parentheses++;
01820                     break;
01821                 } //end if
01822                 else if (t->subtype == P_PARENTHESESCLOSE)
01823                 {
01824                     parentheses--;
01825                     if (parentheses < 0)
01826                     {
01827                         SourceError(source, "too many ) in #if/#elsif");
01828                         error = 1;
01829                     } //end if
01830                     break;
01831                 } //end else if
01832                 //check for invalid operators on floating point values
01833                 if (!integer)
01834                 {
01835                     if (t->subtype == P_BIN_NOT || t->subtype == P_MOD ||
01836                         t->subtype == P_RSHIFT || t->subtype == P_LSHIFT ||
01837                         t->subtype == P_BIN_AND || t->subtype == P_BIN_OR ||
01838                         t->subtype == P_BIN_XOR)
01839                     {
01840                         SourceError(source, "illigal operator %s on floating point operands\n", t->string);
01841                         error = 1;
01842                         break;
01843                     } //end if
01844                 } //end if
01845                 switch(t->subtype)
01846                 {
01847                     case P_LOGIC_NOT:
01848                     case P_BIN_NOT:
01849                     {
01850                         if (lastwasvalue)
01851                         {
01852                             SourceError(source, "! or ~ after value in #if/#elif");
01853                             error = 1;
01854                             break;
01855                         } //end if
01856                         break;
01857                     } //end case
01858                     case P_INC:
01859                     case P_DEC:
01860                     {
01861                         SourceError(source, "++ or -- used in #if/#elif");
01862                         break;
01863                     } //end case
01864                     case P_SUB:
01865                     {
01866                         if (!lastwasvalue)
01867                         {
01868                             negativevalue = 1;
01869                             break;
01870                         } //end if
01871                     } //end case
01872                     
01873                     case P_MUL:
01874                     case P_DIV:
01875                     case P_MOD:
01876                     case P_ADD:
01877 
01878                     case P_LOGIC_AND:
01879                     case P_LOGIC_OR:
01880                     case P_LOGIC_GEQ:
01881                     case P_LOGIC_LEQ:
01882                     case P_LOGIC_EQ:
01883                     case P_LOGIC_UNEQ:
01884 
01885                     case P_LOGIC_GREATER:
01886                     case P_LOGIC_LESS:
01887 
01888                     case P_RSHIFT:
01889                     case P_LSHIFT:
01890 
01891                     case P_BIN_AND:
01892                     case P_BIN_OR:
01893                     case P_BIN_XOR:
01894 
01895                     case P_COLON:
01896                     case P_QUESTIONMARK:
01897                     {
01898                         if (!lastwasvalue)
01899                         {
01900                             SourceError(source, "operator %s after operator in #if/#elif", t->string);
01901                             error = 1;
01902                             break;
01903                         } //end if
01904                         break;
01905                     } //end case
01906                     default:
01907                     {
01908                         SourceError(source, "invalid operator %s in #if/#elif", t->string);
01909                         error = 1;
01910                         break;
01911                     } //end default
01912                 } //end switch
01913                 if (!error && !negativevalue)
01914                 {
01915                     //o = (operator_t *) GetClearedMemory(sizeof(operator_t));
01916                     AllocOperator(o);
01917                     o->operator = t->subtype;
01918                     o->priority = PC_OperatorPriority(t->subtype);
01919                     o->parentheses = parentheses;
01920                     o->next = NULL;
01921                     o->prev = lastoperator;
01922                     if (lastoperator) lastoperator->next = o;
01923                     else firstoperator = o;
01924                     lastoperator = o;
01925                     lastwasvalue = 0;
01926                 } //end if
01927                 break;
01928             } //end case
01929             default:
01930             {
01931                 SourceError(source, "unknown %s in #if/#elif", t->string);
01932                 error = 1;
01933                 break;
01934             } //end default
01935         } //end switch
01936         if (error) break;
01937     } //end for
01938     if (!error)
01939     {
01940         if (!lastwasvalue)
01941         {
01942             SourceError(source, "trailing operator in #if/#elif");
01943             error = 1;
01944         } //end if
01945         else if (parentheses)
01946         {
01947             SourceError(source, "too many ( in #if/#elif");
01948             error = 1;
01949         } //end else if
01950     } //end if
01951     //
01952     gotquestmarkvalue = qfalse;
01953     questmarkintvalue = 0;
01954     questmarkfloatvalue = 0;
01955     //while there are operators
01956     while(!error && firstoperator)
01957     {
01958         v = firstvalue;
01959         for (o = firstoperator; o->next; o = o->next)
01960         {
01961             //if the current operator is nested deeper in parentheses
01962             //than the next operator
01963             if (o->parentheses > o->next->parentheses) break;
01964             //if the current and next operator are nested equally deep in parentheses
01965             if (o->parentheses == o->next->parentheses)
01966             {
01967                 //if the priority of the current operator is equal or higher
01968                 //than the priority of the next operator
01969                 if (o->priority >= o->next->priority) break;
01970             } //end if
01971             //if the arity of the operator isn't equal to 1
01972             if (o->operator != P_LOGIC_NOT
01973                     && o->operator != P_BIN_NOT) v = v->next;
01974             //if there's no value or no next value
01975             if (!v)
01976             {
01977                 SourceError(source, "mising values in #if/#elif");
01978                 error = 1;
01979                 break;
01980             } //end if
01981         } //end for
01982         if (error) break;
01983         v1 = v;
01984         v2 = v->next;
01985 #ifdef DEBUG_EVAL
01986         if (integer)
01987         {
01988             Log_Write("operator %s, value1 = %d", PunctuationFromNum(source->scriptstack, o->operator), v1->intvalue);
01989             if (v2) Log_Write("value2 = %d", v2->intvalue);
01990         } //end if
01991         else
01992         {
01993             Log_Write("operator %s, value1 = %f", PunctuationFromNum(source->scriptstack, o->operator), v1->floatvalue);
01994             if (v2) Log_Write("value2 = %f", v2->floatvalue);
01995         } //end else
01996 #endif //DEBUG_EVAL
01997         switch(o->operator)
01998         {
01999             case P_LOGIC_NOT:       v1->intvalue = !v1->intvalue;
02000                                     v1->floatvalue = !v1->floatvalue; break;
02001             case P_BIN_NOT:         v1->intvalue = ~v1->intvalue;
02002                                     break;
02003             case P_MUL:             v1->intvalue *= v2->intvalue;
02004                                     v1->floatvalue *= v2->floatvalue; break;
02005             case P_DIV:             if (!v2->intvalue || !v2->floatvalue)
02006                                     {
02007                                         SourceError(source, "divide by zero in #if/#elif\n");
02008                                         error = 1;
02009                                         break;
02010                                     }
02011                                     v1->intvalue /= v2->intvalue;
02012                                     v1->floatvalue /= v2->floatvalue; break;
02013             case P_MOD:             if (!v2->intvalue)
02014                                     {
02015                                         SourceError(source, "divide by zero in #if/#elif\n");
02016                                         error = 1;
02017                                         break;
02018                                     }
02019                                     v1->intvalue %= v2->intvalue; break;
02020             case P_ADD:             v1->intvalue += v2->intvalue;
02021                                     v1->floatvalue += v2->floatvalue; break;
02022             case P_SUB:             v1->intvalue -= v2->intvalue;
02023                                     v1->floatvalue -= v2->floatvalue; break;
02024             case P_LOGIC_AND:       v1->intvalue = v1->intvalue && v2->intvalue;
02025                                     v1->floatvalue = v1->floatvalue && v2->floatvalue; break;
02026             case P_LOGIC_OR:        v1->intvalue = v1->intvalue || v2->intvalue;
02027                                     v1->floatvalue = v1->floatvalue || v2->floatvalue; break;
02028             case P_LOGIC_GEQ:       v1->intvalue = v1->intvalue >= v2->intvalue;
02029                                     v1->floatvalue = v1->floatvalue >= v2->floatvalue; break;
02030             case P_LOGIC_LEQ:       v1->intvalue = v1->intvalue <= v2->intvalue;
02031                                     v1->floatvalue = v1->floatvalue <= v2->floatvalue; break;
02032             case P_LOGIC_EQ:        v1->intvalue = v1->intvalue == v2->intvalue;
02033                                     v1->floatvalue = v1->floatvalue == v2->floatvalue; break;
02034             case P_LOGIC_UNEQ:      v1->intvalue = v1->intvalue != v2->intvalue;
02035                                     v1->floatvalue = v1->floatvalue != v2->floatvalue; break;
02036             case P_LOGIC_GREATER:   v1->intvalue = v1->intvalue > v2->intvalue;
02037                                     v1->floatvalue = v1->floatvalue > v2->floatvalue; break;
02038             case P_LOGIC_LESS:      v1->intvalue = v1->intvalue < v2->intvalue;
02039                                     v1->floatvalue = v1->floatvalue < v2->floatvalue; break;
02040             case P_RSHIFT:          v1->intvalue >>= v2->intvalue;
02041                                     break;
02042             case P_LSHIFT:          v1->intvalue <<= v2->intvalue;
02043                                     break;
02044             case P_BIN_AND:         v1->intvalue &= v2->intvalue;
02045                                     break;
02046             case P_BIN_OR:          v1->intvalue |= v2->intvalue;
02047                                     break;
02048             case P_BIN_XOR:         v1->intvalue ^= v2->intvalue;
02049                                     break;
02050             case P_COLON:
02051             {
02052                 if (!gotquestmarkvalue)
02053                 {
02054                     SourceError(source, ": without ? in #if/#elif");
02055                     error = 1;
02056                     break;
02057                 } //end if
02058                 if (integer)
02059                 {
02060                     if (!questmarkintvalue) v1->intvalue = v2->intvalue;
02061                 } //end if
02062                 else
02063                 {
02064                     if (!questmarkfloatvalue) v1->floatvalue = v2->floatvalue;
02065                 } //end else
02066                 gotquestmarkvalue = qfalse;
02067                 break;
02068             } //end case
02069             case P_QUESTIONMARK:
02070             {
02071                 if (gotquestmarkvalue)
02072                 {
02073                     SourceError(source, "? after ? in #if/#elif");
02074                     error = 1;
02075                     break;
02076                 } //end if
02077                 questmarkintvalue = v1->intvalue;
02078                 questmarkfloatvalue = v1->floatvalue;
02079                 gotquestmarkvalue = qtrue;
02080                 break;
02081             } //end if
02082         } //end switch
02083 #ifdef DEBUG_EVAL
02084         if (integer) Log_Write("result value = %d", v1->intvalue);
02085         else Log_Write("result value = %f", v1->floatvalue);
02086 #endif //DEBUG_EVAL
02087         if (error) break;
02088         lastoperatortype = o->operator;
02089         //if not an operator with arity 1
02090         if (o->operator != P_LOGIC_NOT
02091                 && o->operator != P_BIN_NOT)
02092         {
02093             //remove the second value if not question mark operator
02094             if (o->operator != P_QUESTIONMARK) v = v->next;
02095             //
02096             if (v->prev) v->prev->next = v->next;
02097             else firstvalue = v->next;
02098             if (v->next) v->next->prev = v->prev;
02099             else lastvalue = v->prev;
02100             //FreeMemory(v);
02101             FreeValue(v);
02102         } //end if
02103         //remove the operator
02104         if (o->prev) o->prev->next = o->next;
02105         else firstoperator = o->next;
02106         if (o->next) o->next->prev = o->prev;
02107         else lastoperator = o->prev;
02108         //FreeMemory(o);
02109         FreeOperator(o);
02110     } //end while
02111     if (firstvalue)
02112     {
02113         if (intvalue) *intvalue = firstvalue->intvalue;
02114         if (floatvalue) *floatvalue = firstvalue->floatvalue;
02115     } //end if
02116     for (o = firstoperator; o; o = lastoperator)
02117     {
02118         lastoperator = o->next;
02119         //FreeMemory(o);
02120         FreeOperator(o);
02121     } //end for
02122     for (v = firstvalue; v; v = lastvalue)
02123     {
02124         lastvalue = v->next;
02125         //FreeMemory(v);
02126         FreeValue(v);
02127     } //end for
02128     if (!error) return qtrue;
02129     if (intvalue) *intvalue = 0;
02130     if (floatvalue) *floatvalue = 0;
02131     return qfalse;
02132 } //end of the function PC_EvaluateTokens
02133 //============================================================================
02134 //
02135 // Parameter:               -
02136 // Returns:                 -
02137 // Changes Globals:     -
02138 //============================================================================
02139 int PC_Evaluate(source_t *source, signed long int *intvalue,
02140                                                 double *floatvalue, int integer)
02141 {
02142     token_t token, *firsttoken, *lasttoken;
02143     token_t *t, *nexttoken;
02144     define_t *define;
02145     int defined = qfalse;
02146 
02147     if (intvalue) *intvalue = 0;
02148     if (floatvalue) *floatvalue = 0;
02149     //
02150     if (!PC_ReadLine(source, &token))
02151     {
02152         SourceError(source, "no value after #if/#elif");
02153         return qfalse;
02154     } //end if
02155     firsttoken = NULL;
02156     lasttoken = NULL;
02157     do
02158     {
02159         //if the token is a name
02160         if (token.type == TT_NAME)
02161         {
02162             if (defined)
02163             {
02164                 defined = qfalse;
02165                 t = PC_CopyToken(&token);
02166                 t->next = NULL;
02167                 if (lasttoken) lasttoken->next = t;
02168                 else firsttoken = t;
02169                 lasttoken = t;
02170             } //end if
02171             else if (!strcmp(token.string, "defined"))
02172             {
02173                 defined = qtrue;
02174                 t = PC_CopyToken(&token);
02175                 t->next = NULL;
02176                 if (lasttoken) lasttoken->next = t;
02177                 else firsttoken = t;
02178                 lasttoken = t;
02179             } //end if
02180             else
02181             {
02182                 //then it must be a define
02183 #if DEFINEHASHING
02184                 define = PC_FindHashedDefine(source->definehash, token.string);
02185 #else
02186                 define = PC_FindDefine(source->defines, token.string);
02187 #endif //DEFINEHASHING
02188                 if (!define)
02189                 {
02190                     SourceError(source, "can't evaluate %s, not defined", token.string);
02191                     return qfalse;
02192                 } //end if
02193                 if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
02194             } //end else
02195         } //end if
02196         //if the token is a number or a punctuation
02197         else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
02198         {
02199             t = PC_CopyToken(&token);
02200             t->next = NULL;
02201             if (lasttoken) lasttoken->next = t;
02202             else firsttoken = t;
02203             lasttoken = t;
02204         } //end else
02205         else //can't evaluate the token
02206         {
02207             SourceError(source, "can't evaluate %s", token.string);
02208             return qfalse;
02209         } //end else
02210     } while(PC_ReadLine(source, &token));
02211     //
02212     if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
02213     //
02214 #ifdef DEBUG_EVAL
02215     Log_Write("eval:");
02216 #endif //DEBUG_EVAL
02217     for (t = firsttoken; t; t = nexttoken)
02218     {
02219 #ifdef DEBUG_EVAL
02220         Log_Write(" %s", t->string);
02221 #endif //DEBUG_EVAL
02222         nexttoken = t->next;
02223         PC_FreeToken(t);
02224     } //end for
02225 #ifdef DEBUG_EVAL
02226     if (integer) Log_Write("eval result: %d", *intvalue);
02227     else Log_Write("eval result: %f", *floatvalue);
02228 #endif //DEBUG_EVAL
02229     //
02230     return qtrue;
02231 } //end of the function PC_Evaluate
02232 //============================================================================
02233 //
02234 // Parameter:               -
02235 // Returns:                 -
02236 // Changes Globals:     -
02237 //============================================================================
02238 int PC_DollarEvaluate(source_t *source, signed long int *intvalue,
02239                                                 double *floatvalue, int integer)
02240 {
02241     int indent, defined = qfalse;
02242     token_t token, *firsttoken, *lasttoken;
02243     token_t *t, *nexttoken;
02244     define_t *define;
02245 
02246     if (intvalue) *intvalue = 0;
02247     if (floatvalue) *floatvalue = 0;
02248     //
02249     if (!PC_ReadSourceToken(source, &token))
02250     {
02251         SourceError(source, "no leading ( after $evalint/$evalfloat");
02252         return qfalse;
02253     } //end if
02254     if (!PC_ReadSourceToken(source, &token))
02255     {
02256         SourceError(source, "nothing to evaluate");
02257         return qfalse;
02258     } //end if
02259     indent = 1;
02260     firsttoken = NULL;
02261     lasttoken = NULL;
02262     do
02263     {
02264         //if the token is a name
02265         if (token.type == TT_NAME)
02266         {
02267             if (defined)
02268             {
02269                 defined = qfalse;
02270                 t = PC_CopyToken(&token);
02271                 t->next = NULL;
02272                 if (lasttoken) lasttoken->next = t;
02273                 else firsttoken = t;
02274                 lasttoken = t;
02275             } //end if
02276             else if (!strcmp(token.string, "defined"))
02277             {
02278                 defined = qtrue;
02279                 t = PC_CopyToken(&token);
02280                 t->next = NULL;
02281                 if (lasttoken) lasttoken->next = t;
02282                 else firsttoken = t;
02283                 lasttoken = t;
02284             } //end if
02285             else
02286             {
02287                 //then it must be a define
02288 #if DEFINEHASHING
02289                 define = PC_FindHashedDefine(source->definehash, token.string);
02290 #else
02291                 define = PC_FindDefine(source->defines, token.string);
02292 #endif //DEFINEHASHING
02293                 if (!define)
02294                 {
02295                     SourceError(source, "can't evaluate %s, not defined", token.string);
02296                     return qfalse;
02297                 } //end if
02298                 if (!PC_ExpandDefineIntoSource(source, &token, define)) return qfalse;
02299             } //end else
02300         } //end if
02301         //if the token is a number or a punctuation
02302         else if (token.type == TT_NUMBER || token.type == TT_PUNCTUATION)
02303         {
02304             if (*token.string == '(') indent++;
02305             else if (*token.string == ')') indent--;
02306             if (indent <= 0) break;
02307             t = PC_CopyToken(&token);
02308             t->next = NULL;
02309             if (lasttoken) lasttoken->next = t;
02310             else firsttoken = t;
02311             lasttoken = t;
02312         } //end else
02313         else //can't evaluate the token
02314         {
02315             SourceError(source, "can't evaluate %s", token.string);
02316             return qfalse;
02317         } //end else
02318     } while(PC_ReadSourceToken(source, &token));
02319     //
02320     if (!PC_EvaluateTokens(source, firsttoken, intvalue, floatvalue, integer)) return qfalse;
02321     //
02322 #ifdef DEBUG_EVAL
02323     Log_Write("$eval:");
02324 #endif //DEBUG_EVAL
02325     for (t = firsttoken; t; t = nexttoken)
02326     {
02327 #ifdef DEBUG_EVAL
02328         Log_Write(" %s", t->string);
02329 #endif //DEBUG_EVAL
02330         nexttoken = t->next;
02331         PC_FreeToken(t);
02332     } //end for
02333 #ifdef DEBUG_EVAL
02334     if (integer) Log_Write("$eval result: %d", *intvalue);
02335     else Log_Write("$eval result: %f", *floatvalue);
02336 #endif //DEBUG_EVAL
02337     //
02338     return qtrue;
02339 } //end of the function PC_DollarEvaluate
02340 //============================================================================
02341 //
02342 // Parameter:               -
02343 // Returns:                 -
02344 // Changes Globals:     -
02345 //============================================================================
02346 int PC_Directive_elif(source_t *source)
02347 {
02348     signed long int value;
02349     int type, skip;
02350 
02351     PC_PopIndent(source, &type, &skip);
02352     if (!type || type == INDENT_ELSE)
02353     {
02354         SourceError(source, "misplaced #elif");
02355         return qfalse;
02356     } //end if
02357     if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
02358     skip = (value == 0);
02359     PC_PushIndent(source, INDENT_ELIF, skip);
02360     return qtrue;
02361 } //end of the function PC_Directive_elif
02362 //============================================================================
02363 //
02364 // Parameter:               -
02365 // Returns:                 -
02366 // Changes Globals:     -
02367 //============================================================================
02368 int PC_Directive_if(source_t *source)
02369 {
02370     signed long int value;
02371     int skip;
02372 
02373     if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
02374     skip = (value == 0);
02375     PC_PushIndent(source, INDENT_IF, skip);
02376     return qtrue;
02377 } //end of the function PC_Directive
02378 //============================================================================
02379 //
02380 // Parameter:               -
02381 // Returns:                 -
02382 // Changes Globals:     -
02383 //============================================================================
02384 int PC_Directive_line(source_t *source)
02385 {
02386     SourceError(source, "#line directive not supported");
02387     return qfalse;
02388 } //end of the function PC_Directive_line
02389 //============================================================================
02390 //
02391 // Parameter:               -
02392 // Returns:                 -
02393 // Changes Globals:     -
02394 //============================================================================
02395 int PC_Directive_error(source_t *source)
02396 {
02397     token_t token;
02398 
02399     strcpy(token.string, "");
02400     PC_ReadSourceToken(source, &token);
02401     SourceError(source, "#error directive: %s", token.string);
02402     return qfalse;
02403 } //end of the function PC_Directive_error
02404 //============================================================================
02405 //
02406 // Parameter:               -
02407 // Returns:                 -
02408 // Changes Globals:     -
02409 //============================================================================
02410 int PC_Directive_pragma(source_t *source)
02411 {
02412     token_t token;
02413 
02414     SourceWarning(source, "#pragma directive not supported");
02415     while(PC_ReadLine(source, &token)) ;
02416     return qtrue;
02417 } //end of the function PC_Directive_pragma
02418 //============================================================================
02419 //
02420 // Parameter:               -
02421 // Returns:                 -
02422 // Changes Globals:     -
02423 //============================================================================
02424 void UnreadSignToken(source_t *source)
02425 {
02426     token_t token;
02427 
02428     token.line = source->scriptstack->line;
02429     token.whitespace_p = source->scriptstack->script_p;
02430     token.endwhitespace_p = source->scriptstack->script_p;
02431     token.linescrossed = 0;
02432     strcpy(token.string, "-");
02433     token.type = TT_PUNCTUATION;
02434     token.subtype = P_SUB;
02435     PC_UnreadSourceToken(source, &token);
02436 } //end of the function UnreadSignToken
02437 //============================================================================
02438 //
02439 // Parameter:               -
02440 // Returns:                 -
02441 // Changes Globals:     -
02442 //============================================================================
02443 int PC_Directive_eval(source_t *source)
02444 {
02445     signed long int value;
02446     token_t token;
02447 
02448     if (!PC_Evaluate(source, &value, NULL, qtrue)) return qfalse;
02449     //
02450     token.line = source->scriptstack->line;
02451     token.whitespace_p = source->scriptstack->script_p;
02452     token.endwhitespace_p = source->scriptstack->script_p;
02453     token.linescrossed = 0;
02454     sprintf(token.string, "%d", abs(value));
02455     token.type = TT_NUMBER;
02456     token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
02457     PC_UnreadSourceToken(source, &token);
02458     if (value < 0) UnreadSignToken(source);
02459     return qtrue;
02460 } //end of the function PC_Directive_eval
02461 //============================================================================
02462 //
02463 // Parameter:               -
02464 // Returns:                 -
02465 // Changes Globals:     -
02466 //============================================================================
02467 int PC_Directive_evalfloat(source_t *source)
02468 {
02469     double value;
02470     token_t token;
02471 
02472     if (!PC_Evaluate(source, NULL, &value, qfalse)) return qfalse;
02473     token.line = source->scriptstack->line;
02474     token.whitespace_p = source->scriptstack->script_p;
02475     token.endwhitespace_p = source->scriptstack->script_p;
02476     token.linescrossed = 0;
02477     sprintf(token.string, "%1.2f", fabs(value));
02478     token.type = TT_NUMBER;
02479     token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
02480     PC_UnreadSourceToken(source, &token);
02481     if (value < 0) UnreadSignToken(source);
02482     return qtrue;
02483 } //end of the function PC_Directive_evalfloat
02484 //============================================================================
02485 //
02486 // Parameter:               -
02487 // Returns:                 -
02488 // Changes Globals:     -
02489 //============================================================================
02490 directive_t directives[20] =
02491 {
02492     {"if", PC_Directive_if},
02493     {"ifdef", PC_Directive_ifdef},
02494     {"ifndef", PC_Directive_ifndef},
02495     {"elif", PC_Directive_elif},
02496     {"else", PC_Directive_else},
02497     {"endif", PC_Directive_endif},
02498     {"include", PC_Directive_include},
02499     {"define", PC_Directive_define},
02500     {"undef", PC_Directive_undef},
02501     {"line", PC_Directive_line},
02502     {"error", PC_Directive_error},
02503     {"pragma", PC_Directive_pragma},
02504     {"eval", PC_Directive_eval},
02505     {"evalfloat", PC_Directive_evalfloat},
02506     {NULL, NULL}
02507 };
02508 
02509 int PC_ReadDirective(source_t *source)
02510 {
02511     token_t token;
02512     int i;
02513 
02514     //read the directive name
02515     if (!PC_ReadSourceToken(source, &token))
02516     {
02517         SourceError(source, "found # without name");
02518         return qfalse;
02519     } //end if
02520     //directive name must be on the same line
02521     if (token.linescrossed > 0)
02522     {
02523         PC_UnreadSourceToken(source, &token);
02524         SourceError(source, "found # at end of line");
02525         return qfalse;
02526     } //end if
02527     //if if is a name
02528     if (token.type == TT_NAME)
02529     {
02530         //find the precompiler directive
02531         for (i = 0; directives[i].name; i++)
02532         {
02533             if (!strcmp(directives[i].name, token.string))
02534             {
02535                 return directives[i].func(source);
02536             } //end if
02537         } //end for
02538     } //end if
02539     SourceError(source, "unknown precompiler directive %s", token.string);
02540     return qfalse;
02541 } //end of the function PC_ReadDirective
02542 //============================================================================
02543 //
02544 // Parameter:               -
02545 // Returns:                 -
02546 // Changes Globals:     -
02547 //============================================================================
02548 int PC_DollarDirective_evalint(source_t *source)
02549 {
02550     signed long int value;
02551     token_t token;
02552 
02553     if (!PC_DollarEvaluate(source, &value, NULL, qtrue)) return qfalse;
02554     //
02555     token.line = source->scriptstack->line;
02556     token.whitespace_p = source->scriptstack->script_p;
02557     token.endwhitespace_p = source->scriptstack->script_p;
02558     token.linescrossed = 0;
02559     sprintf(token.string, "%d", abs(value));
02560     token.type = TT_NUMBER;
02561     token.subtype = TT_INTEGER|TT_LONG|TT_DECIMAL;
02562 #ifdef NUMBERVALUE
02563     token.intvalue = value;
02564     token.floatvalue = value;
02565 #endif //NUMBERVALUE
02566     PC_UnreadSourceToken(source, &token);
02567     if (value < 0) UnreadSignToken(source);
02568     return qtrue;
02569 } //end of the function PC_DollarDirective_evalint
02570 //============================================================================
02571 //
02572 // Parameter:               -
02573 // Returns:                 -
02574 // Changes Globals:     -
02575 //============================================================================
02576 int PC_DollarDirective_evalfloat(source_t *source)
02577 {
02578     double value;
02579     token_t token;
02580 
02581     if (!PC_DollarEvaluate(source, NULL, &value, qfalse)) return qfalse;
02582     token.line = source->scriptstack->line;
02583     token.whitespace_p = source->scriptstack->script_p;
02584     token.endwhitespace_p = source->scriptstack->script_p;
02585     token.linescrossed = 0;
02586     sprintf(token.string, "%1.2f", fabs(value));
02587     token.type = TT_NUMBER;
02588     token.subtype = TT_FLOAT|TT_LONG|TT_DECIMAL;
02589 #ifdef NUMBERVALUE
02590     token.intvalue = (unsigned long) value;
02591     token.floatvalue = value;
02592 #endif //NUMBERVALUE
02593     PC_UnreadSourceToken(source, &token);
02594     if (value < 0) UnreadSignToken(source);
02595     return qtrue;
02596 } //end of the function PC_DollarDirective_evalfloat
02597 //============================================================================
02598 //
02599 // Parameter:               -
02600 // Returns:                 -
02601 // Changes Globals:     -
02602 //============================================================================
02603 directive_t dollardirectives[20] =
02604 {
02605     {"evalint", PC_DollarDirective_evalint},
02606     {"evalfloat", PC_DollarDirective_evalfloat},
02607     {NULL, NULL}
02608 };
02609 
02610 int PC_ReadDollarDirective(source_t *source)
02611 {
02612     token_t token;
02613     int i;
02614 
02615     //read the directive name
02616     if (!PC_ReadSourceToken(source, &token))
02617     {
02618         SourceError(source, "found $ without name");
02619         return qfalse;
02620     } //end if
02621     //directive name must be on the same line
02622     if (token.linescrossed > 0)
02623     {
02624         PC_UnreadSourceToken(source, &token);
02625         SourceError(source, "found $ at end of line");
02626         return qfalse;
02627     } //end if
02628     //if if is a name
02629     if (token.type == TT_NAME)
02630     {
02631         //find the precompiler directive
02632         for (i = 0; dollardirectives[i].name; i++)
02633         {
02634             if (!strcmp(dollardirectives[i].name, token.string))
02635             {
02636                 return dollardirectives[i].func(source);
02637             } //end if
02638         } //end for
02639     } //end if
02640     PC_UnreadSourceToken(source, &token);
02641     SourceError(source, "unknown precompiler directive %s", token.string);
02642     return qfalse;
02643 } //end of the function PC_ReadDirective
02644 
02645 #ifdef QUAKEC
02646 //============================================================================
02647 //
02648 // Parameter:               -
02649 // Returns:                 -
02650 // Changes Globals:     -
02651 //============================================================================
02652 int BuiltinFunction(source_t *source)
02653 {
02654     token_t token;
02655 
02656     if (!PC_ReadSourceToken(source, &token)) return qfalse;
02657     if (token.type == TT_NUMBER)
02658     {
02659         PC_UnreadSourceToken(source, &token);
02660         return qtrue;
02661     } //end if
02662     else
02663     {
02664         PC_UnreadSourceToken(source, &token);
02665         return qfalse;
02666     } //end else
02667 } //end of the function BuiltinFunction
02668 //============================================================================
02669 //
02670 // Parameter:               -
02671 // Returns:                 -
02672 // Changes Globals:     -
02673 //============================================================================
02674 int QuakeCMacro(source_t *source)
02675 {
02676     int i;
02677     token_t token;
02678 
02679     if (!PC_ReadSourceToken(source, &token)) return qtrue;
02680     if (token.type != TT_NAME)
02681     {
02682         PC_UnreadSourceToken(source, &token);
02683         return qtrue;
02684     } //end if
02685     //find the precompiler directive
02686     for (i = 0; dollardirectives[i].name; i++)
02687     {
02688         if (!strcmp(dollardirectives[i].name, token.string))
02689         {
02690             PC_UnreadSourceToken(source, &token);
02691             return qfalse;
02692         } //end if
02693     } //end for
02694     PC_UnreadSourceToken(source, &token);
02695     return qtrue;
02696 } //end of the function QuakeCMacro
02697 #endif //QUAKEC
02698 //============================================================================
02699 //
02700 // Parameter:               -
02701 // Returns:                 -
02702 // Changes Globals:     -
02703 //============================================================================
02704 int PC_ReadToken(source_t *source, token_t *token)
02705 {
02706     define_t *define;
02707 
02708     while(1)
02709     {
02710         if (!PC_ReadSourceToken(source, token)) return qfalse;
02711         //check for precompiler directives
02712         if (token->type == TT_PUNCTUATION && *token->string == '#')
02713         {
02714 #ifdef QUAKEC
02715             if (!BuiltinFunction(source))
02716 #endif //QUAKC
02717             {
02718                 //read the precompiler directive
02719                 if (!PC_ReadDirective(source)) return qfalse;
02720                 continue;
02721             } //end if
02722         } //end if
02723         if (token->type == TT_PUNCTUATION && *token->string == '$')
02724         {
02725 #ifdef QUAKEC
02726             if (!QuakeCMacro(source))
02727 #endif //QUAKEC
02728             {
02729                 //read the precompiler directive
02730                 if (!PC_ReadDollarDirective(source)) return qfalse;
02731                 continue;
02732             } //end if
02733         } //end if
02734         // recursively concatenate strings that are behind each other still resolving defines
02735         if (token->type == TT_STRING)
02736         {
02737             token_t newtoken;
02738             if (PC_ReadToken(source, &newtoken))
02739             {
02740                 if (newtoken.type == TT_STRING)
02741                 {
02742                     token->string[strlen(token->string)-1] = '\0';
02743                     if (strlen(token->string) + strlen(newtoken.string+1) + 1 >= MAX_TOKEN)
02744                     {
02745                         SourceError(source, "string longer than MAX_TOKEN %d\n", MAX_TOKEN);
02746                         return qfalse;
02747                     }
02748                     strcat(token->string, newtoken.string+1);
02749                 }
02750                 else
02751                 {
02752                     PC_UnreadToken(source, &newtoken);
02753                 }
02754             }
02755         } //end if
02756         //if skipping source because of conditional compilation
02757         if (source->skip) continue;
02758         //if the token is a name
02759         if (token->type == TT_NAME)
02760         {
02761             //check if the name is a define macro
02762 #if DEFINEHASHING
02763             define = PC_FindHashedDefine(source->definehash, token->string);
02764 #else
02765             define = PC_FindDefine(source->defines, token->string);
02766 #endif //DEFINEHASHING
02767             //if it is a define macro
02768             if (define)
02769             {
02770                 //expand the defined macro
02771                 if (!PC_ExpandDefineIntoSource(source, token, define)) return qfalse;
02772                 continue;
02773             } //end if
02774         } //end if
02775         //copy token for unreading
02776         Com_Memcpy(&source->token, token, sizeof(token_t));
02777         //found a token
02778         return qtrue;
02779     } //end while
02780 } //end of the function PC_ReadToken
02781 //============================================================================
02782 //
02783 // Parameter:               -
02784 // Returns:                 -
02785 // Changes Globals:     -
02786 //============================================================================
02787 int PC_ExpectTokenString(source_t *source, char *string)
02788 {
02789     token_t token;
02790 
02791     if (!PC_ReadToken(source, &token))
02792     {
02793         SourceError(source, "couldn't find expected %s", string);
02794         return qfalse;
02795     } //end if
02796 
02797     if (strcmp(token.string, string))
02798     {
02799         SourceError(source, "expected %s, found %s", string, token.string);
02800         return qfalse;
02801     } //end if
02802     return qtrue;
02803 } //end of the function PC_ExpectTokenString
02804 //============================================================================
02805 //
02806 // Parameter:               -
02807 // Returns:                 -
02808 // Changes Globals:     -
02809 //============================================================================
02810 int PC_ExpectTokenType(source_t *source, int type, int subtype, token_t *token)
02811 {
02812     char str[MAX_TOKEN];
02813 
02814     if (!PC_ReadToken(source, token))
02815     {
02816         SourceError(source, "couldn't read expected token");
02817         return qfalse;
02818     } //end if
02819 
02820     if (token->type != type)
02821     {
02822         strcpy(str, "");
02823         if (type == TT_STRING) strcpy(str, "string");
02824         if (type == TT_LITERAL) strcpy(str, "literal");
02825         if (type == TT_NUMBER) strcpy(str, "number");
02826         if (type == TT_NAME) strcpy(str, "name");
02827         if (type == TT_PUNCTUATION) strcpy(str, "punctuation");
02828         SourceError(source, "expected a %s, found %s", str, token->string);
02829         return qfalse;
02830     } //end if
02831     if (token->type == TT_NUMBER)
02832     {
02833         if ((token->subtype & subtype) != subtype)
02834         {
02835             if (subtype & TT_DECIMAL) strcpy(str, "decimal");
02836             if (subtype & TT_HEX) strcpy(str, "hex");
02837             if (subtype & TT_OCTAL) strcpy(str, "octal");
02838             if (subtype & TT_BINARY) strcpy(str, "binary");
02839             if (subtype & TT_LONG) strcat(str, " long");
02840             if (subtype & TT_UNSIGNED) strcat(str, " unsigned");
02841             if (subtype & TT_FLOAT) strcat(str, " float");
02842             if (subtype & TT_INTEGER) strcat(str, " integer");
02843             SourceError(source, "expected %s, found %s", str, token->string);
02844             return qfalse;
02845         } //end if
02846     } //end if
02847     else if (token->type == TT_PUNCTUATION)
02848     {
02849         if (token->subtype != subtype)
02850         {
02851             SourceError(source, "found %s", token->string);
02852             return qfalse;
02853         } //end if
02854     } //end else if
02855     return qtrue;
02856 } //end of the function PC_ExpectTokenType
02857 //============================================================================
02858 //
02859 // Parameter:               -
02860 // Returns:                 -
02861 // Changes Globals:     -
02862 //============================================================================
02863 int PC_ExpectAnyToken(source_t *source, token_t *token)
02864 {
02865     if (!PC_ReadToken(source, token))
02866     {
02867         SourceError(source, "couldn't read expected token");
02868         return qfalse;
02869     } //end if
02870     else
02871     {
02872         return qtrue;
02873     } //end else
02874 } //end of the function PC_ExpectAnyToken
02875 //============================================================================
02876 //
02877 // Parameter:               -
02878 // Returns:                 -
02879 // Changes Globals:     -
02880 //============================================================================
02881 int PC_CheckTokenString(source_t *source, char *string)
02882 {
02883     token_t tok;
02884 
02885     if (!PC_ReadToken(source, &tok)) return qfalse;
02886     //if the token is available
02887     if (!strcmp(tok.string, string)) return qtrue;
02888     //
02889     PC_UnreadSourceToken(source, &tok);
02890     return qfalse;
02891 } //end of the function PC_CheckTokenString
02892 //============================================================================
02893 //
02894 // Parameter:               -
02895 // Returns:                 -
02896 // Changes Globals:     -
02897 //============================================================================
02898 int PC_CheckTokenType(source_t *source, int type, int subtype, token_t *token)
02899 {
02900     token_t tok;
02901 
02902     if (!PC_ReadToken(source, &tok)) return qfalse;
02903     //if the type matches
02904     if (tok.type == type &&
02905             (tok.subtype & subtype) == subtype)
02906     {
02907         Com_Memcpy(token, &tok, sizeof(token_t));
02908         return qtrue;
02909     } //end if
02910     //
02911     PC_UnreadSourceToken(source, &tok);
02912     return qfalse;
02913 } //end of the function PC_CheckTokenType
02914 //============================================================================
02915 //
02916 // Parameter:               -
02917 // Returns:                 -
02918 // Changes Globals:     -
02919 //============================================================================
02920 int PC_SkipUntilString(source_t *source, char *string)
02921 {
02922     token_t token;
02923 
02924     while(PC_ReadToken(source, &token))
02925     {
02926         if (!strcmp(token.string, string)) return qtrue;
02927     } //end while
02928     return qfalse;
02929 } //end of the function PC_SkipUntilString
02930 //============================================================================
02931 //
02932 // Parameter:               -
02933 // Returns:                 -
02934 // Changes Globals:     -
02935 //============================================================================
02936 void PC_UnreadLastToken(source_t *source)
02937 {
02938     PC_UnreadSourceToken(source, &source->token);
02939 } //end of the function PC_UnreadLastToken
02940 //============================================================================
02941 //
02942 // Parameter:               -
02943 // Returns:                 -
02944 // Changes Globals:     -
02945 //============================================================================
02946 void PC_UnreadToken(source_t *source, token_t *token)
02947 {
02948     PC_UnreadSourceToken(source, token);
02949 } //end of the function PC_UnreadToken
02950 //============================================================================
02951 //
02952 // Parameter:               -
02953 // Returns:                 -
02954 // Changes Globals:     -
02955 //============================================================================
02956 void PC_SetIncludePath(source_t *source, char *path)
02957 {
02958     strncpy(source->includepath, path, MAX_PATH);
02959     //add trailing path seperator
02960     if (source->includepath[strlen(source->includepath)-1] != '\\' &&
02961         source->includepath[strlen(source->includepath)-1] != '/')
02962     {
02963         strcat(source->includepath, PATHSEPERATOR_STR);
02964     } //end if
02965 } //end of the function PC_SetIncludePath
02966 //============================================================================
02967 //
02968 // Parameter:               -
02969 // Returns:                 -
02970 // Changes Globals:     -
02971 //============================================================================
02972 void PC_SetPunctuations(source_t *source, punctuation_t *p)
02973 {
02974     source->punctuations = p;
02975 } //end of the function PC_SetPunctuations
02976 //============================================================================
02977 //
02978 // Parameter:           -
02979 // Returns:             -
02980 // Changes Globals:     -
02981 //============================================================================
02982 source_t *LoadSourceFile(const char *filename)
02983 {
02984     source_t *source;
02985     script_t *script;
02986 
02987     PC_InitTokenHeap();
02988 
02989     script = LoadScriptFile(filename);
02990     if (!script) return NULL;
02991 
02992     script->next = NULL;
02993 
02994     source = (source_t *) GetMemory(sizeof(source_t));
02995     Com_Memset(source, 0, sizeof(source_t));
02996 
02997     strncpy(source->filename, filename, MAX_PATH);
02998     source->scriptstack = script;
02999     source->tokens = NULL;
03000     source->defines = NULL;
03001     source->indentstack = NULL;
03002     source->skip = 0;
03003 
03004 #if DEFINEHASHING
03005     source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
03006 #endif //DEFINEHASHING
03007     PC_AddGlobalDefinesToSource(source);
03008     return source;
03009 } //end of the function LoadSourceFile
03010 //============================================================================
03011 //
03012 // Parameter:               -
03013 // Returns:                 -
03014 // Changes Globals:     -
03015 //============================================================================
03016 source_t *LoadSourceMemory(char *ptr, int length, char *name)
03017 {
03018     source_t *source;
03019     script_t *script;
03020 
03021     PC_InitTokenHeap();
03022 
03023     script = LoadScriptMemory(ptr, length, name);
03024     if (!script) return NULL;
03025     script->next = NULL;
03026 
03027     source = (source_t *) GetMemory(sizeof(source_t));
03028     Com_Memset(source, 0, sizeof(source_t));
03029 
03030     strncpy(source->filename, name, MAX_PATH);
03031     source->scriptstack = script;
03032     source->tokens = NULL;
03033     source->defines = NULL;
03034     source->indentstack = NULL;
03035     source->skip = 0;
03036 
03037 #if DEFINEHASHING
03038     source->definehash = GetClearedMemory(DEFINEHASHSIZE * sizeof(define_t *));
03039 #endif //DEFINEHASHING
03040     PC_AddGlobalDefinesToSource(source);
03041     return source;
03042 } //end of the function LoadSourceMemory
03043 //============================================================================
03044 //
03045 // Parameter:               -
03046 // Returns:                 -
03047 // Changes Globals:     -
03048 //============================================================================
03049 void FreeSource(source_t *source)
03050 {
03051     script_t *script;
03052     token_t *token;
03053     define_t *define;
03054     indent_t *indent;
03055     int i;
03056 
03057     //PC_PrintDefineHashTable(source->definehash);
03058     //free all the scripts
03059     while(source->scriptstack)
03060     {
03061         script = source->scriptstack;
03062         source->scriptstack = source->scriptstack->next;
03063         FreeScript(script);
03064     } //end for
03065     //free all the tokens
03066     while(source->tokens)
03067     {
03068         token = source->tokens;
03069         source->tokens = source->tokens->next;
03070         PC_FreeToken(token);
03071     } //end for
03072 #if DEFINEHASHING
03073     for (i = 0; i < DEFINEHASHSIZE; i++)
03074     {
03075         while(source->definehash[i])
03076         {
03077             define = source->definehash[i];
03078             source->definehash[i] = source->definehash[i]->hashnext;
03079             PC_FreeDefine(define);
03080         } //end while
03081     } //end for
03082 #else //DEFINEHASHING
03083     //free all defines
03084     while(source->defines)
03085     {
03086         define = source->defines;
03087         source->defines = source->defines->next;
03088         PC_FreeDefine(define);
03089     } //end for
03090 #endif //DEFINEHASHING
03091     //free all indents
03092     while(source->indentstack)
03093     {
03094         indent = source->indentstack;
03095         source->indentstack = source->indentstack->next;
03096         FreeMemory(indent);
03097     } //end for
03098 #if DEFINEHASHING
03099     //
03100     if (source->definehash) FreeMemory(source->definehash);
03101 #endif //DEFINEHASHING
03102     //free the source itself
03103     FreeMemory(source);
03104 } //end of the function FreeSource
03105 //============================================================================
03106 //
03107 // Parameter:           -
03108 // Returns:             -
03109 // Changes Globals:     -
03110 //============================================================================
03111 
03112 #define MAX_SOURCEFILES     64
03113 
03114 source_t *sourceFiles[MAX_SOURCEFILES];
03115 
03116 int PC_LoadSourceHandle(const char *filename)
03117 {
03118     source_t *source;
03119     int i;
03120 
03121     for (i = 1; i < MAX_SOURCEFILES; i++)
03122     {
03123         if (!sourceFiles[i])
03124             break;
03125     } //end for
03126     if (i >= MAX_SOURCEFILES)
03127         return 0;
03128     PS_SetBaseFolder("");
03129     source = LoadSourceFile(filename);
03130     if (!source)
03131         return 0;
03132     sourceFiles[i] = source;
03133     return i;
03134 } //end of the function PC_LoadSourceHandle
03135 //============================================================================
03136 //
03137 // Parameter:           -
03138 // Returns:             -
03139 // Changes Globals:     -
03140 //============================================================================
03141 int PC_FreeSourceHandle(int handle)
03142 {
03143     if (handle < 1 || handle >= MAX_SOURCEFILES)
03144         return qfalse;
03145     if (!sourceFiles[handle])
03146         return qfalse;
03147 
03148     FreeSource(sourceFiles[handle]);
03149     sourceFiles[handle] = NULL;
03150     return qtrue;
03151 } //end of the function PC_FreeSourceHandle
03152 //============================================================================
03153 //
03154 // Parameter:           -
03155 // Returns:             -
03156 // Changes Globals:     -
03157 //============================================================================
03158 int PC_ReadTokenHandle(int handle, pc_token_t *pc_token)
03159 {
03160     token_t token;
03161     int ret;
03162 
03163     if (handle < 1 || handle >= MAX_SOURCEFILES)
03164         return 0;
03165     if (!sourceFiles[handle])
03166         return 0;
03167 
03168     ret = PC_ReadToken(sourceFiles[handle], &token);
03169     strcpy(pc_token->string, token.string);
03170     pc_token->type = token.type;
03171     pc_token->subtype = token.subtype;
03172     pc_token->intvalue = token.intvalue;
03173     pc_token->floatvalue = token.floatvalue;
03174     if (pc_token->type == TT_STRING)
03175         StripDoubleQuotes(pc_token->string);
03176     return ret;
03177 } //end of the function PC_ReadTokenHandle
03178 //============================================================================
03179 //
03180 // Parameter:           -
03181 // Returns:             -
03182 // Changes Globals:     -
03183 //============================================================================
03184 int PC_SourceFileAndLine(int handle, char *filename, int *line)
03185 {
03186     if (handle < 1 || handle >= MAX_SOURCEFILES)
03187         return qfalse;
03188     if (!sourceFiles[handle])
03189         return qfalse;
03190 
03191     strcpy(filename, sourceFiles[handle]->filename);
03192     if (sourceFiles[handle]->scriptstack)
03193         *line = sourceFiles[handle]->scriptstack->line;
03194     else
03195         *line = 0;
03196     return qtrue;
03197 } //end of the function PC_SourceFileAndLine
03198 //============================================================================
03199 //
03200 // Parameter:           -
03201 // Returns:             -
03202 // Changes Globals:     -
03203 //============================================================================
03204 void PC_SetBaseFolder(char *path)
03205 {
03206     PS_SetBaseFolder(path);
03207 } //end of the function PC_SetBaseFolder
03208 //============================================================================
03209 //
03210 // Parameter:           -
03211 // Returns:             -
03212 // Changes Globals:     -
03213 //============================================================================
03214 void PC_CheckOpenSourceHandles(void)
03215 {
03216     int i;
03217 
03218     for (i = 1; i < MAX_SOURCEFILES; i++)
03219     {
03220         if (sourceFiles[i])
03221         {
03222 #ifdef BOTLIB
03223             botimport.Print(PRT_ERROR, "file %s still open in precompiler\n", sourceFiles[i]->scriptstack->filename);
03224 #endif  //BOTLIB
03225         } //end if
03226     } //end for
03227 } //end of the function PC_CheckOpenSourceHandles
03228 

Generated on Thu Aug 25 12:37:13 2005 for Quake III Arena by  doxygen 1.3.9.1