1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16
17
18 // HEADER FILES ------------------------------------------------------------
19
20 #include <string.h>
21 #include <stdlib.h>
22 #include "h2def.h"
23 #include "i_system.h"
24 #include "m_misc.h"
25
26 // MACROS ------------------------------------------------------------------
27
28 #define MAX_STRING_SIZE 64
29 #define ASCII_COMMENT (';')
30 #define ASCII_QUOTE (34)
31 #define LUMP_SCRIPT 1
32 #define FILE_ZONE_SCRIPT 2
33
34 // TYPES -------------------------------------------------------------------
35
36 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
37
38 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
39
40 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
41
42 static void CheckOpen(void);
43 static void OpenScript(const char *name, int type);
44
45 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
46
47 // PUBLIC DATA DEFINITIONS -------------------------------------------------
48
49 char *sc_String;
50 int sc_Number;
51 int sc_Line;
52 boolean sc_End;
53 boolean sc_Crossed;
54 boolean sc_FileScripts = false;
55 const char *sc_ScriptsDir = "";
56
57 // PRIVATE DATA DEFINITIONS ------------------------------------------------
58
59 static char ScriptName[16];
60 static char *ScriptBuffer;
61 static char *ScriptPtr;
62 static char *ScriptEndPtr;
63 static char StringBuffer[MAX_STRING_SIZE];
64 static int ScriptLumpNum;
65 static boolean ScriptOpen = false;
66 static int ScriptSize;
67 static boolean AlreadyGot = false;
68
69 // CODE --------------------------------------------------------------------
70
71 //==========================================================================
72 //
73 // SC_Open
74 //
75 //==========================================================================
76
SC_Open(const char * name)77 void SC_Open(const char *name)
78 {
79 char fileName[128];
80
81 if (sc_FileScripts == true)
82 {
83 M_snprintf(fileName, sizeof(fileName), "%s%s.txt", sc_ScriptsDir, name);
84 SC_OpenFile(fileName);
85 }
86 else
87 {
88 SC_OpenLump(name);
89 }
90 }
91
92 //==========================================================================
93 //
94 // SC_OpenLump
95 //
96 // Loads a script (from the WAD files) and prepares it for parsing.
97 //
98 //==========================================================================
99
SC_OpenLump(const char * name)100 void SC_OpenLump(const char *name)
101 {
102 OpenScript(name, LUMP_SCRIPT);
103 }
104
105 //==========================================================================
106 //
107 // SC_OpenFile
108 //
109 // Loads a script (from a file) and prepares it for parsing. Uses the
110 // zone memory allocator for memory allocation and de-allocation.
111 //
112 //==========================================================================
113
SC_OpenFile(const char * name)114 void SC_OpenFile(const char *name)
115 {
116 OpenScript(name, FILE_ZONE_SCRIPT);
117 }
118
119 //==========================================================================
120 //
121 // OpenScript
122 //
123 //==========================================================================
124
OpenScript(const char * name,int type)125 static void OpenScript(const char *name, int type)
126 {
127 SC_Close();
128 if (type == LUMP_SCRIPT)
129 { // Lump script
130 ScriptLumpNum = W_GetNumForName(name);
131 ScriptBuffer = (char *) W_CacheLumpNum(ScriptLumpNum, PU_STATIC);
132 ScriptSize = W_LumpLength(ScriptLumpNum);
133 M_StringCopy(ScriptName, name, sizeof(ScriptName));
134 }
135 else if (type == FILE_ZONE_SCRIPT)
136 { // File script - zone
137 ScriptLumpNum = -1;
138 ScriptSize = M_ReadFile(name, (byte **) & ScriptBuffer);
139 M_ExtractFileBase(name, ScriptName);
140 }
141 ScriptPtr = ScriptBuffer;
142 ScriptEndPtr = ScriptPtr + ScriptSize;
143 sc_Line = 1;
144 sc_End = false;
145 ScriptOpen = true;
146 sc_String = StringBuffer;
147 AlreadyGot = false;
148 }
149
150 //==========================================================================
151 //
152 // SC_Close
153 //
154 //==========================================================================
155
SC_Close(void)156 void SC_Close(void)
157 {
158 if (ScriptOpen)
159 {
160 if (ScriptLumpNum >= 0)
161 {
162 W_ReleaseLumpNum(ScriptLumpNum);
163 }
164 else
165 {
166 Z_Free(ScriptBuffer);
167 }
168 ScriptOpen = false;
169 }
170 }
171
172 //==========================================================================
173 //
174 // SC_GetString
175 //
176 //==========================================================================
177
SC_GetString(void)178 boolean SC_GetString(void)
179 {
180 char *text;
181 boolean foundToken;
182
183 CheckOpen();
184 if (AlreadyGot)
185 {
186 AlreadyGot = false;
187 return true;
188 }
189 foundToken = false;
190 sc_Crossed = false;
191 if (ScriptPtr >= ScriptEndPtr)
192 {
193 sc_End = true;
194 return false;
195 }
196 while (foundToken == false)
197 {
198 while (ScriptPtr < ScriptEndPtr && *ScriptPtr <= 32)
199 {
200 if (*ScriptPtr++ == '\n')
201 {
202 sc_Line++;
203 sc_Crossed = true;
204 }
205 }
206 if (ScriptPtr >= ScriptEndPtr)
207 {
208 sc_End = true;
209 return false;
210 }
211 if (*ScriptPtr != ASCII_COMMENT)
212 { // Found a token
213 foundToken = true;
214 }
215 else
216 { // Skip comment
217 while (*ScriptPtr++ != '\n')
218 {
219 if (ScriptPtr >= ScriptEndPtr)
220 {
221 sc_End = true;
222 return false;
223 }
224 }
225 sc_Line++;
226 sc_Crossed = true;
227 }
228 }
229 text = sc_String;
230 if (*ScriptPtr == ASCII_QUOTE)
231 { // Quoted string
232 ScriptPtr++;
233 while (*ScriptPtr != ASCII_QUOTE)
234 {
235 *text++ = *ScriptPtr++;
236 if (ScriptPtr == ScriptEndPtr
237 || text == &sc_String[MAX_STRING_SIZE - 1])
238 {
239 break;
240 }
241 }
242 ScriptPtr++;
243 }
244 else
245 { // Normal string
246 while ((*ScriptPtr > 32) && (*ScriptPtr != ASCII_COMMENT))
247 {
248 *text++ = *ScriptPtr++;
249 if (ScriptPtr == ScriptEndPtr
250 || text == &sc_String[MAX_STRING_SIZE - 1])
251 {
252 break;
253 }
254 }
255 }
256 *text = 0;
257 return true;
258 }
259
260 //==========================================================================
261 //
262 // SC_MustGetString
263 //
264 //==========================================================================
265
SC_MustGetString(void)266 void SC_MustGetString(void)
267 {
268 if (SC_GetString() == false)
269 {
270 SC_ScriptError("Missing string.");
271 }
272 }
273
274 //==========================================================================
275 //
276 // SC_MustGetStringName
277 //
278 //==========================================================================
279
SC_MustGetStringName(char * name)280 void SC_MustGetStringName(char *name)
281 {
282 SC_MustGetString();
283 if (SC_Compare(name) == false)
284 {
285 SC_ScriptError(NULL);
286 }
287 }
288
289 //==========================================================================
290 //
291 // SC_GetNumber
292 //
293 //==========================================================================
294
SC_GetNumber(void)295 boolean SC_GetNumber(void)
296 {
297 char *stopper;
298
299 CheckOpen();
300 if (SC_GetString())
301 {
302 sc_Number = strtol(sc_String, &stopper, 0);
303 if (*stopper != 0)
304 {
305 I_Error("SC_GetNumber: Bad numeric constant \"%s\".\n"
306 "Script %s, Line %d", sc_String, ScriptName, sc_Line);
307 }
308 return true;
309 }
310 else
311 {
312 return false;
313 }
314 }
315
316 //==========================================================================
317 //
318 // SC_MustGetNumber
319 //
320 //==========================================================================
321
SC_MustGetNumber(void)322 void SC_MustGetNumber(void)
323 {
324 if (SC_GetNumber() == false)
325 {
326 SC_ScriptError("Missing integer.");
327 }
328 }
329
330 //==========================================================================
331 //
332 // SC_UnGet
333 //
334 // Assumes there is a valid string in sc_String.
335 //
336 //==========================================================================
337
SC_UnGet(void)338 void SC_UnGet(void)
339 {
340 AlreadyGot = true;
341 }
342
343 //==========================================================================
344 //
345 // SC_Check
346 //
347 // Returns true if another token is on the current line.
348 //
349 //==========================================================================
350
351 /*
352 boolean SC_Check(void)
353 {
354 char *text;
355
356 CheckOpen();
357 text = ScriptPtr;
358 if(text >= ScriptEndPtr)
359 {
360 return false;
361 }
362 while(*text <= 32)
363 {
364 if(*text == '\n')
365 {
366 return false;
367 }
368 text++;
369 if(text == ScriptEndPtr)
370 {
371 return false;
372 }
373 }
374 if(*text == ASCII_COMMENT)
375 {
376 return false;
377 }
378 return true;
379 }
380 */
381
382 //==========================================================================
383 //
384 // SC_MatchString
385 //
386 // Returns the index of the first match to sc_String from the passed
387 // array of strings, or -1 if not found.
388 //
389 //==========================================================================
390
SC_MatchString(const char ** strings)391 int SC_MatchString(const char **strings)
392 {
393 int i;
394
395 for (i = 0; *strings != NULL; i++)
396 {
397 if (SC_Compare(*strings++))
398 {
399 return i;
400 }
401 }
402 return -1;
403 }
404
405 //==========================================================================
406 //
407 // SC_MustMatchString
408 //
409 //==========================================================================
410
SC_MustMatchString(const char ** strings)411 int SC_MustMatchString(const char **strings)
412 {
413 int i;
414
415 i = SC_MatchString(strings);
416 if (i == -1)
417 {
418 SC_ScriptError(NULL);
419 }
420 return i;
421 }
422
423 //==========================================================================
424 //
425 // SC_Compare
426 //
427 //==========================================================================
428
SC_Compare(const char * text)429 boolean SC_Compare(const char *text)
430 {
431 if (strcasecmp(text, sc_String) == 0)
432 {
433 return true;
434 }
435 return false;
436 }
437
438 //==========================================================================
439 //
440 // SC_ScriptError
441 //
442 //==========================================================================
443
SC_ScriptError(const char * message)444 void SC_ScriptError(const char *message)
445 {
446 if (message == NULL)
447 {
448 message = "Bad syntax.";
449 }
450 I_Error("Script error, \"%s\" line %d: %s", ScriptName, sc_Line, message);
451 }
452
453 //==========================================================================
454 //
455 // CheckOpen
456 //
457 //==========================================================================
458
CheckOpen(void)459 static void CheckOpen(void)
460 {
461 if (ScriptOpen == false)
462 {
463 I_Error("SC_ call before SC_Open().");
464 }
465 }
466