1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: sc_man.cpp 4469 2014-01-03 23:38:29Z dr_sean $
5 //
6 // sc_man.c : Heretic 2 : Raven Software, Corp.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //
21 //		General lump script parser from Hexen (MAPINFO, etc)
22 //
23 //-----------------------------------------------------------------------------
24 
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 #include "doomtype.h"
33 #include "i_system.h"
34 #include "sc_man.h"
35 #include "w_wad.h"
36 #include "z_zone.h"
37 #include "cmdlib.h"
38 #include "m_fileio.h"
39 
40 // MACROS ------------------------------------------------------------------
41 
42 #define MAX_STRING_SIZE 4096
43 #define ASCII_COMMENT (';')
44 #define CPP_COMMENT ('/')
45 #define C_COMMENT ('*')
46 #define ASCII_QUOTE (34)
47 #define LUMP_SCRIPT 1
48 #define FILE_ZONE_SCRIPT 2
49 
50 // TYPES -------------------------------------------------------------------
51 
52 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
53 
54 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
55 
56 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
57 
58 static void SC_PrepareScript (void);
59 static void CheckOpen (void);
60 
61 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
62 
63 // PUBLIC DATA DEFINITIONS -------------------------------------------------
64 
65 char *sc_String;
66 int sc_Number;
67 float sc_Float;
68 int sc_Line;
69 BOOL sc_End;
70 BOOL sc_Crossed;
71 BOOL sc_FileScripts = false;
72 char *sc_ScriptsDir;
73 
74 // PRIVATE DATA DEFINITIONS ------------------------------------------------
75 
76 static std::string ScriptName;
77 static char *ScriptBuffer;
78 static char *ScriptPtr;
79 static char *ScriptEndPtr;
80 static char StringBuffer[MAX_STRING_SIZE];
81 static BOOL ScriptOpen = false;
82 static int ScriptSize;
83 static BOOL AlreadyGot = false;
84 static BOOL FreeScript = false;
85 static char *SavedScriptPtr;
86 static int SavedScriptLine;
87 
88 // CODE --------------------------------------------------------------------
89 
90 
91 //
92 // SC_Open
93 //
SC_Open(const char * name)94 void SC_Open (const char *name)
95 {
96 	SC_OpenLumpNum (W_GetNumForName (name), name);
97 }
98 
99 
100 //
101 // SC_OpenFile
102 //
103 // Loads a script (from a file). Uses the zone memory allocator for
104 // memory allocation and de-allocation.
105 //
SC_OpenFile(const char * name)106 void SC_OpenFile (const char *name)
107 {
108 	SC_Close ();
109 	ScriptSize = M_ReadFile (name, (byte **)&ScriptBuffer);
110 	M_ExtractFileBase (name, ScriptName);
111 	FreeScript = true;
112 	SC_PrepareScript ();
113 }
114 
115 
116 //
117 // SC_OpenMem
118 //
119 // Prepares a script that is already in memory for parsing. The caller is
120 // responsible for freeing it, if needed.
121 //
SC_OpenMem(const char * name,char * buffer,int size)122 void SC_OpenMem (const char *name, char *buffer, int size)
123 {
124 	SC_Close ();
125 	ScriptSize = size;
126 	ScriptBuffer = buffer;
127 	ScriptName = name;
128 	FreeScript = false;
129 	SC_PrepareScript ();
130 }
131 
132 
133 //
134 // SC_OpenLumpNum
135 //
136 // Loads a script (from the WAD files).
137 //
SC_OpenLumpNum(int lump,const char * name)138 void SC_OpenLumpNum (int lump, const char *name)
139 {
140 	SC_Close ();
141 	ScriptBuffer = (char *)W_CacheLumpNum (lump, PU_STATIC);
142 	ScriptSize = W_LumpLength (lump);
143 	ScriptName = name;
144 	FreeScript = true;
145 	SC_PrepareScript ();
146 }
147 
148 
149 //
150 // SC_PrepareScript
151 //
152 // Prepares a script for parsing.
153 //
SC_PrepareScript(void)154 static void SC_PrepareScript (void)
155 {
156 	ScriptPtr = ScriptBuffer;
157 	ScriptEndPtr = ScriptPtr + ScriptSize;
158 	sc_Line = 1;
159 	sc_End = false;
160 	ScriptOpen = true;
161 	sc_String = StringBuffer;
162 	AlreadyGot = false;
163 	SavedScriptPtr = NULL;
164 }
165 
166 
167 //
168 // SC_Close
169 //
SC_Close(void)170 void SC_Close (void)
171 {
172 	if (ScriptOpen)
173 	{
174 		if (FreeScript && ScriptBuffer)
175 			Z_Free (ScriptBuffer);
176 		ScriptBuffer = NULL;
177 		ScriptOpen = false;
178 	}
179 }
180 
181 
182 //
183 // SC_SavePos
184 //
185 // Saves the current script location for restoration later
186 //
SC_SavePos(void)187 void SC_SavePos (void)
188 {
189 	CheckOpen ();
190 	if (sc_End)
191 	{
192 		SavedScriptPtr = NULL;
193 	}
194 	else
195 	{
196 		SavedScriptPtr = ScriptPtr;
197 		SavedScriptLine = sc_Line;
198 	}
199 }
200 
201 
202 //
203 // SC_RestorePos
204 //
205 // Restores the previously saved script location
206 //
SC_RestorePos(void)207 void SC_RestorePos (void)
208 {
209 	if (SavedScriptPtr)
210 	{
211 		ScriptPtr = SavedScriptPtr;
212 		sc_Line = SavedScriptLine;
213 		sc_End = false;
214 		AlreadyGot = false;
215 	}
216 }
217 
218 
219 //
220 // SC_GetString
221 //
SC_GetString(void)222 BOOL SC_GetString (void)
223 {
224 	char *text;
225 	BOOL foundToken;
226 
227 	CheckOpen();
228 	if (AlreadyGot)
229 	{
230 		AlreadyGot = false;
231 		return true;
232 	}
233 	foundToken = false;
234 	sc_Crossed = false;
235 	if (ScriptPtr >= ScriptEndPtr)
236 	{
237 		sc_End = true;
238 		return false;
239 	}
240 	while (foundToken == false)
241 	{
242 		while (*ScriptPtr <= 32)
243 		{
244 			if (ScriptPtr >= ScriptEndPtr)
245 			{
246 				sc_End = true;
247 				return false;
248 			}
249 			if (*ScriptPtr++ == '\n')
250 			{
251 				sc_Line++;
252 				sc_Crossed = true;
253 			}
254 		}
255 		if (ScriptPtr >= ScriptEndPtr)
256 		{
257 			sc_End = true;
258 			return false;
259 		}
260 		if (*ScriptPtr != ASCII_COMMENT &&
261 			!(ScriptPtr[0] == CPP_COMMENT && ScriptPtr < ScriptEndPtr - 1 &&
262 			  (ScriptPtr[1] == CPP_COMMENT || ScriptPtr[1] == C_COMMENT)))
263 		{ // Found a token
264 			foundToken = true;
265 		}
266 		else
267 		{ // Skip comment
268 			if (ScriptPtr[0] == CPP_COMMENT && ScriptPtr[1] == C_COMMENT)
269 			{	// C comment
270 				while (ScriptPtr[0] != C_COMMENT || ScriptPtr[1] != CPP_COMMENT)
271 				{
272 					if (ScriptPtr[0] == '\n')
273 					{
274 						sc_Line++;
275 						sc_Crossed = true;
276 					}
277 					ScriptPtr++;
278 					if (ScriptPtr >= ScriptEndPtr - 1)
279 					{
280 						sc_End = true;
281 						return false;
282 					}
283 				}
284 				ScriptPtr += 2;
285 			}
286 			else
287 			{	// C++ comment
288 				while (*ScriptPtr++ != '\n')
289 				{
290 					if (ScriptPtr >= ScriptEndPtr)
291 					{
292 						sc_End = true;
293 						return false;
294 					}
295 				}
296 				sc_Line++;
297 				sc_Crossed = true;
298 			}
299 		}
300 	}
301 	text = sc_String;
302 	if (*ScriptPtr == ASCII_QUOTE)
303 	{ // Quoted string
304 		ScriptPtr++;
305 		while (*ScriptPtr != ASCII_QUOTE)
306 		{
307 			*text++ = *ScriptPtr++;
308 			if (ScriptPtr == ScriptEndPtr
309 				|| text == &sc_String[MAX_STRING_SIZE-1])
310 			{
311 				break;
312 			}
313 		}
314 		ScriptPtr++;
315 	}
316 	else
317 	{ // Normal string
318 		if (strchr ("{}|=", *ScriptPtr))
319 		{
320 			*text++ = *ScriptPtr++;
321 		}
322 		else
323 		{
324 			while ((*ScriptPtr > 32) && (strchr ("{}|=", *ScriptPtr) == NULL)
325 				&& (*ScriptPtr != ASCII_COMMENT)
326 				&& !(ScriptPtr[0] == CPP_COMMENT && (ScriptPtr < ScriptEndPtr - 1) &&
327 					 (ScriptPtr[1] == CPP_COMMENT || ScriptPtr[1] == C_COMMENT)))
328 			{
329 				*text++ = *ScriptPtr++;
330 				if (ScriptPtr == ScriptEndPtr
331 					|| text == &sc_String[MAX_STRING_SIZE-1])
332 				{
333 					break;
334 				}
335 			}
336 		}
337 	}
338 	*text = 0;
339 	return true;
340 }
341 
342 
343 //
344 // SC_MustGetString
345 //
SC_MustGetString(void)346 void SC_MustGetString (void)
347 {
348 	if (SC_GetString () == false)
349 	{
350 		SC_ScriptError ("Missing string (unexpected end of file).");
351 	}
352 }
353 
354 
355 //
356 // SC_MustGetStringName
357 //
SC_MustGetStringName(const char * name)358 void SC_MustGetStringName (const char *name)
359 {
360 	SC_MustGetString ();
361 	if (SC_Compare (name) == false)
362 	{
363 		const char *args[2];
364 		args[0] = name;
365 		args[1] = sc_String;
366 		SC_ScriptError ("Expected '%s', got '%s'.", args);
367 	}
368 }
369 
370 
371 //
372 // SC_GetNumber
373 //
SC_GetNumber(void)374 BOOL SC_GetNumber (void)
375 {
376 	char *stopper;
377 
378 	CheckOpen ();
379 	if (SC_GetString())
380 	{
381 		if (strcmp (sc_String, "MAXINT") == 0)
382 		{
383 			sc_Number = MAXINT;
384 		}
385 		else
386 		{
387 			sc_Number = strtol (sc_String, &stopper, 0);
388 			if (*stopper != 0)
389 			{
390 				//I_Error ("SC_GetNumber: Bad numeric constant \"%s\".\n"
391 				//	"Script %s, Line %d\n", sc_String, ScriptName.c_str(), sc_Line);
392 				Printf (PRINT_HIGH,"SC_GetNumber: Bad numeric constant \"%s\".\n"
393 					"Script %s, Line %d\n", sc_String, ScriptName.c_str(), sc_Line);
394 			}
395 		}
396 		sc_Float = (float)sc_Number;
397 		return true;
398 	}
399 	else
400 	{
401 		return false;
402 	}
403 }
404 
405 
406 //
407 // SC_MustGetNumber
408 //
SC_MustGetNumber(void)409 void SC_MustGetNumber (void)
410 {
411 	if (SC_GetNumber() == false)
412 	{
413 		SC_ScriptError ("Missing integer (unexpected end of file).");
414 	}
415 }
416 
417 
418 //
419 // SC_GetFloat
420 //
SC_GetFloat(void)421 BOOL SC_GetFloat (void)
422 {
423 	char *stopper;
424 
425 	CheckOpen ();
426 	if (SC_GetString())
427 	{
428 		sc_Float = (float)strtod (sc_String, &stopper);
429 		if (*stopper != 0)
430 		{
431 			//I_Error ("SC_GetFloat: Bad numeric constant \"%s\".\n"
432 			//	"Script %s, Line %d\n", sc_String, ScriptName.c_str(), sc_Line);
433 			Printf (PRINT_HIGH,"SC_GetFloat: Bad numeric constant \"%s\".\n"
434 				"Script %s, Line %d\n", sc_String, ScriptName.c_str(), sc_Line);
435 		}
436 		sc_Number = (int)sc_Float;
437 		return true;
438 	}
439 	else
440 	{
441 		return false;
442 	}
443 }
444 
445 
446 //
447 // SC_MustGetFloat
448 //
SC_MustGetFloat(void)449 void SC_MustGetFloat (void)
450 {
451 	if (SC_GetFloat() == false)
452 	{
453 		SC_ScriptError ("Missing floating-point number (unexpected end of file).");
454 	}
455 }
456 
457 
458 //
459 // SC_UnGet
460 //
461 // Assumes there is a valid string in sc_String.
462 //
SC_UnGet(void)463 void SC_UnGet (void)
464 {
465 	AlreadyGot = true;
466 }
467 
468 
469 //
470 // SC_Check
471 //
472 // Returns true if another token is on the current line.
473 //
474 
475 
476 /*
477 BOOL SC_Check(void)
478 {
479 	char *text;
480 
481 	CheckOpen();
482 	text = ScriptPtr;
483 	if(text >= ScriptEndPtr)
484 	{
485 		return false;
486 	}
487 	while(*text <= 32)
488 	{
489 		if(*text == '\n')
490 		{
491 			return false;
492 		}
493 		text++;
494 		if(text == ScriptEndPtr)
495 		{
496 			return false;
497 		}
498 	}
499 	if(*text == ASCII_COMMENT)
500 	{
501 		return false;
502 	}
503 	return true;
504 }
505 */
506 
507 
508 //
509 // SC_MatchString
510 //
511 // Returns the index of the first match to sc_String from the passed
512 // array of strings, or -1 if not found.
513 //
SC_MatchString(const char ** strings)514 int SC_MatchString (const char **strings)
515 {
516 	int i;
517 
518 	for (i = 0; *strings != NULL; i++)
519 	{
520 		if (SC_Compare (*strings++))
521 		{
522 			return i;
523 		}
524 	}
525 	return -1;
526 }
527 
528 
529 //
530 // SC_MustMatchString
531 //
SC_MustMatchString(const char ** strings)532 int SC_MustMatchString (const char **strings)
533 {
534 	int i;
535 
536 	i = SC_MatchString (strings);
537 	if (i == -1)
538 	{
539 		SC_ScriptError (NULL);
540 	}
541 	return i;
542 }
543 
544 
545 //
546 // SC_Compare
547 //
SC_Compare(const char * text)548 BOOL SC_Compare (const char *text)
549 {
550 	return (stricmp (text, sc_String) == 0);
551 }
552 
553 
554 //
555 // SC_ScriptError
556 //
SC_ScriptError(const char * message,const char ** args)557 void SC_ScriptError (const char *message, const char **args)
558 {
559 	//char composed[2048];
560 	if (message == NULL)
561 		message = "Bad syntax.";
562 
563 /*#if !defined(__GNUC__) && !defined(_MSC_VER)
564 	va_list arglist;
565 	va_start (arglist, *args);
566 	vsprintf (composed, message, arglist);
567 	va_end (arglist);
568 #else
569 	vsprintf (composed, message, args);
570 #endif*/
571 
572     Printf(PRINT_HIGH,"Script error, \"%s\" line %d: %s\n", ScriptName.c_str(),
573 		sc_Line, message);
574 
575 	//I_Error ("Script error, \"%s\" line %d: %s\n", ScriptName.c_str(),
576 	//	sc_Line, message);
577 }
578 
579 
580 //
581 // CheckOpen
582 //
CheckOpen(void)583 static void CheckOpen(void)
584 {
585 	if (ScriptOpen == false)
586 	{
587 		I_FatalError ("SC_ call before SC_Open().");
588 	}
589 }
590 
591 VERSION_CONTROL (sc_man_cpp, "$Id: sc_man.cpp 4469 2014-01-03 23:38:29Z dr_sean $")
592