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