/* SCallTip::loadArgSet * Opens and displays the arg set [set] from the current function *******************************************************************/ void SCallTip::loadArgSet(int set) { args.clear(); if (!function->getArgSet(set).empty()) { Tokenizer tz; tz.setSpecialCharacters("[],"); tz.openString(function->getArgSet(set)); string token = tz.getToken(); vector<string> tokens; while (true) { tokens.push_back(token); string next = tz.peekToken(); if (next == "," || next == "") { addArg(tokens); tokens.clear(); tz.getToken(); } if (next == "") break; token = tz.getToken(); } } updateSize(); Update(); Refresh(); }
// ----------------------------------------------------------------------------- // 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); }
/* WadArchive::detectIncludes * Parses the DECORATE, GLDEFS, etc. lumps for included files, and * mark them as being of the same type *******************************************************************/ void WadArchive::detectIncludes() { // DECORATE: #include "lumpname" // GLDEFS: #include "lumpname" // SBARINFO: #include "lumpname" // ZMAPINFO: translator = "lumpname" // EMAPINFO: extradata = lumpname // EDFROOT: lumpinclude("lumpname") const char * lumptypes[6] = { "DECORATE", "GLDEFS", "SBARINFO", "ZMAPINFO", "EMAPINFO", "EDFROOT" }; const char * entrytypes[6] = { "decorate", "gldefslump", "sbarinfo", "xlat", "extradata", "edf" }; const char * tokens[6] = { "#include", "#include", "#include", "translator", "extradata", "lumpinclude" }; Archive::search_options_t opt; opt.ignore_ext = true; Tokenizer tz; tz.setSpecialCharacters(";,:|={}/()"); for (int i = 0; i < 6; ++i) { opt.match_name = lumptypes[i]; vector<ArchiveEntry*> entries = findAll(opt); if (entries.size()) { for (size_t j = 0; j < entries.size(); ++j) { tz.openMem(&entries[j]->getMCData(), lumptypes[i]); string token = tz.getToken(); while (token.length()) { if (token.Lower() == tokens[i]) { if (i >= 3) // skip '=' or '(' tz.getToken(); string name = tz.getToken(); if (i == 5) // skip ')' tz.getToken(); opt.match_name = name; ArchiveEntry * entry = findFirst(opt); if (entry) entry->setType(EntryType::getType(entrytypes[i])); } else tz.skipLineComment(); token = tz.getToken(); } } } } }
/* Translation::parse * Parses a text definition [def] (in zdoom format, detailed here: * http://zdoom.org/wiki/Translation) *******************************************************************/ void Translation::parse(string def) { // Open definition string for processing w/tokenizer Tokenizer tz; tz.setSpecialCharacters("[]:%,="); tz.openString(def); //wxLogMessage("Parse translation \"%s\"", CHR(def)); // Read original range uint8_t o_start, o_end; o_start = tz.getInteger(); if (tz.peekToken() == "=") o_end = o_start; else if (!tz.checkToken(":")) return; else o_end = tz.getInteger(); if (!tz.checkToken("=")) return; // Check for reverse origin range bool reverse = (o_start > o_end); // Type of translation depends on next token if (tz.peekToken() == "[") { // Colour translation rgba_t start, end; tz.getToken(); // Skip [ // Read start colour start.r = tz.getInteger(); if (!tz.checkToken(",")) return; start.g = tz.getInteger(); if (!tz.checkToken(",")) return; start.b = tz.getInteger(); if (!tz.checkToken("]")) return; if (!tz.checkToken(":")) return; if (!tz.checkToken("[")) return; // Read end colour end.r = tz.getInteger(); if (!tz.checkToken(",")) return; end.g = tz.getInteger(); if (!tz.checkToken(",")) return; end.b = tz.getInteger(); if (!tz.checkToken("]")) return; // Add translation TransRangeColour* tr = new TransRangeColour(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_start.set(end); tr->d_end.set(start); } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_start.set(start); tr->d_end.set(end); } translations.push_back(tr); //wxLogMessage("Added colour translation"); } else if (tz.peekToken() == "%") { // Desat colour translation float sr, sg, sb, er, eg, eb; tz.getToken(); // Skip % if (!tz.checkToken("[")) return; // Read start colour sr = tz.getFloat(); if (!tz.checkToken(",")) return; sg = tz.getFloat(); if (!tz.checkToken(",")) return; sb = tz.getFloat(); if (!tz.checkToken("]")) return; if (!tz.checkToken(":")) return; if (!tz.checkToken("[")) return; // Read end colour er = tz.getFloat(); if (!tz.checkToken(",")) return; eg = tz.getFloat(); if (!tz.checkToken(",")) return; eb = tz.getFloat(); if (!tz.checkToken("]")) return; // Add translation TransRangeDesat* tr = new TransRangeDesat(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_sr = er; tr->d_sg = eg; tr->d_sb = eb; tr->d_er = sr; tr->d_eg = sg; tr->d_eb = sb; } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_sr = sr; tr->d_sg = sg; tr->d_sb = sb; tr->d_er = er; tr->d_eg = eg; tr->d_eb = eb; } translations.push_back(tr); //wxLogMessage("Added desat translation"); } else { // Palette range translation uint8_t d_start, d_end; // Read range values d_start = tz.getInteger(); if (!tz.checkToken(":")) d_end = d_start; else d_end = tz.getInteger(); // Add translation TransRangePalette* tr = new TransRangePalette(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_start = d_end; tr->d_end = d_start; } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_start = d_start; tr->d_end = d_end; } translations.push_back(tr); //wxLogMessage("Added range translation"); } }
// ---------------------------------------------------------------------------- // 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(); } }
void ArchiveOperations::removeUnusedFlats(Archive* archive) { // Check archive was given if (!archive) return; // --- Build list of used flats --- TexUsedMap used_textures; int total_maps = 0; // Get all SECTORS entries Archive::SearchOptions opt; opt.match_type = EntryType::fromId("map_sectors"); auto sectors = archive->findAll(opt); total_maps += sectors.size(); // Go through and add used flats to list DoomMapFormat::Sector sec; wxString tex_floor, tex_ceil; for (auto& sector : sectors) { int nsec = sector->size() / 26; sector->seek(0, SEEK_SET); for (int s = 0; s < nsec; s++) { // Read sector data sector->read(&sec, 26); // Get textures tex_floor = wxString::FromAscii(sec.f_tex, 8); tex_ceil = wxString::FromAscii(sec.c_tex, 8); // Add to used textures list used_textures[tex_floor].used = true; used_textures[tex_ceil].used = true; } } // Get all TEXTMAP entries opt.match_name = "TEXTMAP"; opt.match_type = EntryType::fromId("udmf_textmap"); auto udmfmaps = archive->findAll(opt); total_maps += udmfmaps.size(); // Go through and add used flats to list Tokenizer tz; tz.setSpecialCharacters("{};="); for (auto& udmfmap : udmfmaps) { // Open in tokenizer tz.openMem(udmfmap->data(), "UDMF TEXTMAP"); // Go through text tokens wxString token = tz.getToken(); while (!token.IsEmpty()) { // Check for sector definition if (token == "sector") { tz.getToken(); // Skip { token = tz.getToken(); while (token != "}") { // Check for texture property if (token == "texturefloor" || token == "textureceiling") { tz.getToken(); // Skip = used_textures[tz.getToken()].used = true; } token = tz.getToken(); } } // Next token token = tz.getToken(); } } // Check if any maps were found if (total_maps == 0) return; // Find all flats opt.match_name = ""; opt.match_namespace = "flats"; opt.match_type = nullptr; auto flats = archive->findAll(opt); // Create list of all unused flats wxArrayString unused_tex; bool anim = false; for (auto& flat : flats) { // Skip markers if (flat->size() == 0) continue; // Check for animation start string flatname{ flat->nameNoExt() }; for (int b = 0; b < n_flat_anim; b++) { if (flatname == flat_anim_start[b]) { anim = true; Log::info(wxString::Format("%s anim start", flatname)); break; } } // Check for animation end bool thisend = false; for (int b = 0; b < n_flat_anim; b++) { if (flatname == flat_anim_end[b]) { anim = false; thisend = true; Log::info(wxString::Format("%s anim end", flatname)); break; } } // Add if not animated if (!used_textures[flatname].used && !anim && !thisend) unused_tex.Add(flatname); } // Pop up a dialog with a checkbox list of unused textures wxMultiChoiceDialog dialog( theMainWindow, "The following textures are not used in any map,\nselect which textures to delete", "Delete Unused Textures", unused_tex); // Select all flats initially wxArrayInt selection; for (unsigned a = 0; a < unused_tex.size(); a++) selection.push_back(a); dialog.SetSelections(selection); int n_removed = 0; if (dialog.ShowModal() == wxID_OK) { // Go through selected flats selection = dialog.GetSelections(); opt.match_namespace = "flats"; for (int i : selection) { opt.match_name = unused_tex[i]; ArchiveEntry* entry = archive->findFirst(opt); archive->removeEntry(entry); n_removed++; } } wxMessageBox(wxString::Format("Removed %d unused flats", n_removed)); }
void ArchiveOperations::removeUnusedTextures(Archive* archive) { // Check archive was given if (!archive) return; // --- Build list of used textures --- TexUsedMap used_textures; int total_maps = 0; // Get all SIDEDEFS entries Archive::SearchOptions opt; opt.match_type = EntryType::fromId("map_sidedefs"); auto sidedefs = archive->findAll(opt); total_maps += sidedefs.size(); // Go through and add used textures to list DoomMapFormat::SideDef sdef; wxString tex_lower, tex_middle, tex_upper; for (auto& sidedef : sidedefs) { int nsides = sidedef->size() / 30; sidedef->seek(0, SEEK_SET); for (int s = 0; s < nsides; s++) { // Read side data sidedef->read(&sdef, 30); // Get textures tex_lower = wxString::FromAscii(sdef.tex_lower, 8); tex_middle = wxString::FromAscii(sdef.tex_middle, 8); tex_upper = wxString::FromAscii(sdef.tex_upper, 8); // Add to used textures list used_textures[tex_lower].used = true; used_textures[tex_middle].used = true; used_textures[tex_upper].used = true; } } // Get all TEXTMAP entries opt.match_name = "TEXTMAP"; opt.match_type = EntryType::fromId("udmf_textmap"); auto udmfmaps = archive->findAll(opt); total_maps += udmfmaps.size(); // Go through and add used textures to list Tokenizer tz; tz.setSpecialCharacters("{};="); for (auto& udmfmap : udmfmaps) { // Open in tokenizer tz.openMem(udmfmap->data(), "UDMF TEXTMAP"); // Go through text tokens wxString token = tz.getToken(); while (!token.IsEmpty()) { // Check for sidedef definition if (token == "sidedef") { tz.getToken(); // Skip { token = tz.getToken(); while (token != "}") { // Check for texture property if (token == "texturetop" || token == "texturemiddle" || token == "texturebottom") { tz.getToken(); // Skip = used_textures[tz.getToken()].used = true; } token = tz.getToken(); } } // Next token token = tz.getToken(); } } // Check if any maps were found if (total_maps == 0) return; // Find all TEXTUREx entries opt.match_name = ""; opt.match_type = EntryType::fromId("texturex"); auto tx_entries = archive->findAll(opt); // Go through texture lists PatchTable ptable; // Dummy patch table, patch info not needed here wxArrayString unused_tex; for (auto& tx_entrie : tx_entries) { TextureXList txlist; txlist.readTEXTUREXData(tx_entrie, ptable); // Go through textures bool anim = false; for (unsigned t = 1; t < txlist.size(); t++) { wxString texname = txlist.texture(t)->name(); // Check for animation start for (int b = 0; b < n_tex_anim; b++) { if (texname == tex_anim_start[b]) { anim = true; break; } } // Check for animation end bool thisend = false; for (int b = 0; b < n_tex_anim; b++) { if (texname == tex_anim_end[b]) { anim = false; thisend = true; break; } } // Mark if unused and not part of an animation if (!used_textures[texname].used && !anim && !thisend) unused_tex.Add(txlist.texture(t)->name()); } } // Pop up a dialog with a checkbox list of unused textures wxMultiChoiceDialog dialog( theMainWindow, "The following textures are not used in any map,\nselect which textures to delete", "Delete Unused Textures", unused_tex); // Get base resource textures (if any) auto base_resource = App::archiveManager().baseResourceArchive(); vector<ArchiveEntry*> base_tx_entries; if (base_resource) base_tx_entries = base_resource->findAll(opt); PatchTable pt_temp; TextureXList tx; for (auto& texturex : base_tx_entries) tx.readTEXTUREXData(texturex, pt_temp, true); vector<wxString> base_resource_textures; for (unsigned a = 0; a < tx.size(); a++) base_resource_textures.push_back(tx.texture(a)->name()); // Determine which textures to check initially wxArrayInt selection; for (unsigned a = 0; a < unused_tex.size(); a++) { bool swtex = false; // Check for switch texture if (unused_tex[a].StartsWith("SW1")) { // Get counterpart switch name wxString swname = unused_tex[a]; swname.Replace("SW1", "SW2", false); // Check if its counterpart is used if (used_textures[swname].used) swtex = true; } else if (unused_tex[a].StartsWith("SW2")) { // Get counterpart switch name wxString swname = unused_tex[a]; swname.Replace("SW2", "SW1", false); // Check if its counterpart is used if (used_textures[swname].used) swtex = true; } // Check for base resource texture bool br_tex = false; for (auto& texture : base_resource_textures) { if (texture.CmpNoCase(unused_tex[a]) == 0) { Log::info(3, "Texture " + texture + " is in base resource"); br_tex = true; break; } } if (!swtex && !br_tex) selection.Add(a); } dialog.SetSelections(selection); int n_removed = 0; if (dialog.ShowModal() == wxID_OK) { // Get selected textures selection = dialog.GetSelections(); // Go through texture lists for (auto& entry : tx_entries) { TextureXList txlist; txlist.readTEXTUREXData(entry, ptable); // Go through selected textures to delete for (int i : selection) { // Get texture index int index = txlist.textureIndex(WxUtils::strToView(unused_tex[i])); // Delete it from the list (if found) if (index >= 0) { txlist.removeTexture(index); n_removed++; } } // Write texture list data back to entry txlist.writeTEXTUREXData(entry, ptable); } } wxMessageBox(wxString::Format("Removed %d unused textures", n_removed)); }
/* 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; }