Merge commit '515673c08f8718a237e90c2130a1f5294f966d6a'
[xonotic/netradiant.git] / tools / quake2 / 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 // scriplib.c
22
23 #include "cmdlib.h"
24 #include "inout.h"
25 #include "scriplib.h"
26
27 /*
28 =============================================================================
29
30                                                 PARSING STUFF
31
32 =============================================================================
33 */
34
35 typedef struct
36 {
37         char    filename[1024];
38         char    *buffer,*script_p,*end_p;
39         int     line;
40 } script_t;
41
42 #define MAX_INCLUDES    8
43 script_t        scriptstack[MAX_INCLUDES];
44 script_t        *script;
45 int                     scriptline;
46
47 char    token[MAXTOKEN];
48 qboolean endofscript;
49 qboolean tokenready;                     // only true if UnGetToken was just called
50
51 /*
52 ==============
53 AddScriptToStack
54 ==============
55 */
56 void AddScriptToStack (char *filename)
57 {
58         int            size;
59
60         script++;
61         if (script == &scriptstack[MAX_INCLUDES])
62                 Error ("script file exceeded MAX_INCLUDES");
63         strcpy (script->filename, ExpandPath (filename) );
64
65         size = LoadFile (script->filename, (void **)&script->buffer);
66
67         printf ("entering %s\n", script->filename);
68
69         script->line = 1;
70
71         script->script_p = script->buffer;
72         script->end_p = script->buffer + size;
73 }
74
75
76 /*
77 ==============
78 LoadScriptFile
79 ==============
80 */
81 void LoadScriptFile (char *filename)
82 {
83         script = scriptstack;
84         AddScriptToStack (filename);
85
86         endofscript = false;
87         tokenready = false;
88 }
89
90
91 /*
92 ==============
93 ParseFromMemory
94 ==============
95 */
96 void ParseFromMemory (char *buffer, int size)
97 {
98         script = scriptstack;
99         script++;
100         if (script == &scriptstack[MAX_INCLUDES])
101                 Error ("script file exceeded MAX_INCLUDES");
102         strcpy (script->filename, "memory buffer" );
103
104         script->buffer = buffer;
105         script->line = 1;
106         script->script_p = script->buffer;
107         script->end_p = script->buffer + size;
108
109         endofscript = false;
110         tokenready = false;
111 }
112
113
114 /*
115 ==============
116 UnGetToken
117
118 Signals that the current token was not used, and should be reported
119 for the next GetToken.  Note that
120
121 GetToken (true);
122 UnGetToken ();
123 GetToken (false);
124
125 could cross a line boundary.
126 ==============
127 */
128 void UnGetToken (void)
129 {
130         tokenready = true;
131 }
132
133
134 qboolean EndOfScript (qboolean crossline)
135 {
136         if (!crossline)
137                 Error ("Line %i is incomplete\n",scriptline);
138
139         if (!strcmp (script->filename, "memory buffer"))
140         {
141                 endofscript = true;
142                 return false;
143         }
144
145         free (script->buffer);
146         if (script == scriptstack+1)
147         {
148                 endofscript = true;
149                 return false;
150         }
151         script--;
152         scriptline = script->line;
153         printf ("returning to %s\n", script->filename);
154         return GetToken (crossline);
155 }
156
157 /*
158 ==============
159 GetToken
160 ==============
161 */
162 qboolean GetToken (qboolean crossline)
163 {
164         char    *token_p;
165
166         if (tokenready)                         // is a token allready waiting?
167         {
168                 tokenready = false;
169                 return true;
170         }
171
172         if (script->script_p >= script->end_p)
173                 return EndOfScript (crossline);
174
175 //
176 // skip space
177 //
178 skipspace:
179         while (*script->script_p <= 32)
180         {
181                 if (script->script_p >= script->end_p)
182                         return EndOfScript (crossline);
183                 if (*script->script_p++ == '\n')
184                 {
185                         if (!crossline)
186                                 Error ("Line %i is incomplete\n",scriptline);
187                         scriptline = script->line++;
188                 }
189         }
190
191         if (script->script_p >= script->end_p)
192                 return EndOfScript (crossline);
193
194         // ; # // comments
195         if (*script->script_p == ';' || *script->script_p == '#'
196                 || ( script->script_p[0] == '/' && script->script_p[1] == '/') )
197         {
198                 if (!crossline)
199                         Error ("Line %i is incomplete\n",scriptline);
200                 while (*script->script_p++ != '\n')
201                         if (script->script_p >= script->end_p)
202                                 return EndOfScript (crossline);
203                 goto skipspace;
204         }
205
206         // /* */ comments
207         if (script->script_p[0] == '/' && script->script_p[1] == '*')
208         {
209                 if (!crossline)
210                         Error ("Line %i is incomplete\n",scriptline);
211                 script->script_p+=2;
212                 while (script->script_p[0] != '*' && script->script_p[1] != '/')
213                 {
214                         script->script_p++;
215                         if (script->script_p >= script->end_p)
216                                 return EndOfScript (crossline);
217                 }
218                 script->script_p += 2;
219                 goto skipspace;
220         }
221
222 //
223 // copy token
224 //
225         token_p = token;
226
227         if (*script->script_p == '"')
228         {
229                 // quoted token
230                 script->script_p++;
231                 while (*script->script_p != '"')
232                 {
233                         *token_p++ = *script->script_p++;
234                         if (script->script_p == script->end_p)
235                                 break;
236                         if (token_p == &token[MAXTOKEN])
237                                 Error ("Token too large on line %i\n",scriptline);
238                 }
239                 script->script_p++;
240         }
241         else    // regular token
242         while ( *script->script_p > 32 && *script->script_p != ';')
243         {
244                 *token_p++ = *script->script_p++;
245                 if (script->script_p == script->end_p)
246                         break;
247                 if (token_p == &token[MAXTOKEN])
248                         Error ("Token too large on line %i\n",scriptline);
249         }
250
251         *token_p = 0;
252
253         if (!strcmp (token, "$include"))
254         {
255                 GetToken (false);
256                 AddScriptToStack (token);
257                 return GetToken (crossline);
258         }
259
260         return true;
261 }
262
263
264 /*
265 ==============
266 TokenAvailable
267
268 Returns true if there is another token on the line
269 ==============
270 */
271 qboolean TokenAvailable (void)
272 {
273         char    *search_p;
274
275         search_p = script->script_p;
276
277         if (search_p >= script->end_p)
278                 return false;
279
280         while ( *search_p <= 32)
281         {
282                 if (*search_p == '\n')
283                         return false;
284                 search_p++;
285                 if (search_p == script->end_p)
286                         return false;
287
288         }
289
290         if (*search_p == ';')
291                 return false;
292
293         return true;
294 }
295
296