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,