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