]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/common/scriplib.c
Q3map2:
[xonotic/netradiant.git] / tools / quake3 / common / scriplib.c
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    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 GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 // scriplib.c
23
24 #include "cmdlib.h"
25 #include "mathlib.h"
26 #include "inout.h"
27 #include "scriplib.h"
28 #include "vfs.h"
29
30 /*
31    =============================================================================
32
33                         PARSING STUFF
34
35    =============================================================================
36  */
37
38 typedef struct
39 {
40         char filename[1024];
41         char    *buffer,*script_p,*end_p;
42         int line;
43 } script_t;
44
45 #define MAX_INCLUDES    8
46 script_t scriptstack[MAX_INCLUDES];
47 script_t    *script;
48 int scriptline;
49
50 char token[MAXTOKEN];
51 qboolean endofscript;
52 qboolean tokenready;                     // only qtrue if UnGetToken was just called
53
54 /*
55    ==============
56    AddScriptToStack
57    ==============
58  */
59 void AddScriptToStack( const char *filename, int index ){
60         int size;
61
62         script++;
63         if ( script == &scriptstack[MAX_INCLUDES] ) {
64                 Error( "script file exceeded MAX_INCLUDES" );
65         }
66         strcpy( script->filename, ExpandPath( filename ) );
67
68         size = vfsLoadFile( script->filename, (void **)&script->buffer, index );
69
70         if ( size == -1 ) {
71                 Sys_Printf( "Script file %s was not found\n", script->filename );
72         }
73         else
74         {
75                 if ( index > 0 ) {
76                         Sys_Printf( "entering %s (%d)\n", script->filename, index + 1 );
77                 }
78                 else{
79                         Sys_Printf( "entering %s\n", script->filename );
80                 }
81         }
82
83         script->line = 1;
84         script->script_p = script->buffer;
85         script->end_p = script->buffer + size;
86 }
87
88
89 /*
90    ==============
91    LoadScriptFile
92    ==============
93  */
94 void LoadScriptFile( const char *filename, int index ){
95         script = scriptstack;
96         AddScriptToStack( filename, index );
97
98         endofscript = qfalse;
99         tokenready = qfalse;
100 }
101 /* &unload current; for autopacker */
102 void SilentLoadScriptFile( const char *filename, int index ){
103         int size;
104
105         if ( script->buffer != NULL && !endofscript ) {
106                 free( script->buffer );
107                 script->buffer = NULL;
108         }
109
110         script = scriptstack;
111
112         script++;
113         if ( script == &scriptstack[MAX_INCLUDES] ) {
114                 Error( "script file exceeded MAX_INCLUDES" );
115         }
116         strcpy( script->filename, ExpandPath( filename ) );
117
118         size = vfsLoadFile( script->filename, (void **)&script->buffer, index );
119
120         if ( size == -1 ) {
121                 Sys_Printf( "Script file %s was not found\n", script->filename );
122         }
123         script->line = 1;
124         script->script_p = script->buffer;
125         script->end_p = script->buffer + size;
126
127         endofscript = qfalse;
128         tokenready = qfalse;
129 }
130
131 /*
132    ==============
133    ParseFromMemory
134    ==============
135  */
136 void ParseFromMemory( char *buffer, int size ){
137         script = scriptstack;
138         script++;
139         if ( script == &scriptstack[MAX_INCLUDES] ) {
140                 Error( "script file exceeded MAX_INCLUDES" );
141         }
142         strcpy( script->filename, "memory buffer" );
143
144         script->buffer = buffer;
145         script->line = 1;
146         script->script_p = script->buffer;
147         script->end_p = script->buffer + size;
148
149         endofscript = qfalse;
150         tokenready = qfalse;
151 }
152
153
154 /*
155    ==============
156    UnGetToken
157
158    Signals that the current token was not used, and should be reported
159    for the next GetToken.  Note that
160
161    GetToken (qtrue);
162    UnGetToken ();
163    GetToken (qfalse);
164
165    could cross a line boundary.
166    ==============
167  */
168 void UnGetToken( void ){
169         tokenready = qtrue;
170 }
171
172
173 qboolean EndOfScript( qboolean crossline ){
174         if ( !crossline ) {
175                 Error( "Line %i is incomplete\n",scriptline );
176         }
177
178         if ( !strcmp( script->filename, "memory buffer" ) ) {
179                 endofscript = qtrue;
180                 return qfalse;
181         }
182
183         if ( script->buffer == NULL ) {
184                 Sys_Printf( "WARNING: Attempt to free already freed script buffer\n" );
185         }
186         else{
187                 free( script->buffer );
188         }
189         script->buffer = NULL;
190         if ( script == scriptstack + 1 ) {
191                 endofscript = qtrue;
192                 return qfalse;
193         }
194         script--;
195         scriptline = script->line;
196         Sys_Printf( "returning to %s\n", script->filename );
197         return GetToken( crossline );
198 }
199
200 /*
201    ==============
202    GetToken
203    ==============
204  */
205 qboolean GetToken( qboolean crossline ){
206         char    *token_p;
207
208
209         /* ydnar: dummy testing */
210         if ( script == NULL || script->buffer == NULL ) {
211                 return qfalse;
212         }
213
214         if ( tokenready ) {                       // is a token already waiting?
215                 tokenready = qfalse;
216                 return qtrue;
217         }
218
219         if ( ( script->script_p >= script->end_p ) || ( script->script_p == NULL ) ) {
220                 return EndOfScript( crossline );
221         }
222
223 //
224 // skip space
225 //
226 skipspace:
227         while ( *script->script_p <= 32 )
228         {
229                 if ( script->script_p >= script->end_p ) {
230                         return EndOfScript( crossline );
231                 }
232                 if ( *script->script_p++ == '\n' ) {
233                         if ( !crossline ) {
234                                 Error( "Line %i is incomplete\n",scriptline );
235                         }
236                         script->line++;
237                         scriptline = script->line;
238                 }
239         }
240
241         if ( script->script_p >= script->end_p ) {
242                 return EndOfScript( crossline );
243         }
244
245         // ; # // comments
246         if ( *script->script_p == ';' || *script->script_p == '#'
247                  || ( script->script_p[0] == '/' && script->script_p[1] == '/' ) ) {
248                 if ( !crossline ) {
249                         Error( "Line %i is incomplete\n",scriptline );
250                 }
251                 while ( *script->script_p++ != '\n' )
252                         if ( script->script_p >= script->end_p ) {
253                                 return EndOfScript( crossline );
254                         }
255                 script->line++;
256                 scriptline = script->line;
257                 goto skipspace;
258         }
259
260         // /* */ comments
261         if ( script->script_p[0] == '/' && script->script_p[1] == '*' ) {
262                 if ( !crossline ) {
263                         Error( "Line %i is incomplete\n",scriptline );
264                 }
265                 script->script_p += 2;
266                 while ( script->script_p[0] != '*' && script->script_p[1] != '/' )
267                 {
268                         if ( *script->script_p == '\n' ) {
269                                 script->line++;
270                                 scriptline = script->line;
271                         }
272                         script->script_p++;
273                         if ( script->script_p >= script->end_p ) {
274                                 return EndOfScript( crossline );
275                         }
276                 }
277                 script->script_p += 2;
278                 goto skipspace;
279         }
280
281 //
282 // copy token
283 //
284         token_p = token;
285
286         if ( *script->script_p == '"' ) {
287                 // quoted token
288                 script->script_p++;
289                 while ( *script->script_p != '"' )
290                 {
291                         *token_p++ = *script->script_p++;
292                         if ( script->script_p == script->end_p ) {
293                                 break;
294                         }
295                         if ( token_p == &token[MAXTOKEN] ) {
296                                 Error( "Token too large on line %i\n",scriptline );
297                         }
298                 }
299                 script->script_p++;
300         }
301         else{   // regular token
302                 while ( *script->script_p > 32 && *script->script_p != ';' )
303                 {
304                         *token_p++ = *script->script_p++;
305                         if ( script->script_p == script->end_p ) {
306                                 break;
307                         }
308                         if ( token_p == &token[MAXTOKEN] ) {
309                                 Error( "Token too large on line %i\n",scriptline );
310                         }
311                 }
312         }
313
314         *token_p = 0;
315
316         if ( !strcmp( token, "$include" ) ) {
317                 GetToken( qfalse );
318                 AddScriptToStack( token, 0 );
319                 return GetToken( crossline );
320         }
321
322         return qtrue;
323 }
324
325
326 /*
327    ==============
328    TokenAvailable
329
330    Returns qtrue if there is another token on the line
331    ==============
332  */
333 qboolean TokenAvailable( void ) {
334         int oldLine;
335         qboolean r;
336
337         /* save */
338         oldLine = scriptline;
339
340         /* test */
341         r = GetToken( qtrue );
342         if ( !r ) {
343                 return qfalse;
344         }
345         UnGetToken();
346         if ( oldLine == scriptline ) {
347                 return qtrue;
348         }
349
350         /* restore */
351         //%     scriptline = oldLine;
352         //%     script->line = oldScriptLine;
353
354         return qfalse;
355 }
356
357
358 //=====================================================================
359
360
361 void MatchToken( char *match ) {
362         GetToken( qtrue );
363
364         if ( strcmp( token, match ) ) {
365                 Error( "MatchToken( \"%s\" ) failed at line %i in file %s", match, scriptline, script->filename );
366         }
367 }
368
369
370 void Parse1DMatrix( int x, vec_t *m ) {
371         int i;
372
373         MatchToken( "(" );
374
375         for ( i = 0 ; i < x ; i++ ) {
376                 GetToken( qfalse );
377                 m[i] = atof( token );
378         }
379
380         MatchToken( ")" );
381 }
382
383 void Parse2DMatrix( int y, int x, vec_t *m ) {
384         int i;
385
386         MatchToken( "(" );
387
388         for ( i = 0 ; i < y ; i++ ) {
389                 Parse1DMatrix( x, m + i * x );
390         }
391
392         MatchToken( ")" );
393 }
394
395 void Parse3DMatrix( int z, int y, int x, vec_t *m ) {
396         int i;
397
398         MatchToken( "(" );
399
400         for ( i = 0 ; i < z ; i++ ) {
401                 Parse2DMatrix( y, x, m + i * x * y );
402         }
403
404         MatchToken( ")" );
405 }
406
407
408 void Write1DMatrix( FILE *f, int x, vec_t *m ) {
409         int i;
410
411         fprintf( f, "( " );
412         for ( i = 0 ; i < x ; i++ ) {
413                 if ( m[i] == (int)m[i] ) {
414                         fprintf( f, "%i ", (int)m[i] );
415                 }
416                 else {
417                         fprintf( f, "%f ", m[i] );
418                 }
419         }
420         fprintf( f, ")" );
421 }
422
423 void Write2DMatrix( FILE *f, int y, int x, vec_t *m ) {
424         int i;
425
426         fprintf( f, "( " );
427         for ( i = 0 ; i < y ; i++ ) {
428                 Write1DMatrix( f, x, m + i * x );
429                 fprintf( f, " " );
430         }
431         fprintf( f, ")\n" );
432 }
433
434
435 void Write3DMatrix( FILE *f, int z, int y, int x, vec_t *m ) {
436         int i;
437
438         fprintf( f, "(\n" );
439         for ( i = 0 ; i < z ; i++ ) {
440                 Write2DMatrix( f, y, x, m + i * ( x * y ) );
441         }
442         fprintf( f, ")\n" );
443 }