engine: reject mbf21 and shit24 wads. there is no way to know if it is safe to ignore...
[k8vavoom.git] / source / utils / scripts.cpp
blobd176b9ca9d9269b2909cec1f0dd844b4b09a34e8
1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
12 //**
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
16 //**
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
21 //**
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
24 //**
25 //**************************************************************************
26 #if !defined(VCC_STANDALONE_EXECUTOR)
27 # include "gamedefs.h"
28 # include "language.h"
29 # include "filesys/files.h"
30 #elif defined(VCC_STANDALONE_EXECUTOR)
31 # include "../../vccrun/vcc_run_vc.h"
32 # include "../../libs/vavoomc/vc_public.h"
33 # include "scripts.h"
34 #endif
36 #if !defined(VCC_STANDALONE_EXECUTOR)
37 static VCvarB dbg_show_name_remap("dbg_show_name_remap", false, "Show hacky name remapping", CVAR_PreInit|CVAR_NoShadow);
38 #endif
41 // ////////////////////////////////////////////////////////////////////////// //
42 class VScriptsParser : public VObject {
43 DECLARE_CLASS(VScriptsParser, VObject, 0)
44 NO_DEFAULT_CONSTRUCTOR(VScriptsParser)
46 VScriptParser *Int;
48 virtual void Destroy () override;
49 void CheckInterface ();
51 #if !defined(VCC_STANDALONE_EXECUTOR)
52 DECLARE_FUNCTION(OpenLumpName)
53 DECLARE_FUNCTION(OpenLumpIndex)
54 #endif
55 DECLARE_FUNCTION(OpenLumpFullName)
56 DECLARE_FUNCTION(OpenString)
57 DECLARE_FUNCTION(get_String)
58 DECLARE_FUNCTION(get_Number)
59 DECLARE_FUNCTION(get_Float)
60 DECLARE_FUNCTION(get_Crossed)
61 DECLARE_FUNCTION(get_Quoted)
62 DECLARE_FUNCTION(get_SourceLump)
63 DECLARE_FUNCTION(set_SourceLump)
64 DECLARE_FUNCTION(get_Escape)
65 DECLARE_FUNCTION(set_Escape)
66 DECLARE_FUNCTION(get_CMode)
67 DECLARE_FUNCTION(set_CMode)
68 DECLARE_FUNCTION(get_AllowNumSign)
69 DECLARE_FUNCTION(set_AllowNumSign)
70 DECLARE_FUNCTION(get_EDGEMode)
71 DECLARE_FUNCTION(set_EDGEMode)
72 DECLARE_FUNCTION(get_EndOfText)
73 DECLARE_FUNCTION(get_SemicolonComments)
74 DECLARE_FUNCTION(set_SemicolonComments)
75 DECLARE_FUNCTION(get_HashComments)
76 DECLARE_FUNCTION(set_HashComments)
77 DECLARE_FUNCTION(IsText)
78 DECLARE_FUNCTION(IsAtEol)
79 DECLARE_FUNCTION(IsCMode)
80 DECLARE_FUNCTION(IsAllowNumSign)
81 DECLARE_FUNCTION(SetCMode)
82 DECLARE_FUNCTION(SetAllowNumSign)
83 DECLARE_FUNCTION(IsEscape)
84 DECLARE_FUNCTION(SetEscape)
85 DECLARE_FUNCTION(AtEnd)
86 DECLARE_FUNCTION(GetString)
87 #if !defined(VCC_STANDALONE_EXECUTOR)
88 DECLARE_FUNCTION(ExpectColor)
89 #endif
90 DECLARE_FUNCTION(ExpectString)
91 DECLARE_FUNCTION(ExpectLoneChar)
92 DECLARE_FUNCTION(Check)
93 DECLARE_FUNCTION(CheckStartsWith)
94 DECLARE_FUNCTION(Expect)
95 DECLARE_FUNCTION(CheckIdentifier)
96 DECLARE_FUNCTION(ExpectIdentifier)
97 DECLARE_FUNCTION(CheckNumber)
98 DECLARE_FUNCTION(ExpectNumber)
99 DECLARE_FUNCTION(CheckFloat)
100 DECLARE_FUNCTION(ExpectFloat)
101 DECLARE_FUNCTION(ResetQuoted)
102 DECLARE_FUNCTION(ResetCrossed)
103 DECLARE_FUNCTION(SkipBracketed)
104 DECLARE_FUNCTION(UnGet)
105 DECLARE_FUNCTION(SkipLine)
106 DECLARE_FUNCTION(FileName)
107 DECLARE_FUNCTION(CurrLine)
108 DECLARE_FUNCTION(TokenLine)
109 DECLARE_FUNCTION(ScriptError)
110 DECLARE_FUNCTION(ScriptMessage)
112 DECLARE_FUNCTION(SavePos)
113 DECLARE_FUNCTION(RestorePos)
115 #if !defined(VCC_STANDALONE_EXECUTOR)
116 DECLARE_FUNCTION(FindRelativeIncludeLump)
117 DECLARE_FUNCTION(FindIncludeLump)
118 #endif
121 IMPLEMENT_CLASS(V, ScriptsParser)
124 static uint32_t c2spec[256/32]; // c-like two-chars specials
125 static uint32_t cidterm[256/32]; // c-like identifier terminator
126 static uint32_t cnumterm[256/32]; // c-like number terminator
127 static uint32_t ncidterm[256/32]; // non-c-like identifier terminator
129 struct CharClassifier {
130 static VVA_FORCEINLINE bool isC2Spec (char ch) noexcept { return (c2spec[(ch>>5)&0x07]&(1U<<(ch&0x1f))); }
131 static VVA_FORCEINLINE bool isCIdTerm (char ch) noexcept { return (cidterm[(ch>>5)&0x07]&(1U<<(ch&0x1f))); }
132 static VVA_FORCEINLINE bool isCNumTerm (char ch) noexcept { return (cnumterm[(ch>>5)&0x07]&(1U<<(ch&0x1f))); }
133 static VVA_FORCEINLINE bool isNCIdTerm (char ch, bool hashCmt) noexcept { return (ncidterm[(ch>>5)&0x07]&(1U<<(ch&0x1f))) || (hashCmt && ch == '#'); }
135 static VVA_FORCEINLINE void setCharBit (vuint32 *set, char ch) noexcept { set[(ch>>5)&0x07] |= (1U<<(ch&0x1f)); }
137 static VVA_FORCEINLINE bool isDigit (char ch) noexcept { return (ch >= '0' && ch <= '9'); }
139 static inline bool isNumStart (const char *s, bool allowNumSign) noexcept {
140 if (allowNumSign) if (*s == '+' || *s == '-') ++s;
141 if (*s == '.') ++s;
142 return isDigit(*s);
145 CharClassifier () noexcept {
146 /*static*/ const char *cIdTerm = "`~!#$%^&*(){}[]/=\\?-+|;:<>,\"'"; // was with '@'
147 /*static*/ const char *ncIdTerm = "{}|=,;\"'";
148 /*static*/ const char *c2specStr = "=!<>+-*/%&|^~";
149 memset(c2spec, 0, sizeof(cidterm));
150 memset(cidterm, 0, sizeof(cidterm));
151 memset(cnumterm, 0, sizeof(cnumterm));
152 memset(ncidterm, 0, sizeof(ncidterm));
153 for (const char *s = c2specStr; *s; ++s) {
154 setCharBit(c2spec, *s);
156 for (const char *s = cIdTerm; *s; ++s) {
157 setCharBit(cidterm, *s);
158 setCharBit(cnumterm, *s);
160 for (const char *s = ncIdTerm; *s; ++s) setCharBit(ncidterm, *s);
161 // blanks will terminate too
162 for (int ch = 0; ch <= 32; ++ch) {
163 setCharBit(cidterm, ch);
164 setCharBit(cnumterm, ch);
165 setCharBit(ncidterm, ch);
167 // c identified is terminated with dot
168 setCharBit(cidterm, '.');
169 // sanity check
170 for (int f = 0; f < 256; ++f) {
171 if (f <= 32 || f == '.' || strchr(cIdTerm, f)) {
172 vassert(isCIdTerm(f));
173 if (f == '.') { vassert(!isCNumTerm(f)); } else { vassert(isCNumTerm(f)); }
174 } else {
175 vassert(!isCIdTerm(f));
176 vassert(!isCNumTerm(f));
182 CharClassifier charClassifierInit;
186 //==========================================================================
188 // VScriptSavedPos::saveFrom
190 //==========================================================================
191 void VScriptSavedPos::saveFrom (const VScriptParser &par) noexcept {
192 Line = par.Line;
193 TokLine = par.TokLine;
194 String = par.String;
195 Name8 = par.Name8;
196 Name = par.Name;
197 Number = par.Number;
198 Float = par.Float;
200 ScriptPtr = par.ScriptPtr;
201 TokStartPtr = par.TokStartPtr;
202 TokStartLine = par.TokStartLine;
203 flags =
204 (par.CMode ? Flag_CMode : Flag_None)|
205 (par.Escape ? Flag_Escape : Flag_None)|
206 (par.AllowNumSign ? Flag_AllowNumSign : Flag_None)|
207 (par.EDGEMode ? Flag_EDGEMode : Flag_None)|
208 (par.SemiComments ? Flag_SemiComments : Flag_None)|
209 (par.HashComments ? Flag_HashComments : Flag_None)|
211 (par.End ? Flag_End : Flag_None)|
212 (par.Crossed ? Flag_Crossed : Flag_None)|
213 (par.QuotedString ? Flag_QuotedString : Flag_None)|
218 //==========================================================================
220 // VScriptSavedPos::restoreTo
222 //==========================================================================
223 void VScriptSavedPos::restoreTo (VScriptParser &par) const noexcept {
224 par.Line = Line;
225 par.TokLine = TokLine;
226 par.String = String;
227 par.Name8 = Name8;
228 par.Name = Name;
229 par.Number = Number;
230 par.Float = Float;
232 par.ScriptPtr = ScriptPtr;
233 par.TokStartPtr = TokStartPtr;
234 par.TokStartLine = TokStartLine;
236 par.CMode = !!(flags&Flag_CMode);
237 par.Escape = !!(flags&Flag_Escape);
238 par.AllowNumSign = !!(flags&Flag_AllowNumSign);
239 par.EDGEMode = !!(flags&Flag_EDGEMode);
240 par.SemiComments = !!(flags&Flag_SemiComments);
241 par.HashComments = !!(flags&Flag_HashComments);
242 par.End = !!(flags&Flag_End);
243 par.Crossed = !!(flags&Flag_Crossed);
244 par.QuotedString = !!(flags&Flag_QuotedString);
249 //==========================================================================
251 // VScriptParser::VScriptParser
253 //==========================================================================
254 VScriptParser::VScriptParser (VStr name, VStream *Strm, int aSourceLump)
255 : Line(1)
256 , TokLine(1)
257 , End(false)
258 , Crossed(false)
259 , QuotedString(false)
260 , ScriptName(name.cloneUniqueMT())
261 , SrcIdx(-1)
262 , CMode(false)
263 , Escape(true)
264 , AllowNumSign(false)
265 , EDGEMode(false)
266 , SemiComments(false)
267 , HashComments(false)
268 , SourceLump(aSourceLump)
270 if (!Strm) {
271 ScriptSize = 1;
272 ScriptBuffer = new char[ScriptSize+1];
273 ScriptBuffer[0] = '\n';
274 ScriptBuffer[1] = 0;
275 } else {
276 try {
277 if (Strm->IsError()) Host_Error("cannot read definition file '%s:%s'", *name, *Strm->GetName());
278 ScriptSize = Strm->TotalSize();
279 if (Strm->IsError()) Host_Error("cannot read definition file '%s:%s'", *name, *Strm->GetName());
280 ScriptBuffer = new char[ScriptSize+1];
281 Strm->Serialise(ScriptBuffer, ScriptSize);
282 ScriptBuffer[ScriptSize] = 0;
283 if (Strm->IsError()) { delete ScriptBuffer; Host_Error("cannot read definition file '%s:%s'", *name, *Strm->GetName()); }
284 } catch (...) {
285 VStream::Destroy(Strm);
286 throw;
288 VStream::Destroy(Strm);
291 ScriptPtr = ScriptBuffer;
292 ScriptEndPtr = ScriptPtr+ScriptSize;
294 TokStartPtr = ScriptPtr;
295 TokStartLine = Line;
297 // skip garbage some editors add in the begining of UTF-8 files
298 if (*(const vuint8 *)ScriptPtr == 0xef && *(const vuint8 *)(ScriptPtr+1) == 0xbb && *(const vuint8 *)(ScriptPtr+2) == 0xbf) ScriptPtr += 3;
302 //==========================================================================
304 // VScriptParser::VScriptParser
306 //==========================================================================
307 VScriptParser::VScriptParser (VStr name, const char *atext, int aSourceLump) noexcept
308 : Line(1)
309 , TokLine(1)
310 , End(false)
311 , Crossed(false)
312 , QuotedString(false)
313 , ScriptName(name.cloneUniqueMT())
314 , SrcIdx(-1)
315 , CMode(false)
316 , Escape(true)
317 , AllowNumSign(false)
318 , EDGEMode(false)
319 , SemiComments(false)
320 , HashComments(false)
321 , SourceLump(aSourceLump)
323 if (atext && atext[0]) {
324 ScriptSize = (int)strlen(atext);
325 ScriptBuffer = new char[ScriptSize+1];
326 if (ScriptSize) memcpy(ScriptBuffer, atext, ScriptSize);
327 ScriptBuffer[ScriptSize] = 0;
328 } else {
329 ScriptSize = 1;
330 ScriptBuffer = new char[ScriptSize+1];
331 ScriptBuffer[0] = 0;
334 ScriptPtr = ScriptBuffer;
335 ScriptEndPtr = ScriptPtr+ScriptSize;
337 TokStartPtr = ScriptPtr;
338 TokStartLine = Line;
340 // skip garbage some editors add in the begining of UTF-8 files
341 if (*(const vuint8 *)ScriptPtr == 0xef && *(const vuint8 *)(ScriptPtr+1) == 0xbb && *(const vuint8 *)(ScriptPtr+2) == 0xbf) ScriptPtr += 3;
345 #if !defined(VCC_STANDALONE_EXECUTOR)
346 //==========================================================================
348 // VScriptParser::NewWithLump
350 //==========================================================================
351 VScriptParser *VScriptParser::NewWithLump (int Lump) {
352 if (Lump < 0) return new VScriptParser("{nullfile}", "");
353 VStream *st = W_CreateLumpReaderNum(Lump);
354 if (!st) return new VScriptParser("{nullfile}", "");
355 return new VScriptParser(W_FullLumpName(Lump), st, Lump);
357 #endif
360 //==========================================================================
362 // VScriptParser::~VScriptParser
364 //==========================================================================
365 VScriptParser::~VScriptParser () noexcept {
366 delete[] ScriptBuffer;
367 ScriptBuffer = nullptr;
371 //==========================================================================
373 // VScriptParser::clone
375 //==========================================================================
376 VScriptParser *VScriptParser::clone () const noexcept {
377 VScriptParser *res = new VScriptParser();
379 res->ScriptBuffer = new char[ScriptSize+1];
380 if (ScriptSize) memcpy(res->ScriptBuffer, ScriptBuffer, ScriptSize);
381 res->ScriptBuffer[ScriptSize] = 0;
383 res->ScriptPtr = res->ScriptBuffer+(ScriptPtr-ScriptBuffer);
384 res->ScriptEndPtr = res->ScriptBuffer+(ScriptEndPtr-ScriptBuffer);
386 res->TokStartPtr = res->ScriptBuffer+(TokStartPtr-ScriptBuffer);
387 res->TokStartLine = res->TokStartLine;
389 res->Line = Line;
390 res->TokLine = TokLine;
391 res->End = End;
392 res->Crossed = Crossed;
393 res->QuotedString = QuotedString;
394 res->String = String;
395 res->Name8 = Name8;
396 res->Name = Name;
397 res->Number = Number;
398 res->Float = Float;
400 res->ScriptName = ScriptName.cloneUniqueMT();
401 res->ScriptSize = ScriptSize;
402 res->CMode = CMode;
403 res->Escape = Escape;
404 res->AllowNumSign = AllowNumSign;
405 res->EDGEMode = EDGEMode;
406 res->SemiComments = SemiComments;
407 res->HashComments = HashComments;
408 res->SourceLump = SourceLump;
410 return res;
414 //==========================================================================
416 // VScriptParser::IsText
418 //==========================================================================
419 bool VScriptParser::IsText () noexcept {
420 int i = 0;
421 while (i < ScriptSize) {
422 vuint8 ch = *(const vuint8 *)(ScriptBuffer+(i++));
423 if (ch == 127) return false;
424 if (ch < ' ' && ch != '\n' && ch != '\r' && ch != '\t') return false;
425 if (ch < 128) continue;
426 // utf8 check
427 int cnt, val;
428 if ((ch&0xe0) == 0xc0) { val = ch&0x1f; cnt = 1; }
429 else if ((ch&0xf0) == 0xe0) { val = ch&0x0f; cnt = 2; }
430 else if ((ch&0xf8) == 0xf0) { val = ch&0x07; cnt = 3; }
431 else return false; // invalid utf8
432 do {
433 if (i >= ScriptSize) return false;
434 ch = ScriptBuffer[i++];
435 if ((ch&0xc0) != 0x80) return false; // invalid utf8
436 val = (val<<6)|(ch&0x3f);
437 } while (--cnt);
438 // check for valid codepoint
439 if (!(val < 0xD800 || (val > 0xDFFF && val <= 0x10FFFF))) return false; // invalid codepoint
441 return true;
445 //==========================================================================
447 // VScriptParser::AtEnd
449 //==========================================================================
450 bool VScriptParser::AtEnd () noexcept {
451 if (GetString()) {
452 //fprintf(stderr, "<%s>\n", *String);
453 UnGet();
454 return false;
456 return true;
460 //==========================================================================
462 // VScriptParser::IsAtEol
464 //==========================================================================
465 bool VScriptParser::IsAtEol () noexcept {
466 int commentLevel = 0;
467 for (const char *s = ScriptPtr; s < ScriptEndPtr; ++s) {
468 const vuint8 ch = *(const vuint8 *)s;
469 if (ch == '\r' && s[1] == '\n') return true;
470 if (ch == '\n') return true;
471 if (!commentLevel) {
472 if ((!CMode || SemiComments) && ch == ';') return true; // this is single-line comment, it always ends with EOL
473 if (HashComments && ch == '#') return true; // this is single-line comment, it always ends with EOL
474 const char c1 = s[1];
475 if (ch == '/' && c1 == '/') return true; // this is single-line comment, it always ends with EOL
476 if (ch == '/' && c1 == '*') {
477 // multiline comment
478 ++s; // skip slash
479 commentLevel = -1;
480 continue;
482 if (ch == '/' && c1 == '+') {
483 // multiline comment
484 ++s; // skip slash
485 commentLevel = 1;
486 continue;
488 if (ch > ' ') return false;
489 } else {
490 // in multiline comment
491 const char c1 = s[1];
492 if (commentLevel < 0) {
493 if (ch == '*' && c1 == '/') {
494 ++s; // skip star
495 commentLevel = 0;
497 } else {
498 if (ch == '/' && c1 == '+') {
499 ++s; // skip slash
500 ++commentLevel;
501 } else if (ch == '+' && c1 == '/') {
502 ++s; // skip plus
503 --commentLevel;
508 return true;
512 //==========================================================================
514 // VScriptParser::SkipComments
516 // this is moved out of `SkipBlanks()`, so i can use it in `SkipLine()`
518 //==========================================================================
519 void VScriptParser::SkipComments (bool changeFlags) noexcept {
520 while (ScriptPtr < ScriptEndPtr) {
521 const char c0 = *ScriptPtr;
522 const char c1 = (ScriptPtr+1 < ScriptEndPtr ? ScriptPtr[1] : 0);
523 // single-line comment?
524 if (((!CMode || SemiComments) && c0 == ';') || (c0 == '/' && c1 == '/') ||
525 (HashComments && c0 == '#'))
527 while (*ScriptPtr++ != '\n') if (ScriptPtr >= ScriptEndPtr) break;
528 if (changeFlags) { ++Line; Crossed = true; }
529 continue;
531 // multiline comment?
532 if (c0 == '/' && c1 == '*') {
533 ScriptPtr += 2;
534 while (ScriptPtr < ScriptEndPtr) {
535 if (ScriptPtr[0] == '*' && ScriptPtr[1] == '/') { ScriptPtr += 2; break; }
536 // check for new-line character
537 if (changeFlags && *ScriptPtr == '\n') { ++Line; Crossed = true; }
538 ++ScriptPtr;
540 continue;
542 // multiline nesting comment?
543 if (c0 == '/' && c1 == '+') {
544 int level = 1;
545 ScriptPtr += 2;
546 while (ScriptPtr < ScriptEndPtr) {
547 if (ScriptPtr[0] == '/' && ScriptPtr[1] == '+') { ScriptPtr += 2; ++level; continue; }
548 if (ScriptPtr[0] == '+' && ScriptPtr[1] == '/') {
549 ScriptPtr += 2;
550 if (--level == 0) break;
551 continue;
553 // check for new-line character
554 if (changeFlags && *ScriptPtr == '\n') { ++Line; Crossed = true; }
555 ++ScriptPtr;
557 continue;
559 // not a comment, stop skipping
560 break;
562 if (ScriptPtr >= ScriptEndPtr) {
563 ScriptPtr = ScriptEndPtr;
564 if (changeFlags) End = true;
569 //==========================================================================
571 // VScriptParser::SkipBlanks
573 //==========================================================================
574 void VScriptParser::SkipBlanks (bool changeFlags) noexcept {
575 while (ScriptPtr < ScriptEndPtr) {
576 SkipComments(changeFlags);
577 if (*(const vuint8 *)ScriptPtr <= ' ') {
578 if (changeFlags && *ScriptPtr == '\n') { ++Line; Crossed = true; }
579 ++ScriptPtr;
580 continue;
582 break;
584 if (ScriptPtr >= ScriptEndPtr) {
585 ScriptPtr = ScriptEndPtr;
586 if (changeFlags) End = true;
591 //==========================================================================
593 // VScriptParser::PeekChar
595 //==========================================================================
596 char VScriptParser::PeekOrSkipChar (bool doSkip) noexcept {
597 char res = 0;
598 char *oldSPtr = ScriptPtr;
599 int oldLine = Line;
600 bool oldCross = Crossed;
601 bool oldEnd = End;
602 SkipBlanks(true); // change flags
603 if (ScriptPtr < ScriptEndPtr) {
604 res = *ScriptPtr;
605 if (doSkip) ++ScriptPtr;
607 if (!doSkip) {
608 ScriptPtr = oldSPtr;
609 Line = oldLine;
610 Crossed = oldCross;
611 End = oldEnd;
613 return res;
617 //==========================================================================
619 // VScriptParser::ParseQuotedString
621 // starting quite is eaten
623 //==========================================================================
624 void VScriptParser::ParseQuotedString (const char qch) noexcept {
625 while (ScriptPtr < ScriptEndPtr) {
626 char ch = *ScriptPtr++;
627 // quote char?
628 if (ch == qch) {
629 if (!CMode) break;
630 // double quote is string continuation in C mode
631 if (*ScriptPtr != qch) break;
632 // check next char
633 if ((vuint8)ScriptPtr[1] < ' ') break;
634 ++ScriptPtr; // skip quote char
635 continue;
637 // newline?
638 if (ch == '\n' || ch == '\r') {
639 // convert from DOS format to UNIX format
640 if (ch == '\r' && *ScriptPtr == '\n') ++ScriptPtr;
641 ch = '\n';
642 if (CMode) {
643 /*if (String.length() == 0)*/ Error("Unterminated string constant");
644 } else {
645 String += ch;
647 ++Line;
648 Crossed = true;
649 continue;
651 // escape?
652 if (Escape && ch == '\\' && ScriptPtr[0]) {
653 const char c1 = *ScriptPtr++;
654 // continuation?
655 if (c1 == '\n' || c1 == '\r') {
656 ++Line;
657 Crossed = true;
658 if (c1 == '\r' && *ScriptPtr == '\n') ++ScriptPtr;
659 continue;
661 if (CMode) {
662 // c-mode escape
663 bool okescape = true;
664 switch (c1) {
665 case 'r': ch = '\r'; break;
666 case 'n': ch = '\n'; break;
667 case 'c': case 'C': ch = TEXT_COLOR_ESCAPE; break;
668 case 'e': ch = '\x1b'; break;
669 case '\t': ch = '\t'; break;
670 case '"': case '\'': case ' ': case '\\': case '`': ch = c1; break;
671 case 'x':
672 if (VStr::digitInBase(*ScriptPtr, 16) < 0) {
673 okescape = false;
674 } else {
675 int n0 = VStr::digitInBase(*ScriptPtr++, 16);
676 int n1 = VStr::digitInBase(*ScriptPtr, 16);
677 if (n1 >= 0) { n0 = n0*16+n1; ++ScriptPtr; }
678 if (!n0) n0 = 32;
679 ch = n0;
681 break;
682 default: okescape = false; break;
684 String += ch;
685 if (!okescape) String += c1;
686 } else {
687 // non-c-mode escape
688 bool okescape = true;
689 switch (c1) {
690 case 'r': ch = '\r'; break;
691 case 'n': ch = '\n'; break;
692 case 'c': case 'C': ch = TEXT_COLOR_ESCAPE; break;
693 case '\\': case '\"': case '\'': case '`': ch = c1; break;
694 default: okescape = false; break;
696 String += ch;
697 if (!okescape) {
698 String += c1;
699 } else {
700 // escaped eol and eol == one eol
701 if (ch == '\r' || ch == '\n') {
702 if (*ScriptPtr == '\n') {
703 ++Line;
704 Crossed = true;
705 ++ScriptPtr;
706 } else if (*ScriptPtr == '\r' && ScriptPtr[1] == '\n') {
707 ++Line;
708 Crossed = true;
709 ScriptPtr += 2;
714 continue;
716 // normal char
717 String += ch;
722 //==========================================================================
724 // skipNum
726 //==========================================================================
727 static const char *skipNum (const char *s, const char *end, int base) {
728 if (base <= 0) base = 10;
729 if (s >= end) return nullptr;
730 if (VStr::digitInBase(*s, base) < 0) return nullptr;
731 ++s;
732 while (s < end) {
733 if (*s != '_') {
734 if (VStr::digitInBase(*s, base) < 0) return s;
736 ++s;
738 return s;
742 //==========================================================================
744 // isValidNum
746 // returns number end, or `nullptr` if definitely not a number
748 //==========================================================================
749 static const char *isValidNum (const char *s, const char *end) {
750 if (s >= end) return nullptr;
752 // sign
753 if (*s == '+' || *s == '-') {
754 if (++s >= end) return nullptr;
757 // hex number?
758 if (*s == '0' && s+1 < end && s+2 < end && (s[1] == 'x' || s[1] == 'X')) {
759 s += 2;
760 return skipNum(s, end, 16);
763 if (*s != '.') {
764 // integral part
765 s = skipNum(s, end, 10);
766 if (!s || s >= end) return s;
767 } else {
768 // no integral part, so fractional part should have at least one digit
769 if (s+1 >= end) return nullptr;
770 if (s[1] < '0' || s[1] > '9') return nullptr;
773 // fractional part
774 if (*s == '.') {
775 if (++s >= end) return s;
776 if (*s >= '0' && *s <= '9') {
777 s = skipNum(s, end, 10);
778 if (!s || s >= end) return s;
782 // exponent
783 if (*s != 'e' && *s != 'E') return s;
784 if (++s >= end) return nullptr;
786 // sign
787 if (*s == '+' || *s == '-') {
788 if (++s >= end) return nullptr;
791 // exponent digits
792 return skipNum(s, end, 10);
796 //==========================================================================
798 // VScriptParser::ParseCMode
800 //==========================================================================
801 void VScriptParser::ParseCMode () noexcept {
802 if (ScriptPtr+1 < ScriptEndPtr) {
803 // special double-character eq-token?
804 if (ScriptPtr[1] == '=' && CharClassifier::isC2Spec(ScriptPtr[0])) {
805 String += *ScriptPtr++;
806 String += *ScriptPtr++;
807 return;
810 // special double-character token?
811 if ((ScriptPtr[0] == '&' && ScriptPtr[1] == '&') ||
812 (ScriptPtr[0] == '|' && ScriptPtr[1] == '|') ||
813 (ScriptPtr[0] == '<' && ScriptPtr[1] == '<') ||
814 (ScriptPtr[0] == '>' && ScriptPtr[1] == '>') ||
815 (ScriptPtr[0] == ':' && ScriptPtr[1] == ':') ||
816 (ScriptPtr[0] == '+' && ScriptPtr[1] == '+') ||
817 (ScriptPtr[0] == '-' && ScriptPtr[1] == '-'))
819 if (ScriptPtr[0] == '>' && ScriptPtr[1] == '>' && ScriptPtr[2] == '>') String += *ScriptPtr++; // for `>>>`
820 String += *ScriptPtr++;
821 String += *ScriptPtr++;
822 return;
826 // number?
827 // have to do it this way to omit underscores
828 if (CharClassifier::isNumStart(ScriptPtr, AllowNumSign)) {
829 const char *ee = isValidNum(ScriptPtr, ScriptEndPtr);
830 if (ee && (ee >= ScriptEndPtr || CharClassifier::isCIdTerm(*ee))) {
831 // looks like a valid number
832 while (ScriptPtr < ee) {
833 const char ch = *ScriptPtr++;
834 if (ch == '_') continue;
835 String += ch;
837 return;
841 // special single-character token?
842 if (CharClassifier::isCIdTerm(*ScriptPtr)) {
843 String += *ScriptPtr++;
844 return;
847 // normal identifier
848 while (ScriptPtr < ScriptEndPtr) {
849 const char ch = *ScriptPtr++;
850 // eh... allow single quote inside an identifier
851 if (ch == '\'' && !String.isEmpty() && ScriptPtr[0] && !CharClassifier::isCIdTerm(ScriptPtr[0])) {
852 String += ch;
853 continue;
855 if (CharClassifier::isCIdTerm(ch)) { --ScriptPtr; break; }
856 if (ch != '_' || !EDGEMode) String += ch;
861 //==========================================================================
863 // VScriptParser::ParseNonCMode
865 //==========================================================================
866 void VScriptParser::ParseNonCMode () noexcept {
867 // special single-character tokens
868 if (CharClassifier::isNCIdTerm(*ScriptPtr, HashComments)) {
869 String += *ScriptPtr++;
870 return;
873 // normal identifier
874 while (ScriptPtr < ScriptEndPtr) {
875 const char ch = *ScriptPtr++;
876 // eh... allow single quote inside an identifier
877 if (ch == '\'' && !String.isEmpty() && ScriptPtr[0] && !CharClassifier::isNCIdTerm(ScriptPtr[0], HashComments)) {
878 String += ch;
879 continue;
881 if (CharClassifier::isNCIdTerm(ch, HashComments)) { --ScriptPtr; break; }
882 // check for comments
883 if (ch == '/') {
884 const char c1 = *ScriptPtr;
885 if (c1 == '/' || c1 == '*' || c1 == '+') {
886 --ScriptPtr;
887 break;
890 if (ch != '_' || !EDGEMode) String += ch;
895 //==========================================================================
897 // VScriptParser::GetString
899 //==========================================================================
900 bool VScriptParser::GetString () noexcept {
901 TokStartPtr = ScriptPtr;
902 TokStartLine = Line;
904 Crossed = false;
905 QuotedString = false;
907 SkipBlanks(true); // change flags
909 // check for end of script
910 if (ScriptPtr >= ScriptEndPtr) {
911 TokStartPtr = ScriptEndPtr;
912 TokStartLine = Line;
913 End = true;
914 return false;
917 TokLine = Line;
919 String.Clean();
921 if (*ScriptPtr == '\"' || *ScriptPtr == '\'') {
922 // quoted string
923 const char qch = *ScriptPtr++;
924 QuotedString = true;
925 ParseQuotedString(qch);
926 } else if (CMode) {
927 ParseCMode();
928 } else {
929 ParseNonCMode();
932 return true;
936 //==========================================================================
938 // VScriptParser::SkipLine
940 //==========================================================================
941 void VScriptParser::SkipLine () noexcept {
942 Crossed = false;
943 QuotedString = false;
944 while (ScriptPtr < ScriptEndPtr) {
945 SkipComments(true);
946 if (Crossed || ScriptPtr >= ScriptEndPtr) break;
947 if (*ScriptPtr++ == '\n') {
948 ++Line;
949 break;
952 Crossed = false;
954 if (ScriptPtr >= ScriptEndPtr) {
955 ScriptPtr = ScriptEndPtr;
956 End = true;
959 TokStartPtr = ScriptEndPtr;
960 TokStartLine = Line;
964 //==========================================================================
966 // VScriptParser::ExpectString
968 //==========================================================================
969 void VScriptParser::ExpectString () {
970 if (!GetString()) Error("String expected");
974 //==========================================================================
976 // VScriptParser::ExpectLoneChar
978 //==========================================================================
979 void VScriptParser::ExpectLoneChar () {
980 UnGet();
981 char ch = PeekOrSkipChar(true); // skip
982 if (ch && ScriptPtr < ScriptEndPtr) {
983 if (ch == '"' && ScriptPtr[0] == '\\' && ScriptPtr[1] && ScriptPtr[2] == '"') {
984 ch = ScriptPtr[1];
985 ScriptPtr += 3;
986 } else if (ch == '"' && ScriptPtr[0] && ScriptPtr[1] == '"') {
987 ch = ScriptPtr[0];
988 ScriptPtr += 2;
989 } else {
990 // check for delimiter (space or comment)
991 vuint8 nch = *(const vuint8 *)ScriptPtr;
992 if (nch > ' ' && nch == '/' && ScriptEndPtr-ScriptPtr > 1) {
993 if (ScriptPtr[1] != '/' && ScriptPtr[1] != '*' && ScriptPtr[1] != '+') ch = 0;
997 if (!ch) Error("Char expected");
998 String.clear();
999 String += ch;
1003 //==========================================================================
1005 // ConvertStrToName8
1007 //==========================================================================
1008 static VName ConvertStrToName8 (VScriptParser *sc, VStr str, bool onlyWarn=true, VName *defval=nullptr) noexcept {
1009 #if !defined(VCC_STANDALONE_EXECUTOR)
1010 // translate "$name" strings
1011 if (str.length() > 1 && str[0] == '$') {
1012 VStr qs = str.mid(1, str.length()-1).toLowerCase();
1013 if (GLanguage.HasTranslation(*qs)) {
1014 qs = *GLanguage[*qs];
1015 if (dbg_show_name_remap) GCon->Logf(NAME_Debug, "**** <%s>=<%s>\n", *str, *qs);
1016 str = qs;
1019 #endif
1021 if (str.Length() > 8) {
1022 #if !defined(VCC_STANDALONE_EXECUTOR)
1023 VStr oldstr = str;
1024 #endif
1025 if (str.endsWithCI(".png")) str.chopRight(4);
1026 else if (str.endsWithCI(".jpg")) str.chopRight(4);
1027 else if (str.endsWithCI(".bmp")) str.chopRight(4);
1028 else if (str.endsWithCI(".pcx")) str.chopRight(4);
1029 else if (str.endsWithCI(".lmp")) str.chopRight(4);
1030 else if (str.endsWithCI(".jpeg")) str.chopRight(5);
1031 #if !defined(VCC_STANDALONE_EXECUTOR)
1032 if (oldstr != str) {
1033 GCon->Logf(NAME_Warning, "%s: Name '%s' converted to '%s'", *sc->GetLoc().toStringNoCol(), *oldstr, *str);
1035 #endif
1038 if (str.Length() > 8) {
1039 #if !defined(VCC_STANDALONE_EXECUTOR)
1040 GCon->Logf(NAME_Warning, "%s: Name '%s' is too long", *sc->GetLoc().toStringNoCol(), *str);
1041 #endif
1042 if (!onlyWarn) sc->Error(va("Name '%s' is too long", *str));
1043 if (defval) return *defval;
1046 return VName(*str, VName::AddLower8);
1050 //==========================================================================
1052 // VScriptParser::ExpectName8
1054 //==========================================================================
1055 void VScriptParser::ExpectName8 () {
1056 if (!GetString()) Error("Short name expected");
1057 Name8 = ConvertStrToName8(this, String, false); // error
1061 //==========================================================================
1063 // VScriptParser::ExpectName8Warn
1065 //==========================================================================
1066 void VScriptParser::ExpectName8Warn () {
1067 if (!GetString()) Error("Short name expected");
1068 Name8 = ConvertStrToName8(this, String); // no error
1072 //==========================================================================
1074 // VScriptParser::ExpectName8WarnOrFilePath
1076 //==========================================================================
1077 bool VScriptParser::ExpectName8WarnOrFilePath () {
1078 if (!GetString()) Error("Short name or path expected");
1079 String = String.fixSlashes();
1080 // hack for "vile/1", etc.
1081 const int slpos = String.indexOf('/');
1082 if (slpos < 0 || (String.length() <= 8 && slpos >= String.length()-2)) {
1083 Name8 = ConvertStrToName8(this, String); // no error
1084 return true;
1086 Name = NAME_None;
1087 Name8 = NAME_None;
1088 return false;
1092 //==========================================================================
1094 // VScriptParser::ExpectName8Def
1096 //==========================================================================
1097 void VScriptParser::ExpectName8Def (VName def) {
1098 if (!GetString()) Error("Short name expected");
1099 Name8 = ConvertStrToName8(this, String, true, &def); // no error
1103 //==========================================================================
1105 // VScriptParser::ExpectName
1107 //==========================================================================
1108 void VScriptParser::ExpectName () {
1109 if (!GetString()) Error("Name expected");
1110 Name = VName(*String, VName::AddLower);
1114 #if !defined(VCC_STANDALONE_EXECUTOR)
1115 //==========================================================================
1117 // ExpectName
1119 // returns parsed color, either in string form, or r,g,b triplet
1121 //==========================================================================
1122 vuint32 VScriptParser::ExpectColor () {
1123 if (!GetString()) Error("Color expected");
1124 //vuint32 clr = M_LookupColorName(String);
1125 //if (clr) return clr;
1126 // hack to allow numbers like "008000"
1127 if (QuotedString || String.length() > 3) {
1128 //GCon->Logf("COLOR(0): <%s> (0x%08x)", *String, M_ParseColor(*String));
1129 return M_ParseColor(*String);
1131 // should be r,g,b triplet
1132 UnGet();
1133 //ExpectNumber();
1134 if (!CheckNumber()) {
1135 ExpectString();
1136 //GCon->Logf("COLOR(1): <%s> (0x%08x)", *String, M_ParseColor(*String));
1137 return M_ParseColor(*String);
1139 int r = clampToByte(Number);
1140 Check(",");
1141 ExpectNumber();
1142 int g = clampToByte(Number);
1143 Check(",");
1144 ExpectNumber();
1145 int b = clampToByte(Number);
1146 //GCon->Logf("COLOR: rgb(%d,%d,%d)", r, g, b);
1147 return 0xff000000u|(r<<16)|(g<<8)|b;
1149 #endif
1152 //==========================================================================
1154 // VScriptParser::Check
1156 //==========================================================================
1157 bool VScriptParser::Check (const char *str) noexcept {
1158 vassert(str);
1159 vassert(str[0]);
1160 if (GetString()) {
1161 if (!String.ICmp(str)) return true;
1162 UnGet();
1164 return false;
1168 //==========================================================================
1170 // VScriptParser::CheckStartsWith
1172 //==========================================================================
1173 bool VScriptParser::CheckStartsWith (const char *str) noexcept {
1174 vassert(str);
1175 vassert(str[0]);
1176 if (GetString()) {
1177 VStr s = VStr(str);
1178 if (String.length() < s.length()) { UnGet(); return false; }
1179 VStr s2 = String.left(s.length());
1180 if (s2.ICmp(s) != 0) { UnGet(); return false; }
1181 return true;
1183 return false;
1187 //==========================================================================
1189 // VScriptParser::Expect
1191 //==========================================================================
1192 void VScriptParser::Expect (const char *name) {
1193 vassert(name);
1194 vassert(name[0]);
1195 if (!GetString()) Error(va("`%s` expected", name));
1196 if (String.ICmp(name)) Error(va("Bad syntax, `%s` expected, got `%s`.", name, *String.quote()));
1200 //==========================================================================
1202 // VScriptParser::CheckQuotedString
1204 //==========================================================================
1205 bool VScriptParser::CheckQuotedString () noexcept {
1206 if (!GetString()) return false;
1207 if (!QuotedString) {
1208 UnGet();
1209 return false;
1211 return true;
1215 //==========================================================================
1217 // VScriptParser::CheckIdentifier
1219 //==========================================================================
1220 bool VScriptParser::CheckIdentifier () noexcept {
1221 if (!GetString()) return false;
1223 // quoted strings are not valid identifiers
1224 if (QuotedString) {
1225 UnGet();
1226 return false;
1229 if (String.Length() < 1) {
1230 UnGet();
1231 return false;
1234 // identifier must start with a letter, a number or an underscore
1235 char c = String[0];
1236 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) {
1237 UnGet();
1238 return false;
1241 // it must be followed by letters, numbers and underscores
1242 for (int i = 1; i < String.Length(); ++i) {
1243 c = String[i];
1244 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) {
1245 UnGet();
1246 return false;
1249 return true;
1253 //==========================================================================
1255 // VScriptParser::ExpectIdentifier
1257 //==========================================================================
1258 void VScriptParser::ExpectIdentifier () {
1259 if (!CheckIdentifier()) Error(va("Identifier expected, got `%s`.", *String.quote()));
1263 //==========================================================================
1265 // NormalizeFuckedGozzoNumber
1267 //==========================================================================
1268 static VStr NormalizeFuckedGozzoNumber (VStr String) noexcept {
1269 VStr str = String.xstrip();
1270 if (str.length() && strchr("lfLF", str[str.length()-1])) {
1271 str.chopRight(1);
1272 str = String.xstrip();
1274 return str;
1278 //==========================================================================
1280 // VScriptParser::CheckNumber
1282 //==========================================================================
1283 bool VScriptParser::CheckNumber () noexcept {
1284 if (GetString()) {
1285 VStr str = NormalizeFuckedGozzoNumber(String);
1286 if (str.length() > 0) {
1287 if (str.convertInt(&Number)) {
1288 //GCon->Logf("VScriptParser::CheckNumber: <%s> is %d", *String, Number);
1289 return true;
1292 UnGet();
1294 return false;
1298 //==========================================================================
1300 // VScriptParser::ExpectNumber
1302 //==========================================================================
1303 void VScriptParser::ExpectNumber (bool allowFloat, bool truncFloat) {
1304 if (!GetString()) {
1305 Error("Integer expected");
1306 } else {
1307 VStr str = NormalizeFuckedGozzoNumber(String);
1308 if (str.length() > 0) {
1309 char *stopper;
1310 Number = strtol(*str, &stopper, 0);
1311 if (*stopper != 0) {
1312 if (allowFloat && *stopper == '.') {
1313 if (truncFloat) {
1314 Message(va("Bad numeric constant \"%s\" (integer expected; truncated to %d).", *String, (int)Number));
1315 } else {
1316 if (stopper[1] >= '5') ++Number;
1317 if (Number == 0) Number = 1; // just in case
1318 Message(va("Bad numeric constant \"%s\" (integer expected; rounded to %d).", *String, (int)Number));
1320 //fprintf(stderr, "%d\n", (int)Number);
1321 //Error(va("Bad numeric constant \"%s\".", *String));
1322 } else {
1323 Error(va("Bad numeric constant \"%s\".", *String));
1326 } else {
1327 Error("Integer expected");
1333 //==========================================================================
1335 // VScriptParser::CheckNumberWithSign
1337 //==========================================================================
1338 bool VScriptParser::CheckNumberWithSign () noexcept {
1339 char *savedPtr = TokStartPtr;
1340 int savedLine = TokStartLine;
1341 bool neg = Check("-");
1342 bool pos = !neg && Check("+");
1343 if (neg || pos) {
1344 if (CheckNumber()) {
1345 if (neg) Number = -Number;
1346 return true;
1348 // unget minus
1349 ScriptPtr = savedPtr;
1350 Line = savedLine;
1351 return false;
1352 } else {
1353 return CheckNumber();
1358 //==========================================================================
1360 // VScriptParser::ExpectNumberWithSign
1362 //==========================================================================
1363 void VScriptParser::ExpectNumberWithSign () {
1364 if (Check("-")) {
1365 ExpectNumber();
1366 Number = -Number;
1367 } else {
1368 ExpectNumber();
1373 //==========================================================================
1375 // VScriptParser::parseFloat
1377 // uses `String`
1379 //==========================================================================
1380 float VScriptParser::parseFloat (bool silent, bool *error) {
1381 bool etmp = false;
1382 if (!error) error = &etmp;
1383 *error = false;
1385 VStr str = NormalizeFuckedGozzoNumber(String);
1386 if (str.length() == 0) {
1387 *error = true;
1388 if (!silent) Error("Float expected");
1389 return 0.0f;
1392 //FIXME: detect when we want to use a really big number
1393 VStr sl = str.toLowerCase();
1394 if (sl.StartsWith("0x") || sl.StartsWith("-0x") || sl.StartsWith("+0x")) {
1395 const char *s = *str;
1396 bool neg = false;
1397 switch (*s) {
1398 case '-':
1399 neg = true;
1400 /* fallthrough */
1401 case '+':
1402 ++s;
1403 break;
1405 s += 2; // skip "0x"
1407 float val = 0.0f;
1408 bool skip = false;
1409 while (*s) {
1410 int dg = VStr::digitInBase(*s++, 16);
1411 if (dg < 0) {
1412 *error = true;
1413 if (!silent) Error(va("Bad floating point constant \"%s\"", *String));
1414 return 0.0f;
1416 if (!skip) {
1417 val = val*16.0f+(float)dg;
1418 if (val > 1.0e12f) {
1419 if (!silent) GLog.Logf(NAME_Warning, "%s: DON'T BE IDIOTS, THIS IS TOO MUCH FOR A FLOAT: '%s'", *GetLoc().toStringNoCol(), *String);
1420 skip = true;
1424 if (!silent) GLog.Logf(NAME_Warning, "%s: hex value '%s' for floating constant", *GetLoc().toStringNoCol(), *String);
1425 if (neg) val = -val;
1426 return val;
1427 } else {
1428 float ff = 0.0f;
1429 if (!str.convertFloat(&ff)) {
1430 // mo...dders from LCA loves numbers like "90000000000000000000000000000000000000000000000000"
1431 const char *s = *str;
1432 bool neg = false;
1433 switch (*s) {
1434 case '-':
1435 neg = true;
1436 /* fallthrough */
1437 case '+':
1438 ++s;
1439 break;
1441 while (*s >= '0' && *s <= '9') ++s;
1442 if (*s) {
1443 *error = true;
1444 if (!silent) Error(va("Bad floating point constant \"%s\".", *String));
1445 return 0.0f;
1447 if (!silent) GLog.Logf(NAME_Warning, "%s: DON'T BE IDIOTS, THIS IS TOO MUCH FOR A FLOAT: '%s'", *GetLoc().toStringNoCol(), *String);
1448 ff = 1.0e12f;
1449 if (neg) ff = -ff;
1450 } else {
1451 if (isNaNF(ff)) {
1452 *error = true;
1453 if (!silent) Error(va("Bad floating point constant \"%s\".", *String));
1454 return 0.0f;
1456 if (isInfF(ff)) {
1457 if (!silent) GLog.Logf(NAME_Warning, "%s: WUTAFUCK IS THIS SO-CALLED FLOAT!? -- '%s'", *GetLoc().toStringNoCol(), *String);
1458 ff = (isPositiveF(ff) ? 1.0e12f : -1.0e12f);
1459 } else if (ff < -1.0e12f || ff > +1.0e12f) {
1460 if (!silent) GLog.Logf(NAME_Warning, "%s: DON'T BE IDIOTS, THIS IS TOO MUCH FOR A FLOAT: '%s'", *GetLoc().toStringNoCol(), *String);
1461 if (ff < -1.0e12f) ff = -1.0e12f; else ff = 1.0e12f;
1464 return ff;
1469 //==========================================================================
1471 // VScriptParser::CheckFloat
1473 //==========================================================================
1474 bool VScriptParser::CheckFloat () noexcept {
1475 if (!GetString()) return false;
1476 if (!CMode || !AllowNumSign) {
1477 if (String.length() && (String[0] == '+' || String[0] == '-')) {
1478 UnGet();
1479 return false;
1482 bool error = false;
1483 const float ff = parseFloat(true, &error);
1484 if (error) UnGet(); else Float = ff;
1485 return !error;
1489 //==========================================================================
1491 // VScriptParser::ExpectFloat
1493 //==========================================================================
1494 void VScriptParser::ExpectFloat () {
1495 if (!GetString()) Error("Float expected");
1496 bool error = false;
1497 const float ff = parseFloat(false, &error);
1498 if (error) Error("Float expected");
1499 Float = ff;
1503 //==========================================================================
1505 // VScriptParser::CheckFloatWithSign
1507 //==========================================================================
1508 bool VScriptParser::CheckFloatWithSign () noexcept {
1509 char *savedPtr = TokStartPtr;
1510 int savedLine = TokStartLine;
1511 bool neg = Check("-");
1512 bool pos = !neg && Check("+");
1513 if (neg || pos) {
1514 if (CheckFloat()) {
1515 if (neg) Float = -Float;
1516 return true;
1518 // unget minus
1519 ScriptPtr = savedPtr;
1520 Line = savedLine;
1521 return false;
1522 } else {
1523 return CheckFloat();
1528 //==========================================================================
1530 // VScriptParser::ExpectFloatWithSign
1532 //==========================================================================
1533 void VScriptParser::ExpectFloatWithSign () {
1534 if (Check("-")) {
1535 ExpectFloat();
1536 Float = -Float;
1537 } else {
1538 Check("+");
1539 ExpectFloat();
1544 //==========================================================================
1546 // VScriptParser::ResetQuoted
1548 //==========================================================================
1549 void VScriptParser::ResetQuoted () noexcept {
1550 /*if (TokStartPtr != ScriptPtr)*/ QuotedString = false;
1554 //==========================================================================
1556 // VScriptParser::ResetCrossed
1558 //==========================================================================
1559 void VScriptParser::ResetCrossed () noexcept {
1560 /*if (TokStartPtr != ScriptPtr)*/ Crossed = false;
1564 //==========================================================================
1566 // VScriptParser::UnGet
1568 // Assumes that `GetString()` was called at least once
1570 //==========================================================================
1571 void VScriptParser::UnGet () noexcept {
1572 //AlreadyGot = true;
1573 ScriptPtr = TokStartPtr;
1574 Line = TokStartLine;
1575 //Crossed = false;
1579 //==========================================================================
1581 // VScriptParser::SkipBracketed
1583 //==========================================================================
1584 void VScriptParser::SkipBracketed (bool bracketEaten) noexcept {
1585 if (!bracketEaten) {
1586 for (;;) {
1587 ResetQuoted();
1588 if (!GetString()) return;
1589 if (QuotedString) continue;
1590 if (String.length() == 1 && String[0] == '{') {
1591 break;
1595 int level = 1;
1596 for (;;) {
1597 ResetQuoted();
1598 if (!GetString()) break;
1599 if (QuotedString) continue;
1600 if (String.length() == 1) {
1601 if (String[0] == '{') {
1602 ++level;
1603 } else if (String[0] == '}') {
1604 if (--level == 0) return;
1611 //==========================================================================
1613 // VScriptParser::Message
1615 //==========================================================================
1616 void VScriptParser::Message (const char *message) {
1617 const char *Msg = (message ? message : "Bad syntax.");
1618 #if !defined(VCC_STANDALONE_EXECUTOR)
1619 GCon->Logf(NAME_Warning, "%s:%d: %s", *ScriptName, TokLine, Msg);
1620 #else
1621 GLog.WriteLine(NAME_Warning, "%s:%d: %s", *ScriptName, TokLine, Msg);
1622 #endif
1626 //==========================================================================
1628 // VScriptParser::DebugMessage
1630 //==========================================================================
1631 void VScriptParser::DebugMessage (const char *message) {
1632 const char *Msg = (message ? message : "Bad syntax.");
1633 #if !defined(VCC_STANDALONE_EXECUTOR)
1634 GCon->Logf(NAME_Debug, "%s:%d: %s", *ScriptName, TokLine, Msg);
1635 #else
1636 GLog.WriteLine(NAME_Debug, "%s:%d: %s", *ScriptName, TokLine, Msg);
1637 #endif
1641 //==========================================================================
1643 // VScriptParser::MessageErr
1645 //==========================================================================
1646 void VScriptParser::MessageErr (const char *message) {
1647 const char *Msg = (message ? message : "Bad syntax.");
1648 #if !defined(VCC_STANDALONE_EXECUTOR)
1649 GCon->Logf(NAME_Error, "%s:%d: %s", *ScriptName, TokLine, Msg);
1650 #else
1651 GLog.WriteLine(NAME_Error, "%s:%d: %s", *ScriptName, TokLine, Msg);
1652 #endif
1656 //==========================================================================
1658 // VScriptParser::Error
1660 //==========================================================================
1661 void VScriptParser::Error (const char *message) {
1662 const char *Msg = (message ? message : "Bad syntax.");
1663 Sys_Error("Script error at %s:%d: %s", *ScriptName, TokLine, Msg);
1667 //==========================================================================
1669 // VScriptParser::HostError
1671 //==========================================================================
1672 #if !defined(VCC_STANDALONE_EXECUTOR)
1673 void VScriptParser::HostError (const char *message) {
1674 const char *Msg = (message ? message : "Bad syntax.");
1675 Host_Error("Script error at %s:%d: %s", *ScriptName, TokLine, Msg);
1677 #endif
1680 //==========================================================================
1682 // VScriptParser::Messagef
1684 //==========================================================================
1685 __attribute__((format(printf, 2, 3))) void VScriptParser::Messagef (const char *fmt, ...) {
1686 va_list ap;
1687 va_start(ap, fmt);
1688 const char *s = vavarg(fmt, ap);
1689 va_end(ap);
1690 Message(s);
1694 //==========================================================================
1696 // VScriptParser::DebugMessagef
1698 //==========================================================================
1699 __attribute__((format(printf, 2, 3))) void VScriptParser::DebugMessagef (const char *fmt, ...) {
1700 va_list ap;
1701 va_start(ap, fmt);
1702 const char *s = vavarg(fmt, ap);
1703 va_end(ap);
1704 DebugMessage(s);
1708 //==========================================================================
1710 // VScriptParser::MessageErrf
1712 //==========================================================================
1713 __attribute__((format(printf, 2, 3))) void VScriptParser::MessageErrf (const char *fmt, ...) {
1714 va_list ap;
1715 va_start(ap, fmt);
1716 const char *s = vavarg(fmt, ap);
1717 va_end(ap);
1718 MessageErr(s);
1722 //==========================================================================
1724 // VScriptParser::Errorf
1726 //==========================================================================
1727 __attribute__((format(printf, 2, 3))) void VScriptParser::Errorf (const char *fmt, ...) {
1728 va_list ap;
1729 va_start(ap, fmt);
1730 const char *s = vavarg(fmt, ap);
1731 va_end(ap);
1732 Error(s);
1736 #if !defined(VCC_STANDALONE_EXECUTOR)
1737 //==========================================================================
1739 // VScriptParser::HostErrorf
1741 //==========================================================================
1742 __attribute__((format(printf, 2, 3))) void VScriptParser::HostErrorf (const char *fmt, ...) {
1743 va_list ap;
1744 va_start(ap, fmt);
1745 const char *s = vavarg(fmt, ap);
1746 va_end(ap);
1747 HostError(s);
1749 #endif
1752 //==========================================================================
1754 // VScriptParser::GetVCLoc
1756 //==========================================================================
1757 TLocation VScriptParser::GetVCLoc () const noexcept {
1758 if (SrcIdx == -1) SrcIdx = TLocation::AddSourceFile(ScriptName);
1759 return TLocation(SrcIdx, TokLine, 1);
1763 #if !defined(VCC_STANDALONE_EXECUTOR)
1764 //==========================================================================
1766 // VScriptParser::FindRelativeIncludeLump
1768 //==========================================================================
1769 int VScriptParser::FindRelativeIncludeLump (int srclump, VStr fname) noexcept {
1770 if (fname.isEmpty()) return -1;
1771 if (srclump < 0 || fname[0] == '/') return -1;
1773 VStr fn = W_RealLumpName(srclump);
1774 if (fn.indexOf('/') < 0) return -1;
1775 fn = fn.ExtractFilePath();
1776 fname = fn.appendPath(fname);
1778 return W_CheckNumForFileNameInSameFile(srclump, fname);
1782 //==========================================================================
1784 // VScriptParser::FindIncludeLump
1786 //==========================================================================
1787 int VScriptParser::FindIncludeLump (int srclump, VStr fname) noexcept {
1788 if (fname.isEmpty()) return -1;
1789 //GLog.Logf(NAME_Debug, "***FindIncludeLumpEx: srclump=%d; fname='%s' (srcfname='%s')", srclump, *fname, *W_FullLumpName(srclump));
1791 int Lump = (srclump >= 0 ? W_CheckNumForFileNameInSameFile(srclump, fname) : W_CheckNumForFileName(fname));
1792 if (Lump >= 0) return Lump;
1794 fname = fname.fixSlashes();
1795 //GLog.Logf(NAME_Debug, " fname='%s'", *fname);
1797 Lump = FindRelativeIncludeLump(srclump, fname);
1798 if (Lump >= 0) return Lump;
1800 //GLog.Logf(NAME_Debug, " XXX: fname='%s'", *fname);
1801 // check WAD lump only if it's no longer than 8 characters and has no path separator
1802 if (/*(srclump == -1 || W_IsWADLump(srclump)) &&*/ fname.indexOf('/') < 0) {
1803 VStr noext = fname.stripExtension();
1804 //GLog.Logf(NAME_Debug, " NOEXT: %s", *noext);
1805 if (!noext.isEmpty() && noext.length() <= 8) {
1806 VName nn(*fname, VName::FindLower8);
1807 if (nn != NAME_None) {
1808 //GLog.Logf(NAME_Debug, " NN: %s", *nn);
1809 Lump = (srclump < 0 ? W_CheckNumForName(nn) : W_CheckNumForNameInFile(nn, W_LumpFile(srclump)));
1810 if (Lump >= 0) return Lump;
1815 return Lump;
1817 #endif
1821 // ////////////////////////////////////////////////////////////////////////// //
1822 // VScriptsParser
1823 // ////////////////////////////////////////////////////////////////////////// //
1825 //==========================================================================
1827 // VScriptsParser::Destroy
1829 //==========================================================================
1830 void VScriptsParser::Destroy () {
1831 if (Int) {
1832 delete Int;
1833 Int = nullptr;
1835 Super::Destroy();
1839 //==========================================================================
1841 // VScriptsParser::CheckInterface
1843 //==========================================================================
1844 void VScriptsParser::CheckInterface () {
1845 if (!Int) Sys_Error("No script currently open");
1850 //==========================================================================
1852 // VScriptsParser natives
1854 //==========================================================================
1856 #if !defined(VCC_STANDALONE_EXECUTOR)
1857 IMPLEMENT_FUNCTION(VScriptsParser, OpenLumpName) {
1858 VName Name;
1859 vobjGetParamSelf(Name);
1860 if (Self->Int) {
1861 delete Self->Int;
1862 Self->Int = nullptr;
1864 int Lump = W_GetNumForName(Name);
1865 if (Lump < 0) Sys_Error("cannot open non-existing lump '%s'", *Name);
1866 Self->Int = VScriptParser::NewWithLump(Lump);
1869 IMPLEMENT_FUNCTION(VScriptsParser, OpenLumpIndex) {
1870 int lump;
1871 vobjGetParamSelf(lump);
1872 if (Self->Int) {
1873 delete Self->Int;
1874 Self->Int = nullptr;
1876 if (lump < 0) Sys_Error("cannot open non-existing lump");
1877 VStream *st = W_CreateLumpReaderNum(lump);
1878 if (!st) Sys_Error("cannot open non-existing lump");
1879 Self->Int = new VScriptParser(W_FullLumpName(lump), st, lump);
1881 #endif
1883 IMPLEMENT_FUNCTION(VScriptsParser, OpenLumpFullName) {
1884 VStr Name;
1885 vobjGetParamSelf(Name);
1886 #if !defined(VCC_STANDALONE_EXECUTOR)
1887 if (Self->Int) {
1888 delete Self->Int;
1889 Self->Int = nullptr;
1891 // first try disk file
1892 if (FL_IsSafeDiskFileName(Name)) {
1893 VStr diskName = FL_GetUserDataDir(false)+"/"+Name;
1894 VStream *st = FL_OpenSysFileRead(*diskName);
1895 if (st) {
1896 bool ok = true;
1897 VStr s;
1898 if (st->TotalSize() > 0) {
1899 s.setLength(st->TotalSize());
1900 st->Serialise(s.getMutableCStr(), s.length());
1901 ok = !st->IsError();
1903 VStream::Destroy(st);
1904 if (!ok) Sys_Error("cannot read file '%s'", *Name);
1905 Self->Int = new VScriptParser(*Name, *s);
1906 return;
1909 if (Name.length() >= 2 && Name[0] == '/' && Name[1] == '/') {
1910 VStream *strm = FL_OpenFileRead(Name);
1911 if (!strm) Sys_Error("file '%s' not found", *Name);
1912 Self->Int = new VScriptParser(*Name, strm);
1913 } else {
1914 int num = W_GetNumForFileName(Name);
1915 //int num = W_IterateFile(-1, *Name);
1916 if (num < 0) Sys_Error("file '%s' not found", *Name);
1917 Self->Int = VScriptParser::NewWithLump(num);
1919 #elif defined(VCC_STANDALONE_EXECUTOR)
1920 if (Self->Int) {
1921 delete Self->Int;
1922 Self->Int = nullptr;
1924 VStream *st = fsysOpenFile(*Name);
1925 if (!st) Sys_Error("file '%s' not found", *Name);
1926 bool ok = true;
1927 VStr s;
1928 if (st->TotalSize() > 0) {
1929 s.setLength(st->TotalSize());
1930 st->Serialise(s.getMutableCStr(), s.length());
1931 ok = !st->IsError();
1933 VStream::Destroy(st);
1934 if (!ok) Sys_Error("cannot read file '%s'", *Name);
1935 Self->Int = new VScriptParser(*Name, *s);
1936 #else
1937 Sys_Error("file '%s' not found", *Name);
1938 #endif
1941 IMPLEMENT_FUNCTION(VScriptsParser, OpenString) {
1942 VName Name;
1943 VStr s;
1944 vobjGetParamSelf(Name, s);
1945 if (Self->Int) {
1946 delete Self->Int;
1947 Self->Int = nullptr;
1949 Self->Int = new VScriptParser(*Name, *s);
1952 IMPLEMENT_FUNCTION(VScriptsParser, get_String) {
1953 vobjGetParamSelf();
1954 Self->CheckInterface();
1955 RET_STR(Self->Int->String);
1958 IMPLEMENT_FUNCTION(VScriptsParser, get_Number) {
1959 vobjGetParamSelf();
1960 Self->CheckInterface();
1961 RET_INT(Self->Int->Number);
1964 IMPLEMENT_FUNCTION(VScriptsParser, get_Float) {
1965 vobjGetParamSelf();
1966 Self->CheckInterface();
1967 RET_FLOAT(Self->Int->Float);
1970 IMPLEMENT_FUNCTION(VScriptsParser, get_Crossed) {
1971 vobjGetParamSelf();
1972 Self->CheckInterface();
1973 RET_BOOL(Self->Int->Crossed);
1976 IMPLEMENT_FUNCTION(VScriptsParser, get_Quoted) {
1977 vobjGetParamSelf();
1978 Self->CheckInterface();
1979 RET_BOOL(Self->Int->QuotedString);
1982 IMPLEMENT_FUNCTION(VScriptsParser, get_SourceLump) {
1983 vobjGetParamSelf();
1984 Self->CheckInterface();
1985 RET_BOOL(Self->Int->SourceLump);
1988 IMPLEMENT_FUNCTION(VScriptsParser, set_SourceLump) {
1989 vuint32 value;
1990 vobjGetParamSelf(value);
1991 Self->CheckInterface();
1992 Self->Int->SourceLump = value;
1995 IMPLEMENT_FUNCTION(VScriptsParser, get_Escape) {
1996 vobjGetParamSelf();
1997 Self->CheckInterface();
1998 RET_BOOL(Self->Int->IsEscape());
2001 IMPLEMENT_FUNCTION(VScriptsParser, set_Escape) {
2002 bool value;
2003 vobjGetParamSelf(value);
2004 Self->CheckInterface();
2005 Self->Int->SetEscape(value);
2008 IMPLEMENT_FUNCTION(VScriptsParser, get_CMode) {
2009 vobjGetParamSelf();
2010 Self->CheckInterface();
2011 RET_BOOL(Self->Int->IsCMode());
2014 IMPLEMENT_FUNCTION(VScriptsParser, set_CMode) {
2015 bool value;
2016 vobjGetParamSelf(value);
2017 Self->CheckInterface();
2018 Self->Int->SetCMode(value);
2021 IMPLEMENT_FUNCTION(VScriptsParser, get_AllowNumSign) {
2022 vobjGetParamSelf();
2023 Self->CheckInterface();
2024 RET_BOOL(Self->Int->IsAllowNumSign());
2027 IMPLEMENT_FUNCTION(VScriptsParser, set_AllowNumSign) {
2028 bool value;
2029 vobjGetParamSelf(value);
2030 Self->CheckInterface();
2031 Self->Int->SetAllowNumSign(value);
2034 IMPLEMENT_FUNCTION(VScriptsParser, get_EDGEMode) {
2035 vobjGetParamSelf();
2036 Self->CheckInterface();
2037 RET_BOOL(Self->Int->IsEDGEMode());
2040 IMPLEMENT_FUNCTION(VScriptsParser, set_EDGEMode) {
2041 bool value;
2042 vobjGetParamSelf(value);
2043 Self->CheckInterface();
2044 Self->Int->SetEDGEMode(value);
2047 IMPLEMENT_FUNCTION(VScriptsParser, get_SemicolonComments) {
2048 vobjGetParamSelf();
2049 Self->CheckInterface();
2050 RET_BOOL(Self->Int->IsSemicolonComments());
2053 IMPLEMENT_FUNCTION(VScriptsParser, set_SemicolonComments) {
2054 bool value;
2055 vobjGetParamSelf(value);
2056 Self->CheckInterface();
2057 Self->Int->SetSemicolonComments(value);
2060 IMPLEMENT_FUNCTION(VScriptsParser, get_HashComments) {
2061 vobjGetParamSelf();
2062 Self->CheckInterface();
2063 RET_BOOL(Self->Int->IsHashComments());
2066 IMPLEMENT_FUNCTION(VScriptsParser, set_HashComments) {
2067 bool value;
2068 vobjGetParamSelf(value);
2069 Self->CheckInterface();
2070 Self->Int->SetHashComments(value);
2073 IMPLEMENT_FUNCTION(VScriptsParser, get_EndOfText) {
2074 vobjGetParamSelf();
2075 Self->CheckInterface();
2076 RET_BOOL(Self->Int->End);
2079 IMPLEMENT_FUNCTION(VScriptsParser, IsText) {
2080 vobjGetParamSelf();
2081 Self->CheckInterface();
2082 RET_BOOL(Self->Int->IsText());
2085 IMPLEMENT_FUNCTION(VScriptsParser, IsAtEol) {
2086 vobjGetParamSelf();
2087 Self->CheckInterface();
2088 RET_BOOL(Self->Int->IsAtEol());
2091 IMPLEMENT_FUNCTION(VScriptsParser, IsCMode) {
2092 vobjGetParamSelf();
2093 Self->CheckInterface();
2094 RET_BOOL(Self->Int->IsCMode());
2097 IMPLEMENT_FUNCTION(VScriptsParser, SetCMode) {
2098 bool On;
2099 vobjGetParamSelf(On);
2100 Self->CheckInterface();
2101 Self->Int->SetCMode(On);
2104 IMPLEMENT_FUNCTION(VScriptsParser, IsAllowNumSign) {
2105 vobjGetParamSelf();
2106 Self->CheckInterface();
2107 RET_BOOL(Self->Int->IsAllowNumSign());
2110 IMPLEMENT_FUNCTION(VScriptsParser, SetAllowNumSign) {
2111 bool On;
2112 vobjGetParamSelf(On);
2113 Self->CheckInterface();
2114 Self->Int->SetAllowNumSign(On);
2117 IMPLEMENT_FUNCTION(VScriptsParser, IsEscape) {
2118 vobjGetParamSelf();
2119 Self->CheckInterface();
2120 RET_BOOL(Self->Int->IsEscape());
2123 IMPLEMENT_FUNCTION(VScriptsParser, SetEscape) {
2124 bool On;
2125 vobjGetParamSelf(On);
2126 Self->CheckInterface();
2127 Self->Int->SetEscape(On);
2130 IMPLEMENT_FUNCTION(VScriptsParser, AtEnd) {
2131 vobjGetParamSelf();
2132 Self->CheckInterface();
2133 RET_BOOL(Self->Int->AtEnd());
2136 IMPLEMENT_FUNCTION(VScriptsParser, GetString) {
2137 vobjGetParamSelf();
2138 Self->CheckInterface();
2139 RET_BOOL(Self->Int->GetString());
2142 IMPLEMENT_FUNCTION(VScriptsParser, ExpectLoneChar) {
2143 vobjGetParamSelf();
2144 Self->CheckInterface();
2145 Self->Int->ExpectLoneChar();
2148 #if !defined(VCC_STANDALONE_EXECUTOR)
2149 IMPLEMENT_FUNCTION(VScriptsParser, ExpectColor) {
2150 vobjGetParamSelf();
2151 Self->CheckInterface();
2152 RET_INT(Self->Int->ExpectColor());
2154 #endif
2156 IMPLEMENT_FUNCTION(VScriptsParser, ExpectString) {
2157 vobjGetParamSelf();
2158 Self->CheckInterface();
2159 Self->Int->ExpectString();
2162 IMPLEMENT_FUNCTION(VScriptsParser, Check) {
2163 VStr Text;
2164 vobjGetParamSelf(Text);
2165 Self->CheckInterface();
2166 RET_BOOL(Self->Int->Check(*Text));
2169 IMPLEMENT_FUNCTION(VScriptsParser, CheckStartsWith) {
2170 VStr Text;
2171 vobjGetParamSelf(Text);
2172 Self->CheckInterface();
2173 RET_BOOL(Self->Int->CheckStartsWith(*Text));
2176 IMPLEMENT_FUNCTION(VScriptsParser, Expect) {
2177 VStr Text;
2178 vobjGetParamSelf(Text);
2179 Self->CheckInterface();
2180 Self->Int->Expect(*Text);
2183 IMPLEMENT_FUNCTION(VScriptsParser, CheckIdentifier) {
2184 vobjGetParamSelf();
2185 Self->CheckInterface();
2186 RET_BOOL(Self->Int->CheckIdentifier());
2189 IMPLEMENT_FUNCTION(VScriptsParser, ExpectIdentifier) {
2190 vobjGetParamSelf();
2191 Self->CheckInterface();
2192 Self->Int->ExpectIdentifier();
2195 IMPLEMENT_FUNCTION(VScriptsParser, CheckNumber) {
2196 VOptParamBool withSign(false);
2197 vobjGetParamSelf(withSign);
2198 Self->CheckInterface();
2199 RET_BOOL(withSign ? Self->Int->CheckNumberWithSign() : Self->Int->CheckNumber());
2202 IMPLEMENT_FUNCTION(VScriptsParser, ExpectNumber) {
2203 VOptParamBool withSign(false);
2204 vobjGetParamSelf(withSign);
2205 Self->CheckInterface();
2206 if (withSign) Self->Int->ExpectNumberWithSign(); else Self->Int->ExpectNumber();
2209 IMPLEMENT_FUNCTION(VScriptsParser, CheckFloat) {
2210 VOptParamBool withSign(false);
2211 vobjGetParamSelf(withSign);
2212 Self->CheckInterface();
2213 RET_BOOL(withSign ? Self->Int->CheckFloatWithSign() : Self->Int->CheckFloat());
2216 IMPLEMENT_FUNCTION(VScriptsParser, ExpectFloat) {
2217 VOptParamBool withSign(false);
2218 vobjGetParamSelf(withSign);
2219 Self->CheckInterface();
2220 if (withSign) Self->Int->ExpectFloatWithSign(); else Self->Int->ExpectFloat();
2223 IMPLEMENT_FUNCTION(VScriptsParser, ResetQuoted) {
2224 vobjGetParamSelf();
2225 Self->CheckInterface();
2226 Self->Int->ResetQuoted();
2229 IMPLEMENT_FUNCTION(VScriptsParser, ResetCrossed) {
2230 vobjGetParamSelf();
2231 Self->CheckInterface();
2232 Self->Int->ResetCrossed();
2235 IMPLEMENT_FUNCTION(VScriptsParser, SkipBracketed) {
2236 VOptParamBool bracketEaten(false);
2237 vobjGetParamSelf(bracketEaten);
2238 Self->CheckInterface();
2239 Self->Int->SkipBracketed(bracketEaten);
2242 IMPLEMENT_FUNCTION(VScriptsParser, SkipLine) {
2243 vobjGetParamSelf();
2244 Self->CheckInterface();
2245 Self->Int->SkipLine();
2248 IMPLEMENT_FUNCTION(VScriptsParser, UnGet) {
2249 vobjGetParamSelf();
2250 Self->CheckInterface();
2251 Self->Int->UnGet();
2254 IMPLEMENT_FUNCTION(VScriptsParser, FileName) {
2255 vobjGetParamSelf();
2256 Self->CheckInterface();
2257 RET_STR(Self->Int->GetScriptName());
2260 IMPLEMENT_FUNCTION(VScriptsParser, CurrLine) {
2261 vobjGetParamSelf();
2262 Self->CheckInterface();
2263 RET_INT(Self->Int->Line);
2266 IMPLEMENT_FUNCTION(VScriptsParser, TokenLine) {
2267 vobjGetParamSelf();
2268 Self->CheckInterface();
2269 RET_INT(Self->Int->TokLine);
2272 IMPLEMENT_FUNCTION(VScriptsParser, ScriptError) {
2273 VStr Msg = PF_FormatString();
2274 vobjGetParamSelf();
2275 Self->CheckInterface();
2276 Self->Int->Error(*Msg);
2279 IMPLEMENT_FUNCTION(VScriptsParser, ScriptMessage) {
2280 VStr Msg = PF_FormatString();
2281 vobjGetParamSelf();
2282 Self->CheckInterface();
2283 Self->Int->Message(*Msg);
2286 IMPLEMENT_FUNCTION(VScriptsParser, SavePos) {
2287 VScriptSavedPos *pos;
2288 vobjGetParamSelf(pos);
2289 Self->CheckInterface();
2290 if (pos) *pos = Self->Int->SavePos();
2293 IMPLEMENT_FUNCTION(VScriptsParser, RestorePos) {
2294 VScriptSavedPos *pos;
2295 vobjGetParamSelf(pos);
2296 Self->CheckInterface();
2297 if (pos) Self->Int->RestorePos(*pos);
2300 #if !defined(VCC_STANDALONE_EXECUTOR)
2301 //static native final int FindRelativeIncludeLump (int srclump, string fname);
2302 IMPLEMENT_FUNCTION(VScriptsParser, FindRelativeIncludeLump) {
2303 int srclump;
2304 VStr fname;
2305 vobjGetParamSelf(srclump, fname);
2306 RET_INT(VScriptParser::FindRelativeIncludeLump(srclump, fname));
2309 //static native final int FindIncludeLump (int srclump, string fname);
2310 IMPLEMENT_FUNCTION(VScriptsParser, FindIncludeLump) {
2311 int srclump;
2312 VStr fname;
2313 vobjGetParamSelf(srclump, fname);
2314 RET_INT(VScriptParser::FindIncludeLump(srclump, fname));
2316 #endif