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