From c7af11702f340ac5d5a90aee2665a890f3256edf Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Sat, 28 Oct 2023 18:17:53 +0800 Subject: [PATCH] add some features in Unvirt - add style [simple | full] command to allow simple display. current object list display take too much space. - add search [obj | mgr] [plain | re] command to allow user search object or manager list by substring or regex. - add ls search to browse the search result. - set IronPad minidump dump type from full memory to normal. - fix Unvirt ls command page count display error. --- IronPad/IronPad.cpp | 2 +- Unvirt/StructFormatter.cpp | 186 +++++++++++++++++++++++++--------- Unvirt/StructFormatter.hpp | 20 +++- Unvirt/UnvirtContext.cpp | 197 ++++++++++++++++++++++++++++++++++--- Unvirt/UnvirtContext.hpp | 11 ++- 5 files changed, 349 insertions(+), 67 deletions(-) diff --git a/IronPad/IronPad.cpp b/IronPad/IronPad.cpp index dd4aeff..7741266 100644 --- a/IronPad/IronPad.cpp +++ b/IronPad/IronPad.cpp @@ -204,7 +204,7 @@ namespace IronPad { exception_info.ClientPointers = TRUE; MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, - MiniDumpWithFullMemory, + MiniDumpNormal, &exception_info, NULL, NULL ); diff --git a/Unvirt/StructFormatter.cpp b/Unvirt/StructFormatter.cpp index ca7dc61..2f8a415 100644 --- a/Unvirt/StructFormatter.cpp +++ b/Unvirt/StructFormatter.cpp @@ -7,8 +7,6 @@ namespace Unvirt::StructFormatter { #pragma region Assist Functions -#define PRIuSIZET "zu" - static void PrintCKSTRING(LibCmo::CKSTRING name) { if (name == nullptr) { fputs(UNVIRT_TERMCOL_LIGHT_MAGENTA(("")), stdout); @@ -39,6 +37,9 @@ namespace Unvirt::StructFormatter { static void PrintBool(bool v) { fputs(v ? "true" : "false", stdout); } + static void PrintColorfulBool(bool v) { + fputs(v ? UNVIRT_TERMCOL_LIGHT_GREEN(("Yes")) : UNVIRT_TERMCOL_LIGHT_RED(("No")), stdout); + } static void PrintColor(const LibCmo::VxMath::VxColor& col) { LibCmo::CKDWORD argb = col.ToARGB(); LibCmo::CKDWORD a = (argb & 0xFF000000) >> 24, @@ -46,9 +47,9 @@ namespace Unvirt::StructFormatter { g = (argb & 0x0000FF00) >> 8, b = (argb & 0x000000FF); fprintf(stdout, "A:%" PRIuCKDWORD " (%.4" PRIfCKFLOAT ") RGB(%" PRIuCKDWORD ", %" PRIuCKDWORD ", %" PRIuCKDWORD ") RGB#%02" PRIxCKDWORD "%02" PRIxCKDWORD "%02" PRIxCKDWORD " RGBA#%02" PRIxCKDWORD "%02" PRIxCKDWORD "%02" PRIxCKDWORD "%02" PRIxCKDWORD, - a, col.a, - r, g, b, - r, g, b, + a, col.a, + r, g, b, + r, g, b, r, g, b, a ); } @@ -61,9 +62,16 @@ namespace Unvirt::StructFormatter { const std::vector<_Ty>& data, size_t page, size_t pageitems, std::function printHdrFct, std::function printEntryFct) { + // check page overflow + if (page * pageitems >= data.size()) { + fputs(UNVIRT_TERMCOL_LIGHT_RED(("Page out of range.\n")), stdout); + return; + } + + // calc page data size_t fulllen = data.size(), startpos = page * pageitems, - fullpage = fulllen / pageitems; + fullpage = (fulllen + (pageitems - 1)) / pageitems; // to solve `fulllen / pageitems` empty page issue. like CKStateChunk::GetCeilDwordSize function (+3 /4 to get DWORD size). // print header printHdrFct(); @@ -73,7 +81,7 @@ namespace Unvirt::StructFormatter { printEntryFct(counter, data[counter]); } - fprintf(stdout, "Page %" PRIuSIZET " of %" PRIuSIZET "\n", page + 1, fullpage + 1); + fprintf(stdout, "Page %" PRIuSIZET " of %" PRIuSIZET "\n", page + 1, fullpage); } #pragma endregion @@ -214,7 +222,7 @@ namespace Unvirt::StructFormatter { fputs("Transparent Color: ", stdout); PrintColor(bd.GetTransparentColor()); fputc('\n', stdout); - + fputs("Bitmap Flags:\n", stdout); fputs(AccessibleValue::GetFlagEnumName(bd.GetBitmapFlags(), AccessibleValue::EnumDesc::CK_BITMAPDATA_FLAGS, "\n").c_str(), stdout); fputc('\n', stdout); @@ -223,7 +231,7 @@ namespace Unvirt::StructFormatter { static void PrintCKMaterialDetail(LibCmo::CK2::ObjImpls::CKMaterial* obj) { PrintCKBeObjectDetail(obj); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMaterial\n")), stdout); - + // color fputs("== Color ==\n", stdout); @@ -278,7 +286,7 @@ namespace Unvirt::StructFormatter { fputc('\n', stdout); fprintf(stdout, "Alpha Function: %s\n", AccessibleValue::GetEnumName(obj->GetAlphaFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str()); fprintf(stdout, "Alpha Ref Value: %" PRIuCKBYTE "\n", obj->GetAlphaRef()); - + // alpha blend fputs("== Alpha Blend ==\n", stdout); fputs("Enabled: ", stdout); @@ -286,14 +294,14 @@ namespace Unvirt::StructFormatter { fputc('\n', stdout); fprintf(stdout, "Source Blend: %s\n", AccessibleValue::GetEnumName(obj->GetSourceBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str()); fprintf(stdout, "Destination Blend: %s\n", AccessibleValue::GetEnumName(obj->GetDestBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str()); - + // z buffer fputs("== Z-Buffer Write ==\n", stdout); fputs("Enabled: ", stdout); PrintBool(obj->GetZWriteEnabled()); fputc('\n', stdout); fprintf(stdout, "Z Compare Function: %s\n", AccessibleValue::GetEnumName(obj->GetZFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str()); - + // effect fputs("== Effect ==\n", stdout); fprintf(stdout, "Effect: %s\n", AccessibleValue::GetEnumName(obj->GetEffect(), AccessibleValue::EnumDesc::VX_EFFECT).c_str()); @@ -303,12 +311,12 @@ namespace Unvirt::StructFormatter { static void PrintCKMeshDetail(LibCmo::CK2::ObjImpls::CKMesh* obj) { PrintCKBeObjectDetail(obj); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMesh\n")), stdout); - + fputs("== Flags ==\n", stdout); fputs("Mesh Flags:\n", stdout); fputs(AccessibleValue::GetFlagEnumName(obj->GetMeshFlags(), AccessibleValue::EnumDesc::VXMESH_FLAGS, "\n").c_str(), stdout); fputc('\n', stdout); - + // vertex data fputs("== Vertex ==\n", stdout); fprintf(stdout, "Vertex Count: %" PRIuCKDWORD "\n", obj->GetVertexCount()); @@ -324,7 +332,7 @@ namespace Unvirt::StructFormatter { fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\tColors\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)); PrintPointer(obj->GetVertexSpecularColors()); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\tSpecularColors\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)); - + // face data fputs("== Face ==\n", stdout); fprintf(stdout, "Face Count: %" PRIuCKDWORD "\n", obj->GetFaceCount()); @@ -403,64 +411,142 @@ namespace Unvirt::StructFormatter { } +#pragma region Object List Printer + + static void PrintObjectListHeader(bool full_detail) { + if (full_detail) { + fputs("SaveFlags\tOptions\tCK ID\tFile CK ID\tFile Index\tPack Size\tIndex\tType\tCKObject\tCKStateChunk\tName\n", stdout); + } else { + fputs("Index\tType\tObject\tChunk\tName\n", stdout); + } + } + static void PrintObjectListEntry(const LibCmo::CK2::CKFileObject& obj, const LibCmo::CK2::CKFileInfo& fileinfo, size_t entry_index, bool full_detail) { + if (full_detail) { + fprintf(stdout, "0x%08" PRIxCKDWORD "\t", obj.SaveFlags); + fputs(AccessibleValue::GetEnumName(obj.Options, AccessibleValue::EnumDesc::CK_FO_OPTIONS).c_str(), stdout); + fputc('\t', stdout); + + fprintf(stdout, "%" PRIuCKID "\t", obj.CreatedObjectId); + fprintf(stdout, "%" PRIuCKID "\t", obj.ObjectId); + + fprintf(stdout, "0x%08" PRIxCKDWORD " (Rel: 0x%08" PRIxCKDWORD ")\t", + obj.FileIndex, + obj.FileIndex - CKSizeof(LibCmo::CK2::CKRawFileInfo) - fileinfo.Hdr1UnPackSize); + fprintf(stdout, "0x%08" PRIxCKDWORD "\t", obj.PackSize); + + fprintf(stdout, "#%" PRIuSIZET "\t", entry_index); + fputs(AccessibleValue::GetClassIdName(obj.ObjectCid).c_str(), stdout); + fputc('\t', stdout); + PrintPointer(obj.ObjPtr); + fputc('\t', stdout); + PrintPointer(obj.Data); + fputc('\t', stdout); + PrintCKSTRING(LibCmo::XContainer::NSXString::ToCKSTRING(obj.Name)); + fputc('\n', stdout); + } else { + fprintf(stdout, "#%" PRIuSIZET "\t", entry_index); + fputs(AccessibleValue::GetClassIdName(obj.ObjectCid).c_str(), stdout); + fputc('\t', stdout); + PrintColorfulBool(obj.ObjPtr != nullptr); + fputc('\t', stdout); + PrintColorfulBool(obj.Data != nullptr); + fputc('\t', stdout); + PrintCKSTRING(LibCmo::XContainer::NSXString::ToCKSTRING(obj.Name)); + fputc('\n', stdout); + } + } void PrintObjectList( const LibCmo::XContainer::XArray& ls, const LibCmo::CK2::CKFileInfo& fileinfo, - size_t page, size_t pageitems) { + size_t page, size_t pageitems, + bool full_detail) { fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileObject\n")), stdout); GeneralPrintList(ls, page, pageitems, - []() -> void { - fputs("SaveFlags\tOptions\tCK ID\tFile CK ID\tFile Index\tPack Size\tIndex\tType\tCKObject\tCKStateChunk\tName\n", stdout); + [full_detail]() -> void { + PrintObjectListHeader(full_detail); }, - [&fileinfo](size_t index, const LibCmo::CK2::CKFileObject& obj) -> void { - fprintf(stdout, "0x%08" PRIxCKDWORD "\t", obj.SaveFlags); - fputs(AccessibleValue::GetEnumName(obj.Options, AccessibleValue::EnumDesc::CK_FO_OPTIONS).c_str(), stdout); - fputc('\t', stdout); - - fprintf(stdout, "%" PRIuCKID "\t", obj.CreatedObjectId); - fprintf(stdout, "%" PRIuCKID "\t", obj.ObjectId); - - fprintf(stdout, "0x%08" PRIxCKDWORD " (Rel: 0x%08" PRIxCKDWORD ")\t", - obj.FileIndex, - obj.FileIndex - CKSizeof(LibCmo::CK2::CKRawFileInfo) - fileinfo.Hdr1UnPackSize); - fprintf(stdout, "0x%08" PRIxCKDWORD "\t", obj.PackSize); - - fprintf(stdout, "#%" PRIuSIZET "\t", index); - fputs(AccessibleValue::GetClassIdName(obj.ObjectCid).c_str(), stdout); - fputc('\t', stdout); - PrintPointer(obj.ObjPtr); - fputc('\t', stdout); - PrintPointer(obj.Data); - fputc('\t', stdout); - PrintCKSTRING(LibCmo::XContainer::NSXString::ToCKSTRING(obj.Name)); - fputc('\n', stdout); + [&fileinfo, full_detail](size_t index, const LibCmo::CK2::CKFileObject& obj) -> void { + PrintObjectListEntry(obj, fileinfo, index, full_detail); } ); } + void PrintSearchedObjectList( + const LibCmo::XContainer::XArray& idxls, + const LibCmo::XContainer::XArray& ls, + const LibCmo::CK2::CKFileInfo& fileinfo, + size_t page, size_t pageitems, + bool full_detail) { + + fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileObject Searching Result\n")), stdout); + GeneralPrintList(idxls, page, pageitems, + [full_detail]() -> void { + PrintObjectListHeader(full_detail); + }, + [&ls, &fileinfo, full_detail](size_t, const size_t& index_to_obj) -> void { + // resolve index to real item. + // and pass the entry index, not the page index. + PrintObjectListEntry(ls[index_to_obj], fileinfo, index_to_obj, full_detail); + } + ); + } + +#pragma endregion + +#pragma region Manager List Printer + + static void PrintManagerListHeader(bool full_detail) { + // manager list now do not affected by list style because it is enough short + fputs("Index\tCKGUID\tCKStateChunk\n", stdout); + } + static void PrintManagerListEntry(const LibCmo::CK2::CKFileManagerData& mgr, size_t entry_index, bool full_detail) { + // not affected by list style. + fprintf(stdout, "#%" PRIuSIZET "\t", entry_index); + PrintCKGUID(mgr.Manager); + fputc('\t', stdout); + PrintPointer(mgr.Data); + fputc('\n', stdout); + } void PrintManagerList( const LibCmo::XContainer::XArray& ls, - size_t page, size_t pageitems) { + size_t page, size_t pageitems, + bool full_detail) { fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileManager\n")), stdout); GeneralPrintList(ls, page, pageitems, - []() -> void { + [full_detail]() -> void { // print header - fputs("Index\tCKGUID\tCKStateChunk\n", stdout); + PrintManagerListHeader(full_detail); }, - [](size_t index, const LibCmo::CK2::CKFileManagerData& mgr) -> void { + [full_detail](size_t index, const LibCmo::CK2::CKFileManagerData& mgr) -> void { // print body - fprintf(stdout, "#%" PRIuSIZET "\t", index); - PrintCKGUID(mgr.Manager); - fputc('\t', stdout); - PrintPointer(mgr.Data); - fputc('\n', stdout); + PrintManagerListEntry(mgr, index, full_detail); } ); } + void PrintSearchedManagerList( + const LibCmo::XContainer::XArray& idxls, + const LibCmo::XContainer::XArray& ls, + size_t page, size_t pageitems, + bool full_detail) { + + fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileManager Searching Result\n")), stdout); + GeneralPrintList(idxls, page, pageitems, + [full_detail]() -> void { + PrintManagerListHeader(full_detail); + }, + [&ls, full_detail](size_t, const size_t& index_to_mgr) -> void { + // resolve index to real one + PrintManagerListEntry(ls[index_to_mgr], index_to_mgr, full_detail); + } + ); + + } + +#pragma endregion void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject* obj) { if (obj == nullptr) { @@ -506,6 +592,7 @@ namespace Unvirt::StructFormatter { } } + void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager* mgr) { fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKBaseManager\n")), stdout); if (mgr == nullptr) { @@ -515,6 +602,7 @@ namespace Unvirt::StructFormatter { fputs(UNVIRT_TERMCOL_LIGHT_RED(("Not Implemented.\n")), stdout); } + void PrintCKStateChunk(const LibCmo::CK2::CKStateChunk* chunk) { fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKStateChunk\n")), stdout); if (chunk == nullptr) { diff --git a/Unvirt/StructFormatter.hpp b/Unvirt/StructFormatter.hpp index e3dd6e9..d93a4b4 100644 --- a/Unvirt/StructFormatter.hpp +++ b/Unvirt/StructFormatter.hpp @@ -4,16 +4,32 @@ #include namespace Unvirt::StructFormatter { + +#define PRIuSIZET "zu" void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo); void PrintObjectList( const LibCmo::XContainer::XArray& ls, const LibCmo::CK2::CKFileInfo& fileinfo, - size_t page, size_t pageitems); + size_t page, size_t pageitems, + bool full_detail); + void PrintSearchedObjectList( + const LibCmo::XContainer::XArray& idxls, + const LibCmo::XContainer::XArray& ls, + const LibCmo::CK2::CKFileInfo& fileinfo, + size_t page, size_t pageitems, + bool full_detail); + void PrintManagerList( const LibCmo::XContainer::XArray& ls, - size_t page, size_t pageitems); + size_t page, size_t pageitems, + bool full_detail); + void PrintSearchedManagerList( + const LibCmo::XContainer::XArray& idxls, + const LibCmo::XContainer::XArray& ls, + size_t page, size_t pageitems, + bool full_detail); void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject*); void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager*); diff --git a/Unvirt/UnvirtContext.cpp b/Unvirt/UnvirtContext.cpp index 9d33350..3f1809c 100644 --- a/Unvirt/UnvirtContext.cpp +++ b/Unvirt/UnvirtContext.cpp @@ -1,6 +1,7 @@ #include "UnvirtContext.hpp" #include #include +#include namespace Unvirt::Context { @@ -8,7 +9,8 @@ namespace Unvirt::Context { UnvirtContext::UnvirtContext() : m_Root(), m_Splitter(), m_Help(nullptr), - m_PageLen(10u), m_OrderExit(false), + m_PageLen(10u), m_ListStyleIsFull(true), m_OrderExit(false), + m_SearchPart(SearchPart::None), m_SearchIdxResult(), m_Ctx(nullptr), m_FileReader(nullptr), m_IsShallowRead(true) { // create command root @@ -49,7 +51,7 @@ namespace Unvirt::Context { ) ) ->Then((new CmdHelper::Literal("ls")) - ->Then((new CmdHelper::Choice("part", { "obj", "mgr"})) + ->Then((new CmdHelper::Choice("part", { "obj", "mgr", "search"})) ->Comment("Which list you want to list.") ->Then((new CmdHelper::IntArgument("page", [](int32_t v) -> bool { return v > 0; })) ->Comment("The page index. Start with 1.") @@ -84,6 +86,21 @@ namespace Unvirt::Context { ) ) ) + ->Then((new CmdHelper::Literal("search")) + ->Then((new CmdHelper::Choice("part", { "obj", "mgr"})) + ->Comment("Which list you want to search.") + ->Then((new CmdHelper::Choice("mode", { "plain", "re"})) + ->Comment("The search mode. `plain` will search by substring and `re` will do regex search.") + ->Then((new CmdHelper::StringArgument("text")) + ->Comment("The text or regex to search.") + ->Executes( + std::bind(&UnvirtContext::ProcSearch, this, std::placeholders::_1), + "Search object or manager by text or regex. Please note that the regex have limited UTF8 support and may cause undefined behavior." + ) + ) + ) + ) + ) ->Then((new CmdHelper::Literal("items")) ->Then((new CmdHelper::IntArgument("count", [](int32_t v) -> bool { return v > 0; })) ->Comment("The count of items you want to show in one page.") @@ -93,6 +110,15 @@ namespace Unvirt::Context { ) ) ) + ->Then((new CmdHelper::Literal("style")) + ->Then((new CmdHelper::Choice("level", { "full", "simple"})) + ->Comment("The amount of showen content.") + ->Executes( + std::bind(&UnvirtContext::ProcStyle, this, std::placeholders::_1), + "Change the detail level of showen data in `ls` command." + ) + ) + ) ->Then((new CmdHelper::Literal("encoding")) ->Then((new CmdHelper::EncodingArgument("enc")) ->Comment("CKContext used encoding splitted by ','. Support mutiple encoding.") @@ -173,6 +199,9 @@ namespace Unvirt::Context { void UnvirtContext::ClearDocument() { if (m_FileReader == nullptr) return; + // clear search result + m_SearchPart = SearchPart::None; + m_SearchIdxResult.clear(); // delete reader delete m_FileReader; m_FileReader = nullptr; @@ -186,6 +215,14 @@ namespace Unvirt::Context { fprintf(stdout, UNVIRT_TERMCOL_LIGHT_YELLOW(("[CKContext] ")) "%s\n", msg); } } + + void UnvirtContext::PrintCommonInfo(const char* u8_fmt, ...) { + va_list argptr; + va_start(argptr, u8_fmt); + std::vfprintf(stdout, u8_fmt, argptr); + va_end(argptr); + std::fputc('\n', stdout); + } void UnvirtContext::PrintCommonError(const char* u8_fmt, ...) { va_list argptr; @@ -321,7 +358,7 @@ namespace Unvirt::Context { return; } - // get page + // get 0 based page (-1) size_t page = *amap->Get("page") - 1; // show list @@ -329,21 +366,55 @@ namespace Unvirt::Context { case 0: { // obj list - if (page * m_PageLen >= m_FileReader->GetFileObjects().size()) { - PrintCommonError("Page out of range."); - return; - } - Unvirt::StructFormatter::PrintObjectList(m_FileReader->GetFileObjects(), m_FileReader->GetFileInfo(), page, this->m_PageLen); + Unvirt::StructFormatter::PrintObjectList( + m_FileReader->GetFileObjects(), + m_FileReader->GetFileInfo(), + page, this->m_PageLen, + m_ListStyleIsFull + ); break; } case 1: { // mgr list - if (page * m_PageLen >= m_FileReader->GetManagersData().size()) { - PrintCommonError("Page out of range."); - return; + Unvirt::StructFormatter::PrintManagerList( + m_FileReader->GetManagersData(), + page, this->m_PageLen, + m_ListStyleIsFull + ); + break; + } + case 2: + { + // search list + switch (m_SearchPart) { + case SearchPart::None: + { + PrintCommonError("No search result to list."); + break; + } + case SearchPart::Object: + { + Unvirt::StructFormatter::PrintSearchedObjectList( + m_SearchIdxResult, + m_FileReader->GetFileObjects(), + m_FileReader->GetFileInfo(), + page, this->m_PageLen, + m_ListStyleIsFull + ); + break; + } + case SearchPart::Manager: + { + Unvirt::StructFormatter::PrintSearchedManagerList( + m_SearchIdxResult, + m_FileReader->GetManagersData(), + page, this->m_PageLen, + m_ListStyleIsFull + ); + break; + } } - Unvirt::StructFormatter::PrintManagerList(m_FileReader->GetManagersData(), page, this->m_PageLen); break; } } @@ -376,7 +447,8 @@ namespace Unvirt::Context { PrintCommonError("Index out of range."); return; } - PrintCommonError("WIP function."); + // todo: finish manager display + PrintCommonError("Not supported now."); //Unvirt::StructFormatter::PrintCKBaseManager(m_FileReader->GetManagersData()[index].Data); break; } @@ -416,11 +488,110 @@ namespace Unvirt::Context { } } + void UnvirtContext::ProcSearch(const CmdHelper::ArgumentsMap* amap) { + // check pre-requirement + if (!HasOpenedFile()) { + PrintCommonError("No loaded file."); + return; + } + + // get search text + std::string search_text(*amap->Get("text")); + + // analyse search mode + std::function search_fct = [](const LibCmo::XContainer::XString&) -> bool { return false; }; + switch (*amap->Get("mode")) { + case 0: + { + // plain mode + search_fct = [&search_text](const LibCmo::XContainer::XString& cmp) -> bool { + return cmp.find(search_text) != std::string::npos; + }; + break; + } + case 1: + { + // regex mode + + // try construct regex + std::regex re; + try { + re = std::regex(search_text, std::regex_constants::ECMAScript); + } catch (const std::regex_error& e) { + PrintCommonError("Invalid regular expressions: %s", e.what()); + return; + } + + // use copy ctor capture to input regex + // because re will be freed when exiting this switch. + search_fct = [re](const LibCmo::XContainer::XString& cmp) -> bool { + return std::regex_search(cmp, re); + }; + break; + } + } + + // start search + switch (*amap->Get("part")) { + case 0: + { + // object + m_SearchPart = SearchPart::Object; + m_SearchIdxResult.clear(); + + size_t counter = 0; + for (const auto& obj : m_FileReader->GetFileObjects()) { + if (search_fct(obj.Name)) { + m_SearchIdxResult.emplace_back(counter); + } + ++counter; + } + + break; + } + case 1: + { + // manager + m_SearchPart = SearchPart::Manager; + m_SearchIdxResult.clear(); + PrintCommonError("Not supported now."); + // todo: remove this return when fixing manager searching. + return; + break; + } + } + + // report search result + if (m_SearchIdxResult.empty()) { + PrintCommonInfo("Search done, but no result."); + } else { + PrintCommonInfo("Search done with %" PRIuSIZET " results. Use `ls search` to check them.", m_SearchIdxResult.size()); + } + } + void UnvirtContext::ProcItems(const CmdHelper::ArgumentsMap* amap) { // assign m_PageLen = *amap->Get("count"); } + void UnvirtContext::ProcStyle(const CmdHelper::ArgumentsMap* amap) { + // set list style level + switch (*amap->Get("level")) { + case 0: + { + // full level + m_ListStyleIsFull = true; + break; + } + case 1: + { + // simple level + m_ListStyleIsFull = false; + break; + } + } + } + void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap* amap) { const auto& encodings = *amap->Get("enc"); m_Ctx->SetEncoding(encodings); diff --git a/Unvirt/UnvirtContext.hpp b/Unvirt/UnvirtContext.hpp index 9d1337a..1932e30 100644 --- a/Unvirt/UnvirtContext.hpp +++ b/Unvirt/UnvirtContext.hpp @@ -22,9 +22,10 @@ namespace Unvirt::Context { void Run(); protected: - enum class ViewPart { - Objects, Managers + enum class SearchPart { + None, Object, Manager }; + void PrintCommonInfo(const char* u8_fmt, ...); void PrintCommonError(const char* u8_fmt, ...); void ProcLoad(const CmdHelper::ArgumentsMap* amap); @@ -34,7 +35,9 @@ namespace Unvirt::Context { void ProcLs(const CmdHelper::ArgumentsMap* amap); void ProcData(const CmdHelper::ArgumentsMap* amap); void ProcChunk(const CmdHelper::ArgumentsMap* amap); + void ProcSearch(const CmdHelper::ArgumentsMap* amap); void ProcItems(const CmdHelper::ArgumentsMap* amap); + void ProcStyle(const CmdHelper::ArgumentsMap* amap); void ProcEncoding(const CmdHelper::ArgumentsMap* amap); void ProcTemp(const CmdHelper::ArgumentsMap* amap); void ProcRsc(const CmdHelper::ArgumentsMap* amap, bool isClear); @@ -52,6 +55,10 @@ namespace Unvirt::Context { CmdHelper::CmdSplitter m_Splitter; size_t m_PageLen; + bool m_ListStyleIsFull; + SearchPart m_SearchPart; + LibCmo::XContainer::XArray m_SearchIdxResult; + bool m_OrderExit; LibCmo::CK2::CKContext* m_Ctx; LibCmo::CK2::CKFileReader* m_FileReader;