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