1 
2 //**************************************************************************
3 //**
4 //** sc_man.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile: sc_man.c,v $
7 //** $Revision: 1.3 $
8 //** $Date: 96/01/06 03:23:43 $
9 //** $Author: bgokey $
10 //**
11 //**************************************************************************
12 
13 // HEADER FILES ------------------------------------------------------------
14 
15 #include <string.h>
16 #include <stdlib.h>
17 #include "doomtype.h"
18 #include "i_system.h"
19 #include "sc_man.h"
20 #include "w_wad.h"
21 #include "cmdlib.h"
22 #include "m_misc.h"
23 #include "templates.h"
24 #include "doomstat.h"
25 #include "v_text.h"
26 
27 // MACROS ------------------------------------------------------------------
28 
29 // TYPES -------------------------------------------------------------------
30 
31 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
32 
33 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
34 
35 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
36 
37 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
38 
39 // PUBLIC DATA DEFINITIONS -------------------------------------------------
40 
41 // PRIVATE DATA DEFINITIONS ------------------------------------------------
42 
43 // CODE --------------------------------------------------------------------
44 
45 //==========================================================================
46 //
47 // FScanner Constructor
48 //
49 //==========================================================================
50 
FScanner()51 FScanner::FScanner()
52 {
53 	ScriptOpen = false;
54 }
55 
56 //==========================================================================
57 //
58 // FScanner Destructor
59 //
60 //==========================================================================
61 
~FScanner()62 FScanner::~FScanner()
63 {
64 	// Humm... Nothing to do in here.
65 }
66 
67 //==========================================================================
68 //
69 // FScanner Copy Constructor
70 //
71 //==========================================================================
72 
FScanner(const FScanner & other)73 FScanner::FScanner(const FScanner &other)
74 {
75 	ScriptOpen = false;
76 	*this = other;
77 }
78 
79 //==========================================================================
80 //
81 // FScanner OpenLumpNum Constructor
82 //
83 //==========================================================================
84 
FScanner(int lumpnum)85 FScanner::FScanner(int lumpnum)
86 {
87 	ScriptOpen = false;
88 	OpenLumpNum(lumpnum);
89 }
90 
91 //==========================================================================
92 //
93 // FScanner :: operator =
94 //
95 //==========================================================================
96 
operator =(const FScanner & other)97 FScanner &FScanner::operator=(const FScanner &other)
98 {
99 	if (this == &other)
100 	{
101 		return *this;
102 	}
103 	if (!other.ScriptOpen)
104 	{
105 		Close();
106 		return *this;
107 	}
108 
109 	// Copy protected members
110 	ScriptOpen = true;
111 	ScriptName = other.ScriptName;
112 	ScriptBuffer = other.ScriptBuffer;
113 	ScriptPtr = other.ScriptPtr;
114 	ScriptEndPtr = other.ScriptEndPtr;
115 	AlreadyGot = other.AlreadyGot;
116 	AlreadyGotLine = other.AlreadyGotLine;
117 	LastGotToken = other.LastGotToken;
118 	LastGotPtr = other.LastGotPtr;
119 	LastGotLine = other.LastGotLine;
120 	CMode = other.CMode;
121 	Escape = other.Escape;
122 
123 	// Copy public members
124 	if (other.String == other.StringBuffer)
125 	{
126 		memcpy(StringBuffer, other.StringBuffer, sizeof(StringBuffer));
127 		BigStringBuffer = "";
128 		String = StringBuffer;
129 	}
130 	else
131 	{
132 		// Past practice means the string buffer must be writeable, which
133 		// removes some of the benefit from using an FString to store
134 		// the big string buffer.
135 		BigStringBuffer = other.BigStringBuffer;
136 		String = BigStringBuffer.LockBuffer();
137 	}
138 	StringLen = other.StringLen;
139 	TokenType = other.TokenType;
140 	Number = other.Number;
141 	Float = other.Float;
142 	Name = other.Name;
143 	Line = other.Line;
144 	End = other.End;
145 	Crossed = other.Crossed;
146 
147 	return *this;
148 }
149 
150 //==========================================================================
151 //
152 // FScanner :: Open
153 //
154 //==========================================================================
155 
Open(const char * name)156 void FScanner::Open (const char *name)
157 {
158 	int lump = Wads.CheckNumForFullName(name, true);
159 	if (lump == -1)
160 	{
161 		I_Error("Could not find script lump '%s'\n", name);
162 	}
163 	OpenLumpNum(lump);
164 }
165 
166 //==========================================================================
167 //
168 // FScanner :: OpenFile
169 //
170 // Loads a script from a file. Uses new/delete for memory allocation.
171 //
172 //==========================================================================
173 
OpenFile(const char * name)174 void FScanner::OpenFile (const char *name)
175 {
176 	BYTE *filebuf;
177 	int filesize;
178 
179 	Close ();
180 	filesize = M_ReadFile (name, &filebuf);
181 	ScriptBuffer = FString((const char *)filebuf, filesize);
182 	delete[] filebuf;
183 	ScriptName = name;	// This is used for error messages so the full file name is preferable
184 	LumpNum = -1;
185 	PrepareScript ();
186 }
187 
188 //==========================================================================
189 //
190 // FScanner :: OpenMem
191 //
192 // Prepares a script that is already in memory for parsing. The memory is
193 // copied, so you can do whatever you want with it after opening it.
194 //
195 //==========================================================================
196 
OpenMem(const char * name,const char * buffer,int size)197 void FScanner::OpenMem (const char *name, const char *buffer, int size)
198 {
199 	OpenString(name, FString(buffer, size));
200 }
201 
202 //==========================================================================
203 //
204 // FScanner :: OpenString
205 //
206 // Like OpenMem, but takes a string directly.
207 //
208 //==========================================================================
209 
OpenString(const char * name,FString buffer)210 void FScanner::OpenString (const char *name, FString buffer)
211 {
212 	Close ();
213 	ScriptBuffer = buffer;
214 	ScriptName = name;
215 	LumpNum = -1;
216 	PrepareScript ();
217 }
218 
219 //==========================================================================
220 //
221 // FScanner :: OpenLumpNum
222 //
223 // Loads a script from the lump directory
224 //
225 //==========================================================================
226 
OpenLumpNum(int lump)227 void FScanner :: OpenLumpNum (int lump)
228 {
229 	Close ();
230 	{
231 		FMemLump mem = Wads.ReadLump(lump);
232 		ScriptBuffer = mem.GetString();
233 	}
234 	ScriptName = Wads.GetLumpFullPath(lump);
235 	LumpNum = lump;
236 	PrepareScript ();
237 }
238 
239 //==========================================================================
240 //
241 // FScanner :: PrepareScript
242 //
243 // Prepares a script for parsing.
244 //
245 //==========================================================================
246 
PrepareScript()247 void FScanner::PrepareScript ()
248 {
249 	// The scanner requires the file to end with a '\n', so add one if
250 	// it doesn't already.
251 	if (ScriptBuffer.Len() == 0 || ScriptBuffer[ScriptBuffer.Len() - 1] != '\n')
252 	{
253 		// If the last character in the buffer is a null character, change
254 		// it to a newline. Otherwise, append a newline to the end.
255 		if (ScriptBuffer.Len() > 0 && ScriptBuffer[ScriptBuffer.Len() - 1] == '\0')
256 		{
257 			ScriptBuffer.LockBuffer()[ScriptBuffer.Len() - 1] = '\n';
258 			ScriptBuffer.UnlockBuffer();
259 		}
260 		else
261 		{
262 			ScriptBuffer += '\n';
263 		}
264 	}
265 
266 	ScriptPtr = &ScriptBuffer[0];
267 	ScriptEndPtr = &ScriptBuffer[ScriptBuffer.Len()];
268 	Line = 1;
269 	End = false;
270 	ScriptOpen = true;
271 	String = StringBuffer;
272 	AlreadyGot = false;
273 	LastGotToken = false;
274 	LastGotPtr = NULL;
275 	LastGotLine = 1;
276 	CMode = false;
277 	Escape = true;
278 	StringBuffer[0] = '\0';
279 	BigStringBuffer = "";
280 }
281 
282 //==========================================================================
283 //
284 // FScanner :: Close
285 //
286 //==========================================================================
287 
Close()288 void FScanner::Close ()
289 {
290 	ScriptOpen = false;
291 	ScriptBuffer = "";
292 	BigStringBuffer = "";
293 	StringBuffer[0] = '\0';
294 	String = StringBuffer;
295 }
296 
297 //==========================================================================
298 //
299 // FScanner :: SavePos
300 //
301 // Saves the current script location for restoration later
302 //
303 //==========================================================================
304 
SavePos()305 const FScanner::SavedPos FScanner::SavePos ()
306 {
307 	SavedPos pos;
308 
309 	CheckOpen ();
310 	if (End)
311 	{
312 		pos.SavedScriptPtr = NULL;
313 	}
314 	else
315 	{
316 		pos.SavedScriptPtr = ScriptPtr;
317 	}
318 	pos.SavedScriptLine = Line;
319 	return pos;
320 }
321 
322 //==========================================================================
323 //
324 // FScanner :: RestorePos
325 //
326 // Restores the previously saved script location
327 //
328 //==========================================================================
329 
RestorePos(const FScanner::SavedPos & pos)330 void FScanner::RestorePos (const FScanner::SavedPos &pos)
331 {
332 	if (pos.SavedScriptPtr)
333 	{
334 		ScriptPtr = pos.SavedScriptPtr;
335 		Line = pos.SavedScriptLine;
336 		End = false;
337 	}
338 	else
339 	{
340 		End = true;
341 	}
342 	AlreadyGot = false;
343 	LastGotToken = false;
344 	Crossed = false;
345 }
346 
347 //==========================================================================
348 //
349 // FScanner :: isText
350 //
351 // Checks if this is a text file.
352 //
353 //==========================================================================
354 
isText()355 bool FScanner::isText()
356 {
357 	for(unsigned int i=0;i<ScriptBuffer.Len();i++)
358 	{
359 		int c = ScriptBuffer[i];
360 		if (c < ' ' && c != '\n' && c != '\r' && c != '\t') return false;
361 	}
362 	return true;
363 }
364 
365 //==========================================================================
366 //
367 // FScanner :: SetCMode
368 //
369 // Enables/disables C mode. In C mode, more characters are considered to
370 // be whole words than in non-C mode.
371 //
372 //==========================================================================
373 
SetCMode(bool cmode)374 void FScanner::SetCMode (bool cmode)
375 {
376 	CMode = cmode;
377 }
378 
379 //==========================================================================
380 //
381 // FScanner :: SetEscape
382 //
383 // Turns the escape sequence \" in strings on or off. If it's off, that
384 // means you can't include quotation marks inside strings.
385 //
386 //==========================================================================
387 
SetEscape(bool esc)388 void FScanner::SetEscape (bool esc)
389 {
390 	Escape = esc;
391 }
392 
393 //==========================================================================
394 //
395 // FScanner::ScanString
396 //
397 // Set tokens true if you want TokenType to be set.
398 //
399 //==========================================================================
400 
ScanString(bool tokens)401 bool FScanner::ScanString (bool tokens)
402 {
403 	const char *marker, *tok;
404 	bool return_val;
405 
406 	CheckOpen();
407 	if (AlreadyGot)
408 	{
409 		AlreadyGot = false;
410 		if (!tokens || LastGotToken)
411 		{
412 			return true;
413 		}
414 		ScriptPtr = LastGotPtr;
415 		Line = LastGotLine;
416 	}
417 
418 	Crossed = false;
419 	if (ScriptPtr >= ScriptEndPtr)
420 	{
421 		End = true;
422 		return false;
423 	}
424 
425 	LastGotPtr = ScriptPtr;
426 	LastGotLine = Line;
427 
428 	// In case the generated scanner does not use marker, avoid compiler warnings.
429 	marker;
430 #include "sc_man_scanner.h"
431 	LastGotToken = tokens;
432 	return return_val;
433 }
434 
435 //==========================================================================
436 //
437 // FScanner :: GetString
438 //
439 //==========================================================================
440 
GetString()441 bool FScanner::GetString ()
442 {
443 	return ScanString (false);
444 }
445 
446 //==========================================================================
447 //
448 // FScanner :: MustGetString
449 //
450 //==========================================================================
451 
MustGetString(void)452 void FScanner::MustGetString (void)
453 {
454 	if (FScanner::GetString() == false)
455 	{
456 		ScriptError ("Missing string (unexpected end of file).");
457 	}
458 }
459 
460 //==========================================================================
461 //
462 // FScanner :: MustGetStringName
463 //
464 //==========================================================================
465 
MustGetStringName(const char * name)466 void FScanner::MustGetStringName (const char *name)
467 {
468 	MustGetString ();
469 	if (Compare (name) == false)
470 	{
471 		ScriptError ("Expected '%s', got '%s'.", name, String);
472 	}
473 }
474 
475 //==========================================================================
476 //
477 // FScanner :: CheckString
478 //
479 // Checks if the next token matches the specified string. Returns true if
480 // it does. If it doesn't, it ungets it and returns false.
481 //
482 //==========================================================================
483 
CheckString(const char * name)484 bool FScanner::CheckString (const char *name)
485 {
486 	if (GetString ())
487 	{
488 		if (Compare (name))
489 		{
490 			return true;
491 		}
492 		UnGet ();
493 	}
494 	return false;
495 }
496 
497 //==========================================================================
498 //
499 // FScanner :: GetToken
500 //
501 // Sets sc_Float, sc_Number, and sc_Name based on sc_TokenType.
502 //
503 //==========================================================================
504 
GetToken()505 bool FScanner::GetToken ()
506 {
507 	if (ScanString (true))
508 	{
509 		if (TokenType == TK_NameConst)
510 		{
511 			Name = FName(String);
512 		}
513 		else if (TokenType == TK_IntConst)
514 		{
515 			char *stopper;
516 			Number = strtol(String, &stopper, 0);
517 			Float = Number;
518 		}
519 		else if (TokenType == TK_FloatConst)
520 		{
521 			char *stopper;
522 			Float = strtod(String, &stopper);
523 		}
524 		else if (TokenType == TK_StringConst)
525 		{
526 			StringLen = strbin(String);
527 		}
528 		return true;
529 	}
530 	return false;
531 }
532 
533 //==========================================================================
534 //
535 // FScanner :: MustGetAnyToken
536 //
537 //==========================================================================
538 
MustGetAnyToken(void)539 void FScanner::MustGetAnyToken (void)
540 {
541 	if (GetToken () == false)
542 	{
543 		ScriptError ("Missing token (unexpected end of file).");
544 	}
545 }
546 
547 //==========================================================================
548 //
549 // FScanner :: TokenMustBe
550 //
551 //==========================================================================
552 
TokenMustBe(int token)553 void FScanner::TokenMustBe (int token)
554 {
555 	if (TokenType != token)
556 	{
557 		FString tok1 = TokenName(token);
558 		FString tok2 = TokenName(TokenType, String);
559 		ScriptError ("Expected %s but got %s instead.", tok1.GetChars(), tok2.GetChars());
560 	}
561 }
562 
563 //==========================================================================
564 //
565 // FScanner :: MustGetToken
566 //
567 //==========================================================================
568 
MustGetToken(int token)569 void FScanner::MustGetToken (int token)
570 {
571 	MustGetAnyToken ();
572 	TokenMustBe(token);
573 }
574 
575 //==========================================================================
576 //
577 // FScanner :: CheckToken
578 //
579 // Checks if the next token matches the specified token. Returns true if
580 // it does. If it doesn't, it ungets it and returns false.
581 //
582 //==========================================================================
583 
CheckToken(int token)584 bool FScanner::CheckToken (int token)
585 {
586 	if (GetToken ())
587 	{
588 		if (TokenType == token)
589 		{
590 			return true;
591 		}
592 		UnGet ();
593 	}
594 	return false;
595 }
596 
597 //==========================================================================
598 //
599 // FScanner :: GetNumber
600 //
601 //==========================================================================
602 
GetNumber()603 bool FScanner::GetNumber ()
604 {
605 	char *stopper;
606 
607 	CheckOpen();
608 	if (GetString())
609 	{
610 		if (strcmp (String, "MAXINT") == 0)
611 		{
612 			Number = INT_MAX;
613 		}
614 		else
615 		{
616 			Number = strtol (String, &stopper, 0);
617 			if (*stopper != 0)
618 			{
619 				ScriptError ("SC_GetNumber: Bad numeric constant \"%s\".", String);
620 			}
621 		}
622 		Float = Number;
623 		return true;
624 	}
625 	else
626 	{
627 		return false;
628 	}
629 }
630 
631 //==========================================================================
632 //
633 // FScanner :: MustGetNumber
634 //
635 //==========================================================================
636 
MustGetNumber()637 void FScanner::MustGetNumber ()
638 {
639 	if (GetNumber() == false)
640 	{
641 		ScriptError ("Missing integer (unexpected end of file).");
642 	}
643 }
644 
645 //==========================================================================
646 //
647 // FScanner :: CheckNumber
648 //
649 // similar to GetNumber but ungets the token if it isn't a number
650 // and does not print an error
651 //
652 //==========================================================================
653 
CheckNumber()654 bool FScanner::CheckNumber ()
655 {
656 	char *stopper;
657 
658 	if (GetString())
659 	{
660 		if (String[0] == 0)
661 		{
662 			UnGet();
663 			return false;
664 		}
665 		else if (strcmp (String, "MAXINT") == 0)
666 		{
667 			Number = INT_MAX;
668 		}
669 		else
670 		{
671 			Number = strtol (String, &stopper, 0);
672 			if (*stopper != 0)
673 			{
674 				UnGet();
675 				return false;
676 			}
677 		}
678 		Float = Number;
679 		return true;
680 	}
681 	else
682 	{
683 		return false;
684 	}
685 }
686 
687 //==========================================================================
688 //
689 // FScanner :: CheckFloat
690 //
691 // [GRB] Same as SC_CheckNumber, only for floats
692 //
693 //==========================================================================
694 
CheckFloat()695 bool FScanner::CheckFloat ()
696 {
697 	char *stopper;
698 
699 	if (GetString())
700 	{
701 		if (String[0] == 0)
702 		{
703 			UnGet();
704 			return false;
705 		}
706 
707 		Float = strtod (String, &stopper);
708 		if (*stopper != 0)
709 		{
710 			UnGet();
711 			return false;
712 		}
713 		return true;
714 	}
715 	else
716 	{
717 		return false;
718 	}
719 }
720 
721 
722 //==========================================================================
723 //
724 // FScanner :: GetFloat
725 //
726 //==========================================================================
727 
GetFloat()728 bool FScanner::GetFloat ()
729 {
730 	char *stopper;
731 
732 	CheckOpen ();
733 	if (GetString())
734 	{
735 		Float = strtod (String, &stopper);
736 		if (*stopper != 0)
737 		{
738 			ScriptError ("SC_GetFloat: Bad numeric constant \"%s\".", String);
739 		}
740 		Number = (int)Float;
741 		return true;
742 	}
743 	else
744 	{
745 		return false;
746 	}
747 }
748 
749 //==========================================================================
750 //
751 // FScanner :: MustGetFloat
752 //
753 //==========================================================================
754 
MustGetFloat()755 void FScanner::MustGetFloat ()
756 {
757 	if (GetFloat() == false)
758 	{
759 		ScriptError ("Missing floating-point number (unexpected end of file).");
760 	}
761 }
762 
763 //==========================================================================
764 //
765 // FScanner :: UnGet
766 //
767 // Assumes there is a valid string in String.
768 //
769 //==========================================================================
770 
UnGet()771 void FScanner::UnGet ()
772 {
773 	AlreadyGot = true;
774 	AlreadyGotLine = LastGotLine;	// in case of an error we want the line of the last token.
775 }
776 
777 //==========================================================================
778 //
779 // FScanner :: MatchString
780 //
781 // Returns the index of the first match to String from the passed
782 // array of strings, or -1 if not found.
783 //
784 //==========================================================================
785 
MatchString(const char * const * strings,size_t stride)786 int FScanner::MatchString (const char * const *strings, size_t stride)
787 {
788 	int i;
789 
790 	assert(stride % sizeof(const char*) == 0);
791 
792 	stride /= sizeof(const char*);
793 
794 	for (i = 0; *strings != NULL; i++)
795 	{
796 		if (Compare (*strings))
797 		{
798 			return i;
799 		}
800 		strings += stride;
801 	}
802 	return -1;
803 }
804 
805 //==========================================================================
806 //
807 // FScanner :: MustMatchString
808 //
809 //==========================================================================
810 
MustMatchString(const char * const * strings,size_t stride)811 int FScanner::MustMatchString (const char * const *strings, size_t stride)
812 {
813 	int i;
814 
815 	i = MatchString (strings, stride);
816 	if (i == -1)
817 	{
818 		ScriptError (NULL);
819 	}
820 	return i;
821 }
822 
823 //==========================================================================
824 //
825 // FScanner :: Compare
826 //
827 //==========================================================================
828 
Compare(const char * text)829 bool FScanner::Compare (const char *text)
830 {
831 	return (stricmp (text, String) == 0);
832 }
833 
834 //==========================================================================
835 //
836 // FScanner :: TokenName
837 //
838 // Returns the name of a token.
839 //
840 //==========================================================================
841 
TokenName(int token,const char * string)842 FString FScanner::TokenName (int token, const char *string)
843 {
844 	static const char *const names[] =
845 	{
846 #define xx(sym,str)		str,
847 #include "sc_man_tokens.h"
848 	};
849 
850 	FString work;
851 
852 	if (token > ' ' && token < 256)
853 	{
854 		work = '\'';
855 		work += token;
856 		work += '\'';
857 	}
858 	else if (token >= TK_Identifier && token < TK_LastToken)
859 	{
860 		work = names[token - TK_Identifier];
861 		if (string != NULL && token >= TK_Identifier && token <= TK_FloatConst)
862 		{
863 			work += ' ';
864 			char quote = (token == TK_StringConst) ? '"' : '\'';
865 			work += quote;
866 			work += string;
867 			work += quote;
868 		}
869 	}
870 	else
871 	{
872 		FString work;
873 		work.Format ("Unknown(%d)", token);
874 		return work;
875 	}
876 	return work;
877 }
878 
879 //==========================================================================
880 //
881 // FScanner::ScriptError
882 //
883 //==========================================================================
884 
GetMessageLine()885 int FScanner::GetMessageLine()
886 {
887 	return AlreadyGot? AlreadyGotLine : Line;
888 }
889 
890 //==========================================================================
891 //
892 // FScanner::ScriptError
893 //
894 //==========================================================================
895 
ScriptError(const char * message,...)896 void STACK_ARGS FScanner::ScriptError (const char *message, ...)
897 {
898 	FString composed;
899 
900 	if (message == NULL)
901 	{
902 		composed = "Bad syntax.";
903 	}
904 	else
905 	{
906 		va_list arglist;
907 		va_start (arglist, message);
908 		composed.VFormat (message, arglist);
909 		va_end (arglist);
910 	}
911 
912 	I_Error ("Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(),
913 		AlreadyGot? AlreadyGotLine : Line, composed.GetChars());
914 }
915 
916 //==========================================================================
917 //
918 // FScanner::ScriptMessage
919 //
920 //==========================================================================
921 
ScriptMessage(const char * message,...)922 void STACK_ARGS FScanner::ScriptMessage (const char *message, ...)
923 {
924 	FString composed;
925 
926 	if (message == NULL)
927 	{
928 		composed = "Bad syntax.";
929 	}
930 	else
931 	{
932 		va_list arglist;
933 		va_start (arglist, message);
934 		composed.VFormat (message, arglist);
935 		va_end (arglist);
936 	}
937 
938 	Printf (TEXTCOLOR_RED "Script error, \"%s\" line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(),
939 		AlreadyGot? AlreadyGotLine : Line, composed.GetChars());
940 }
941 
942 //==========================================================================
943 //
944 // FScanner :: CheckOpen
945 //
946 //==========================================================================
947 
CheckOpen()948 void FScanner::CheckOpen()
949 {
950 	if (ScriptOpen == false)
951 	{
952 		I_FatalError ("SC_ call before SC_Open().");
953 	}
954 }
955 
956 //==========================================================================
957 //
958 // a class that remembers a parser position
959 //
960 //==========================================================================
961 int FScriptPosition::ErrorCounter;
962 
FScriptPosition(const FScriptPosition & other)963 FScriptPosition::FScriptPosition(const FScriptPosition &other)
964 {
965 	FileName = other.FileName;
966 	ScriptLine = other.ScriptLine;
967 }
968 
FScriptPosition(FString fname,int line)969 FScriptPosition::FScriptPosition(FString fname, int line)
970 {
971 	FileName = fname;
972 	ScriptLine = line;
973 }
974 
FScriptPosition(FScanner & sc)975 FScriptPosition::FScriptPosition(FScanner &sc)
976 {
977 	FileName = sc.ScriptName;
978 	ScriptLine = sc.GetMessageLine();
979 }
980 
operator =(const FScriptPosition & other)981 FScriptPosition &FScriptPosition::operator=(const FScriptPosition &other)
982 {
983 	FileName = other.FileName;
984 	ScriptLine = other.ScriptLine;
985 	return *this;
986 }
987 
988 //==========================================================================
989 //
990 // FScriptPosition::Message
991 //
992 //==========================================================================
993 
Message(int severity,const char * message,...) const994 void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ...) const
995 {
996 	FString composed;
997 
998 	if ((severity == MSG_DEBUG || severity == MSG_DEBUGLOG) && !developer) return;
999 
1000 	if (message == NULL)
1001 	{
1002 		composed = "Bad syntax.";
1003 	}
1004 	else
1005 	{
1006 		va_list arglist;
1007 		va_start (arglist, message);
1008 		composed.VFormat (message, arglist);
1009 		va_end (arglist);
1010 	}
1011 	const char *type = "";
1012 	const char *color;
1013 	int level = PRINT_HIGH;
1014 
1015 	switch (severity)
1016 	{
1017 	default:
1018 		return;
1019 
1020 	case MSG_WARNING:
1021 		type = "warning";
1022 		color = TEXTCOLOR_YELLOW;
1023 		break;
1024 
1025 	case MSG_ERROR:
1026 		ErrorCounter++;
1027 		type = "error";
1028 		color = TEXTCOLOR_RED;
1029 		break;
1030 
1031 	case MSG_MESSAGE:
1032 	case MSG_DEBUG:
1033 		type = "message";
1034 		color = TEXTCOLOR_GREEN;
1035 		break;
1036 
1037 	case MSG_DEBUGLOG:
1038 	case MSG_LOG:
1039 		type = "message";
1040 		level = PRINT_LOG;
1041 		color = "";
1042 		break;
1043 
1044 	case MSG_FATAL:
1045 		I_Error ("Script error, \"%s\" line %d:\n%s\n",
1046 			FileName.GetChars(), ScriptLine, composed.GetChars());
1047 		return;
1048 	}
1049 	Printf (level, "%sScript %s, \"%s\" line %d:\n%s%s\n",
1050 		color, type, FileName.GetChars(), ScriptLine, color, composed.GetChars());
1051 }
1052 
1053 
1054