// ----------------------------------------------------------------------------- // Parses all statements/blocks in [entry], adding them to [parsed] // ----------------------------------------------------------------------------- void parseBlocks(ArchiveEntry* entry, vector<ParsedStatement>& parsed) { Tokenizer tz; tz.setSpecialCharacters(CHR(Tokenizer::DEFAULT_SPECIAL_CHARACTERS + "()+-[]&!?.")); tz.enableDecorate(true); tz.setCommentTypes(Tokenizer::CommentTypes::CPPStyle | Tokenizer::CommentTypes::CStyle); tz.openMem(entry->getMCData(), "ZScript"); // Log::info(2, S_FMT("Parsing ZScript entry \"%s\"", entry->getPath(true))); while (!tz.atEnd()) { // Preprocessor if (tz.current().text.StartsWith("#")) { if (tz.checkNC("#include")) { auto inc_entry = entry->relativeEntry(tz.next().text); // Check #include path could be resolved if (!inc_entry) { Log::warning(S_FMT( "Warning parsing ZScript entry %s: " "Unable to find #included entry \"%s\" at line %u, skipping", CHR(entry->getName()), CHR(tz.current().text), tz.current().line_no)); } else parseBlocks(inc_entry, parsed); } tz.advToNextLine(); continue; } // Version else if (tz.checkNC("version")) { tz.advToNextLine(); continue; } // ZScript parsed.push_back({}); parsed.back().entry = entry; if (!parsed.back().parse(tz)) parsed.pop_back(); } // Set entry type if (etype_zscript && entry->getType() != etype_zscript) entry->setType(etype_zscript); }
/* KeyBind::readBinds * Reads keybind defeinitions from tokenizer [tz] *******************************************************************/ bool KeyBind::readBinds(Tokenizer& tz) { // Parse until ending } string name = tz.getToken(); while (name != "}" && !tz.atEnd()) { // Clear any current binds for the key getBind(name).keys.clear(); // Read keys while (1) { string keystr = tz.getToken(); // Finish if no keys are bound if (keystr == "unbound") break; // Parse key string string key, mods; if (keystr.Find("|") >= 0) { mods = keystr.BeforeFirst('|'); key = keystr.AfterFirst('|'); } else key = keystr; // Add the key addBind(name, keypress_t(key, mods.Find('a') >= 0, mods.Find('c') >= 0, mods.Find('s') >= 0)); // Check for more keys if (tz.peekToken() == ",") tz.getToken(); // Skip , else break; } // Next keybind name = tz.getToken(); } // Create sorted list keybinds_sorted = keybinds; std::sort(keybinds_sorted.begin(), keybinds_sorted.end()); return true; }
/* TextEditor::openJumpToDialog * Initialises and opens the 'Jump To' dialog *******************************************************************/ void TextEditor::openJumpToDialog() { // Can't do this without a language definition or defined blocks if (!language || language->nJumpBlocks() == 0) return; // --- Scan for functions/scripts --- Tokenizer tz; vector<jp_t> jump_points; tz.openString(GetText()); string token = tz.getToken(); while (!tz.atEnd()) { if (token == "{") { // Skip block while (!tz.atEnd() && token != "}") token = tz.getToken(); } for (unsigned a = 0; a < language->nJumpBlocks(); a++) { // Get jump block keyword string block = language->jumpBlock(a); long skip = 0; if (block.Contains(":")) { wxArrayString sp = wxSplit(block, ':'); sp.back().ToLong(&skip); block = sp[0]; } if (S_CMPNOCASE(token, block)) { string name = tz.getToken(); for (int s = 0; s < skip; s++) name = tz.getToken(); for (unsigned i = 0; i < language->nJBIgnore(); ++i) if (S_CMPNOCASE(name, language->jBIgnore(i))) name = tz.getToken(); // Numbered block, add block name if (name.IsNumber()) name = S_FMT("%s %s", language->jumpBlock(a), name); // Unnamed block, use block name if (name == "{" || name == ";") name = language->jumpBlock(a); // Create jump point jp_t jp; jp.name = name; jp.line = tz.lineNo() - 1; jump_points.push_back(jp); } } token = tz.getToken(); } // Do nothing if no jump points if (jump_points.size() == 0) return; // --- Setup/show dialog --- wxDialog dlg(this, -1, "Jump To..."); wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); dlg.SetSizer(sizer); // Add Jump to dropdown wxChoice* choice_jump_to = new wxChoice(&dlg, -1); sizer->Add(choice_jump_to, 0, wxEXPAND|wxALL, 4); for (unsigned a = 0; a < jump_points.size(); a++) choice_jump_to->Append(jump_points[a].name); choice_jump_to->SetSelection(0); // Add dialog buttons sizer->Add(dlg.CreateButtonSizer(wxOK|wxCANCEL), 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 4); // Show dialog dlg.SetInitialSize(wxSize(250, -1)); dlg.CenterOnParent(); if (dlg.ShowModal() == wxID_OK) { int selection = choice_jump_to->GetSelection(); if (selection >= 0 && selection < (int)jump_points.size()) { // Get line number int line = jump_points[selection].line; // Move to line int pos = GetLineEndPosition(line); SetCurrentPos(pos); SetSelection(pos, pos); SetFirstVisibleLine(line); SetFocus(); } } }
// ---------------------------------------------------------------------------- // TLFunction::addContext // // Adds a [context] of the function // ---------------------------------------------------------------------------- void TLFunction::addContext( const string& context, const string& args, const string& return_type, string description, const string& deprecated_f) { contexts_.push_back(Context{ context, {}, return_type, description, "", "", "" }); auto& ctx = contexts_.back(); // Parse args Tokenizer tz; tz.setSpecialCharacters("[],"); tz.openString(args); vector<string> arg_tokens; while (true) { while (!tz.check(",")) { arg_tokens.push_back(tz.current().text); if (tz.atEnd()) break; tz.adv(); } ctx.params.push_back({}); ctx.params.back().parse(arg_tokens); arg_tokens.clear(); if (tz.atEnd()) break; tz.adv(); } if (!deprecated_f.empty()) { // Parse deprecated string tz.openString(deprecated_f); for (unsigned t = 0; t < 2; t++) { while (tz.check(",")) tz.adv(); bool is_replacement = true; for (unsigned c = 0; c < tz.current().text.size(); c++) { char chr = tz.current().text[c]; if (isdigit(chr) || chr == '.') { is_replacement = false; break; } } if (is_replacement) ctx.deprecated_f = tz.current().text; else ctx.deprecated_v = tz.current().text; if (tz.atEnd()) break; tz.adv(); } } }
/* MapSpecials::processACSScripts * Process 'OPEN' ACS scripts for various specials - sector colours, * slopes, etc. *******************************************************************/ void MapSpecials::processACSScripts(ArchiveEntry* entry) { sector_colours.clear(); sector_fadecolours.clear(); if (!entry || entry->getSize() == 0) return; Tokenizer tz; tz.setSpecialCharacters(";,:|={}/()"); tz.openMem(entry->getMCData(), "ACS Scripts"); while (!tz.atEnd()) { if (tz.checkNC("script")) { LOG_MESSAGE(3, "script found"); tz.adv(2); // Skip script # // Check for open script if (tz.checkNC("OPEN")) { LOG_MESSAGE(3, "script is OPEN"); // Skip to opening brace while (!tz.check("{")) tz.adv(); // Parse script while (!tz.checkOrEnd("}")) { // --- Sector_SetColor --- if (tz.checkNC("Sector_SetColor")) { // Get parameters auto parameters = tz.getTokensUntil(")"); // Parse parameters long val; int tag = -1; int r = -1; int g = -1; int b = -1; for (unsigned a = 0; a < parameters.size(); a++) { if (parameters[a].text.ToLong(&val)) { if (tag < 0) tag = val; else if (r < 0) r = val; else if (g < 0) g = val; else if (b < 0) b = val; } } // Check everything is set if (b < 0) { LOG_MESSAGE(2, "Invalid Sector_SetColor parameters"); } else { sector_colour_t sc; sc.tag = tag; sc.colour.set(r, g, b, 255); LOG_MESSAGE(3, "Sector tag %d, colour %d,%d,%d", tag, r, g, b); sector_colours.push_back(sc); } } // --- Sector_SetFade --- else if (tz.checkNC("Sector_SetFade")) { // Get parameters auto parameters = tz.getTokensUntil(")"); // Parse parameters long val; int tag = -1; int r = -1; int g = -1; int b = -1; for (unsigned a = 0; a < parameters.size(); a++) { if (parameters[a].text.ToLong(&val)) { if (tag < 0) tag = val; else if (r < 0) r = val; else if (g < 0) g = val; else if (b < 0) b = val; } } // Check everything is set if (b < 0) { LOG_MESSAGE(2, "Invalid Sector_SetFade parameters"); } else { sector_colour_t sc; sc.tag = tag; sc.colour.set(r, g, b, 0); LOG_MESSAGE(3, "Sector tag %d, fade colour %d,%d,%d", tag, r, g, b); sector_fadecolours.push_back(sc); } } tz.adv(); } } } tz.adv(); } }
// ---------------------------------------------------------------------------- // ParseTreeNode::parse // // Parses formatted text data. Current valid formatting is: // (type) child = value; // (type) child = value1, value2, ...; // (type) child = { value1, value2, ... } // (type) child { grandchild = value; etc... } // (type) child : inherited { ... } // // All values are read as strings, but can be retrieved as string, int, bool // or float. // ---------------------------------------------------------------------------- bool ParseTreeNode::parse(Tokenizer& tz) { // Keep parsing until final } is reached (or end of file) string name, type; while (!tz.atEnd() && tz.current() != '}') { // Check for preprocessor stuff if (parser_ && tz.current()[0] == '#') { if (!parsePreprocessor(tz)) return false; tz.advToNextLine(); continue; } // If it's a special character (ie not a valid name), parsing fails if (tz.isSpecialCharacter(tz.current().text[0])) { logError(tz, S_FMT("Unexpected special character '%s'", CHR(tz.current().text))); return false; } // So we have either a node or property name name = tz.current().text; type.Empty(); if (name.empty()) { logError(tz, "Unexpected empty string"); return false; } // Check for type+name pair if (tz.peek() != '=' && tz.peek() != '{' && tz.peek() != ';' && tz.peek() != ':') { type = name; name = tz.next().text; if (name.empty()) { logError(tz, "Unexpected empty string"); return false; } } //Log::debug(S_FMT("%s \"%s\", op %s", CHR(type), CHR(name), CHR(tz.current().text))); // Assignment if (tz.advIfNext('=', 2)) { if (!parseAssignment(tz, addChildPTN(name, type))) return false; } // Child node else if (tz.advIfNext('{', 2)) { // Parse child node if (!addChildPTN(name, type)->parse(tz)) return false; } // Child node (with no values/children) else if (tz.advIfNext(';', 2)) { // Add child node addChildPTN(name, type); continue; } // Child node + inheritance else if (tz.advIfNext(':', 2)) { // Check for opening brace if (tz.checkNext('{')) { // Add child node auto child = addChildPTN(name, type); child->inherit_ = tz.current().text; // Skip { tz.adv(2); // Parse child node if (!child->parse(tz)) return false; } else if (tz.checkNext(';')) // Empty child node { // Add child node auto child = addChildPTN(name, type); child->inherit_ = tz.current().text; // Skip ; tz.adv(2); continue; } else { logError(tz, S_FMT("Expecting \"{\" or \";\", got \"%s\"", CHR(tz.next().text))); return false; } } // Unexpected token else { logError(tz, S_FMT("Unexpected token \"%s\"", CHR(tz.next().text))); return false; } // Continue parsing tz.adv(); } // Success return true; }
// ----------------------------------------------------------------------------- // Parses ZMAPINFO-format definitions in [entry] // ----------------------------------------------------------------------------- bool MapInfo::parseZMapInfo(ArchiveEntry* entry) { Tokenizer tz; tz.setReadLowerCase(true); tz.openMem(entry->data(), entry->name()); while (!tz.atEnd()) { // Include if (tz.check("include")) { // Get entry at include path auto include_entry = entry->parent()->entryAtPath(tz.next().text); if (!include_entry) { Log::warning( "Warning - Parsing ZMapInfo \"{}\": Unable to include \"{}\" at line {}", entry->name(), tz.current().text, tz.lineNo()); } else if (!parseZMapInfo(include_entry)) return false; } // Map else if (tz.check("map") || tz.check("defaultmap") || tz.check("adddefaultmap")) { if (!parseZMap(tz, tz.current().text)) return false; } // DoomEdNums else if (tz.check("doomednums")) { if (!parseDoomEdNums(tz)) return false; } // Unknown block (skip it) else if (tz.check("{")) { Log::warning(2, "Warning - Parsing ZMapInfo \"{}\": Skipping {{}} block", entry->name()); tz.adv(); tz.skipSection("{", "}"); continue; } // Unknown else { Log::warning(2, R"(Warning - Parsing ZMapInfo "{}": Unknown token "{}")", entry->name(), tz.current().text); } tz.adv(); } Log::info(2, "Parsed ZMapInfo entry {} successfully", entry->name()); return true; } // ----------------------------------------------------------------------------- // Parses a ZMAPINFO map definition of [type] beginning at the current token in // tokenizer [tz] // ----------------------------------------------------------------------------- bool MapInfo::parseZMap(Tokenizer& tz, std::string_view type) { // TODO: Handle adddefaultmap auto map = default_map_; // Normal map, get lump/name/etc tz.adv(); if (type == "map") { // Entry name should be just after map keyword map.entry_name = tz.current().text; // Parse map name tz.adv(); if (tz.check("lookup")) { map.lookup_name = true; map.name = tz.next().text; } else { map.lookup_name = false; map.name = tz.current().text; } tz.adv(); } if (!tz.advIf("{")) { Log::error(R"(Error Parsing ZMapInfo: Expecting "{{", got "{}" at line {})", tz.current().text, tz.lineNo()); return false; } while (!tz.checkOrEnd("}")) { // Block (skip it) if (tz.advIf("{")) tz.skipSection("{", "}"); // LevelNum else if (tz.check("levelnum")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; // Parse number // TODO: Checks tz.next().toInt(map.level_num); } // Sky1 else if (tz.check("sky1")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; map.sky1 = tz.next().text; // Scroll speed // TODO: Checks if (tz.advIfNext(",")) tz.next().toFloat(map.sky1_scroll_speed); } // Sky2 else if (tz.check("sky2")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; map.sky2 = tz.next().text; // Scroll speed // TODO: Checks if (tz.advIfNext(",")) tz.next().toFloat(map.sky2_scroll_speed); } // Skybox else if (tz.check("skybox")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; map.sky1 = tz.next().text; } // DoubleSky else if (tz.check("doublesky")) map.sky_double = true; // ForceNoSkyStretch else if (tz.check("forcenoskystretch")) map.sky_force_no_stretch = true; // SkyStretch else if (tz.check("skystretch")) map.sky_stretch = true; // Fade else if (tz.check("fade")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; if (!strToCol(tz.next().text, map.fade)) return false; } // OutsideFog else if (tz.check("outsidefog")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; if (!strToCol(tz.next().text, map.fade_outside)) return false; } // EvenLighting else if (tz.check("evenlighting")) { map.lighting_wallshade_h = 0; map.lighting_wallshade_v = 0; } // SmoothLighting else if (tz.check("smoothlighting")) map.lighting_smooth = true; // VertWallShade else if (tz.check("vertwallshade")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; // TODO: Checks tz.next().toInt(map.lighting_wallshade_v); } // HorzWallShade else if (tz.check("horzwallshade")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; // TODO: Checks tz.next().toInt(map.lighting_wallshade_h); } // ForceFakeContrast else if (tz.check("forcefakecontrast")) map.force_fake_contrast = true; tz.adv(); }
/* JumpToCalculator::Entry * JumpToCalculator thread entry function *******************************************************************/ wxThread::ExitCode JumpToCalculator::Entry() { string jump_points; Tokenizer tz; tz.setSpecialCharacters(";,:|={}/()"); tz.openString(text); string token = tz.getToken(); while (!tz.atEnd()) { if (token == "{") { // Skip block while (!tz.atEnd() && token != "}") token = tz.getToken(); } for (unsigned a = 0; a < block_names.size(); a++) { // Get jump block keyword string block = block_names[a]; long skip = 0; if (block.Contains(":")) { wxArrayString sp = wxSplit(block, ':'); sp.back().ToLong(&skip); block = sp[0]; } if (S_CMPNOCASE(token, block)) { string name = tz.getToken(); for (int s = 0; s < skip; s++) name = tz.getToken(); for (unsigned i = 0; i < ignore.size(); ++i) if (S_CMPNOCASE(name, ignore[i])) name = tz.getToken(); // Numbered block, add block name if (name.IsNumber()) name = S_FMT("%s %s", block, name); // Unnamed block, use block name if (name == "{" || name == ";") name = block; // Add jump point jump_points += S_FMT("%d,%s,", tz.lineNo() - 1, CHR(name)); } } token = tz.getToken(); } // Remove ending comma if (!jump_points.empty()) jump_points.RemoveLast(1); // Send event wxThreadEvent* event = new wxThreadEvent(wxEVT_COMMAND_JTCALCULATOR_COMPLETED); event->SetString(jump_points); wxQueueEvent(handler, event); return nullptr; }
// ----------------------------------------------------------------------------- // Reads and parses the SLADE configuration file // ----------------------------------------------------------------------------- void readConfigFile() { // Open SLADE.cfg Tokenizer tz; if (!tz.openFile(App::path("slade3.cfg", App::Dir::User))) return; // Go through the file with the tokenizer while (!tz.atEnd()) { // If we come across a 'cvars' token, read in the cvars section if (tz.advIf("cvars", 2)) { // Keep reading name/value pairs until we hit the ending '}' while (!tz.checkOrEnd("}")) { CVar::set(tz.current().text, tz.peek().text); tz.adv(2); } tz.adv(); // Skip ending } } // Read base resource archive paths if (tz.advIf("base_resource_paths", 2)) { while (!tz.checkOrEnd("}")) { archive_manager.addBaseResourcePath(tz.current().text); tz.adv(); } tz.adv(); // Skip ending } } // Read recent files list if (tz.advIf("recent_files", 2)) { while (!tz.checkOrEnd("}")) { archive_manager.addRecentFile(tz.current().text); tz.adv(); } tz.adv(); // Skip ending } } // Read keybinds if (tz.advIf("keys", 2)) KeyBind::readBinds(tz); // Read nodebuilder paths if (tz.advIf("nodebuilder_paths", 2)) { while (!tz.checkOrEnd("}")) { NodeBuilders::addBuilderPath(tz.current().text, tz.peek().text); tz.adv(2); } tz.adv(); // Skip ending } } // Read game exe paths if (tz.advIf("executable_paths", 2)) { while (!tz.checkOrEnd("}")) { Executables::setGameExePath(tz.current().text, tz.peek().text); tz.adv(2); } tz.adv(); // Skip ending } } // Read window size/position info if (tz.advIf("window_info", 2)) Misc::readWindowInfo(tz); // Next token tz.adv(); } }
// ----------------------------------------------------------------------------- // Initialises the start page // ----------------------------------------------------------------------------- void SStartPage::init() { // wxWebView #ifdef USE_WEBVIEW_STARTPAGE html_startpage_ = wxWebView::New( this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxWebViewBackendDefault, wxBORDER_NONE); html_startpage_->SetZoomType(App::platform() == App::MacOS ? wxWEBVIEW_ZOOM_TYPE_TEXT : wxWEBVIEW_ZOOM_TYPE_LAYOUT); // wxHtmlWindow #else html_startpage_ = new wxHtmlWindow(this, -1, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER, "startpage"); #endif // Add to sizer GetSizer()->Add(html_startpage_, 1, wxEXPAND); // Bind events #ifdef USE_WEBVIEW_STARTPAGE html_startpage_->Bind(wxEVT_WEBVIEW_NAVIGATING, &SStartPage::onHTMLLinkClicked, this); html_startpage_->Bind( wxEVT_WEBVIEW_ERROR, [&](wxWebViewEvent& e) { Log::error(S_FMT("wxWebView Error: %s", CHR(e.GetString()))); }); if (App::platform() == App::Platform::Windows) { html_startpage_->Bind(wxEVT_WEBVIEW_LOADED, [&](wxWebViewEvent& e) { html_startpage_->Reload(); }); } Bind(wxEVT_THREAD_WEBGET_COMPLETED, [&](wxThreadEvent& e) { latest_news_ = e.GetString(); latest_news_.Trim(); if (latest_news_ == "connect_failed" || latest_news_.empty()) latest_news_ = "<center>Unable to load latest SLADE news</center>"; load(false); }); #else html_startpage_->Bind(wxEVT_COMMAND_HTML_LINK_CLICKED, &SStartPage::onHTMLLinkClicked, this); #endif // Get data used to build the page auto res_archive = App::archiveManager().programResourceArchive(); if (res_archive) { entry_base_html_ = res_archive->entryAtPath(App::useWebView() ? "html/startpage.htm" : "html/startpage_basic.htm"); entry_css_ = res_archive->entryAtPath(web_dark_theme ? "html/theme-dark.css" : "html/theme-light.css"); entry_export_.push_back(res_archive->entryAtPath("html/base.css")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Regular.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Italic.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Medium.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Bold.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Heavy.woff")); entry_export_.push_back(res_archive->entryAtPath("logo_icon.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/archive.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/wad.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/zip.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/folder.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/open.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/newarchive.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/newzip.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/mapeditor.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/wiki.png")); // Load tips auto entry_tips = res_archive->entryAtPath("tips.txt"); if (entry_tips) { Tokenizer tz; tz.openMem((const char*)entry_tips->getData(), entry_tips->getSize(), entry_tips->getName()); while (!tz.atEnd() && tz.peekToken() != "") tips_.push_back(tz.getToken()); } } }
// ----------------------------------------------------------------------------- // Parses a ZScript 'statement'. This isn't technically correct but suits our // purposes well enough // // tokens // { // block[0].tokens // { // block[0].block[0].tokens; // ... // } // // block[1].tokens; // ... // } // ----------------------------------------------------------------------------- bool ParsedStatement::parse(Tokenizer& tz) { // Check for unexpected token if (tz.check('}')) { tz.adv(); return false; } line = tz.lineNo(); // Tokens bool in_initializer = false; while (true) { // End of statement (;) if (tz.advIf(';')) return true; // DB comment if (tz.current().text.StartsWith(db_comment)) { tokens.push_back(tz.current().text); tokens.push_back(tz.getLine()); return true; } if (tz.check('}')) { // End of array initializer if (in_initializer) { in_initializer = false; tokens.emplace_back("}"); tz.adv(); continue; } // End of statement return true; } if (tz.atEnd()) { Log::debug(S_FMT("Failed parsing zscript statement/block beginning line %u", line)); return false; } // Beginning of block if (tz.advIf('{')) break; // Array initializer: ... = { ... } if (tz.current().text.Cmp("=") == 0 && tz.peek() == '{') { tokens.emplace_back("="); tokens.emplace_back("{"); tz.adv(2); in_initializer = true; continue; } tokens.push_back(tz.current().text); tz.adv(); } // Block while (true) { if (tz.advIf('}')) return true; if (tz.atEnd()) { Log::debug(S_FMT("Failed parsing zscript statement/block beginning line %u", line)); return false; } block.push_back({}); block.back().entry = entry; if (!block.back().parse(tz) || block.back().tokens.empty()) block.pop_back(); } }
// ----------------------------------------------------------------------------- // Reads in a ZDoom-format TEXTURES entry. // Returns true on success, false otherwise // ----------------------------------------------------------------------------- bool TextureXList::readTEXTURESData(ArchiveEntry* textures) { // Check for empty entry if (!textures) { Global::error = "Attempt to read texture data from NULL entry"; return false; } if (textures->size() == 0) { txformat_ = Format::Textures; return true; } // Get text to parse Tokenizer tz; tz.openMem(textures->data(), textures->name()); // Parsing gogo while (!tz.atEnd()) { // Texture definition if (tz.checkNC("Texture")) { auto tex = std::make_unique<CTexture>(); if (tex->parse(tz, "Texture")) addTexture(std::move(tex)); } // Sprite definition else if (tz.checkNC("Sprite")) { auto tex = std::make_unique<CTexture>(); if (tex->parse(tz, "Sprite")) addTexture(std::move(tex)); } // Graphic definition else if (tz.checkNC("Graphic")) { auto tex = std::make_unique<CTexture>(); if (tex->parse(tz, "Graphic")) addTexture(std::move(tex)); } // WallTexture definition else if (tz.checkNC("WallTexture")) { auto tex = std::make_unique<CTexture>(); if (tex->parse(tz, "WallTexture")) addTexture(std::move(tex)); } // Flat definition else if (tz.checkNC("Flat")) { auto tex = std::make_unique<CTexture>(); if (tex->parse(tz, "Flat")) addTexture(std::move(tex)); } // Old HIRESTEX "Define" else if (tz.checkNC("Define")) { auto tex = std::make_unique<CTexture>(); if (tex->parseDefine(tz)) addTexture(std::move(tex)); } tz.adv(); } txformat_ = Format::Textures; return true; }