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