~ubuntu-branches/ubuntu/hardy/openarena/hardy-backports

« back to all changes in this revision

Viewing changes to code/botlib/l_precomp.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

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