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