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