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] <text> command to allow user search object or manager list by substring or regex.
- add ls search <page> to browse the search result.
- set IronPad minidump dump type from full memory to normal.
- fix Unvirt ls command page count display error.
This commit is contained in:
yyc12345 2023-10-28 18:17:53 +08:00
parent e4a67a50a5
commit c7af11702f
5 changed files with 349 additions and 67 deletions

View File

@ -204,7 +204,7 @@ namespace IronPad {
exception_info.ClientPointers = TRUE; exception_info.ClientPointers = TRUE;
MiniDumpWriteDump( MiniDumpWriteDump(
GetCurrentProcess(), GetCurrentProcessId(), hFile, GetCurrentProcess(), GetCurrentProcessId(), hFile,
MiniDumpWithFullMemory, MiniDumpNormal,
&exception_info, &exception_info,
NULL, NULL NULL, NULL
); );

View File

@ -7,8 +7,6 @@ namespace Unvirt::StructFormatter {
#pragma region Assist Functions #pragma region Assist Functions
#define PRIuSIZET "zu"
static void PrintCKSTRING(LibCmo::CKSTRING name) { static void PrintCKSTRING(LibCmo::CKSTRING name) {
if (name == nullptr) { if (name == nullptr) {
fputs(UNVIRT_TERMCOL_LIGHT_MAGENTA(("<anonymous>")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_MAGENTA(("<anonymous>")), stdout);
@ -39,6 +37,9 @@ namespace Unvirt::StructFormatter {
static void PrintBool(bool v) { static void PrintBool(bool v) {
fputs(v ? "true" : "false", stdout); 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) { static void PrintColor(const LibCmo::VxMath::VxColor& col) {
LibCmo::CKDWORD argb = col.ToARGB(); LibCmo::CKDWORD argb = col.ToARGB();
LibCmo::CKDWORD a = (argb & 0xFF000000) >> 24, LibCmo::CKDWORD a = (argb & 0xFF000000) >> 24,
@ -46,9 +47,9 @@ namespace Unvirt::StructFormatter {
g = (argb & 0x0000FF00) >> 8, g = (argb & 0x0000FF00) >> 8,
b = (argb & 0x000000FF); 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, 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, a, col.a,
r, g, b, r, g, b,
r, g, b, r, g, b,
r, g, b, a r, g, b, a
); );
} }
@ -61,9 +62,16 @@ namespace Unvirt::StructFormatter {
const std::vector<_Ty>& data, size_t page, size_t pageitems, const std::vector<_Ty>& data, size_t page, size_t pageitems,
std::function<void()> printHdrFct, std::function<void(size_t, const _Ty&)> printEntryFct) { std::function<void()> printHdrFct, std::function<void(size_t, const _Ty&)> 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(), size_t fulllen = data.size(),
startpos = page * pageitems, 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 // print header
printHdrFct(); printHdrFct();
@ -73,7 +81,7 @@ namespace Unvirt::StructFormatter {
printEntryFct(counter, data[counter]); 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 #pragma endregion
@ -214,7 +222,7 @@ namespace Unvirt::StructFormatter {
fputs("Transparent Color: ", stdout); fputs("Transparent Color: ", stdout);
PrintColor(bd.GetTransparentColor()); PrintColor(bd.GetTransparentColor());
fputc('\n', stdout); fputc('\n', stdout);
fputs("Bitmap Flags:\n", stdout); fputs("Bitmap Flags:\n", stdout);
fputs(AccessibleValue::GetFlagEnumName(bd.GetBitmapFlags(), AccessibleValue::EnumDesc::CK_BITMAPDATA_FLAGS, "\n").c_str(), stdout); fputs(AccessibleValue::GetFlagEnumName(bd.GetBitmapFlags(), AccessibleValue::EnumDesc::CK_BITMAPDATA_FLAGS, "\n").c_str(), stdout);
fputc('\n', stdout); fputc('\n', stdout);
@ -223,7 +231,7 @@ namespace Unvirt::StructFormatter {
static void PrintCKMaterialDetail(LibCmo::CK2::ObjImpls::CKMaterial* obj) { static void PrintCKMaterialDetail(LibCmo::CK2::ObjImpls::CKMaterial* obj) {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMaterial\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMaterial\n")), stdout);
// color // color
fputs("== Color ==\n", stdout); fputs("== Color ==\n", stdout);
@ -278,7 +286,7 @@ namespace Unvirt::StructFormatter {
fputc('\n', stdout); fputc('\n', stdout);
fprintf(stdout, "Alpha Function: %s\n", AccessibleValue::GetEnumName(obj->GetAlphaFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str()); fprintf(stdout, "Alpha Function: %s\n", AccessibleValue::GetEnumName(obj->GetAlphaFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str());
fprintf(stdout, "Alpha Ref Value: %" PRIuCKBYTE "\n", obj->GetAlphaRef()); fprintf(stdout, "Alpha Ref Value: %" PRIuCKBYTE "\n", obj->GetAlphaRef());
// alpha blend // alpha blend
fputs("== Alpha Blend ==\n", stdout); fputs("== Alpha Blend ==\n", stdout);
fputs("Enabled: ", stdout); fputs("Enabled: ", stdout);
@ -286,14 +294,14 @@ namespace Unvirt::StructFormatter {
fputc('\n', stdout); fputc('\n', stdout);
fprintf(stdout, "Source Blend: %s\n", AccessibleValue::GetEnumName(obj->GetSourceBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str()); 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()); fprintf(stdout, "Destination Blend: %s\n", AccessibleValue::GetEnumName(obj->GetDestBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str());
// z buffer // z buffer
fputs("== Z-Buffer Write ==\n", stdout); fputs("== Z-Buffer Write ==\n", stdout);
fputs("Enabled: ", stdout); fputs("Enabled: ", stdout);
PrintBool(obj->GetZWriteEnabled()); PrintBool(obj->GetZWriteEnabled());
fputc('\n', stdout); fputc('\n', stdout);
fprintf(stdout, "Z Compare Function: %s\n", AccessibleValue::GetEnumName(obj->GetZFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str()); fprintf(stdout, "Z Compare Function: %s\n", AccessibleValue::GetEnumName(obj->GetZFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str());
// effect // effect
fputs("== Effect ==\n", stdout); fputs("== Effect ==\n", stdout);
fprintf(stdout, "Effect: %s\n", AccessibleValue::GetEnumName(obj->GetEffect(), AccessibleValue::EnumDesc::VX_EFFECT).c_str()); 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) { static void PrintCKMeshDetail(LibCmo::CK2::ObjImpls::CKMesh* obj) {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMesh\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMesh\n")), stdout);
fputs("== Flags ==\n", stdout); fputs("== Flags ==\n", stdout);
fputs("Mesh Flags:\n", stdout); fputs("Mesh Flags:\n", stdout);
fputs(AccessibleValue::GetFlagEnumName(obj->GetMeshFlags(), AccessibleValue::EnumDesc::VXMESH_FLAGS, "\n").c_str(), stdout); fputs(AccessibleValue::GetFlagEnumName(obj->GetMeshFlags(), AccessibleValue::EnumDesc::VXMESH_FLAGS, "\n").c_str(), stdout);
fputc('\n', stdout); fputc('\n', stdout);
// vertex data // vertex data
fputs("== Vertex ==\n", stdout); fputs("== Vertex ==\n", stdout);
fprintf(stdout, "Vertex Count: %" PRIuCKDWORD "\n", obj->GetVertexCount()); 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)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\tColors\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD));
PrintPointer(obj->GetVertexSpecularColors()); PrintPointer(obj->GetVertexSpecularColors());
fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\tSpecularColors\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\tSpecularColors\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD));
// face data // face data
fputs("== Face ==\n", stdout); fputs("== Face ==\n", stdout);
fprintf(stdout, "Face Count: %" PRIuCKDWORD "\n", obj->GetFaceCount()); 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( void PrintObjectList(
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls, const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls,
const LibCmo::CK2::CKFileInfo& fileinfo, 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); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileObject\n")), stdout);
GeneralPrintList<LibCmo::CK2::CKFileObject>(ls, page, pageitems, GeneralPrintList<LibCmo::CK2::CKFileObject>(ls, page, pageitems,
[]() -> void { [full_detail]() -> void {
fputs("SaveFlags\tOptions\tCK ID\tFile CK ID\tFile Index\tPack Size\tIndex\tType\tCKObject\tCKStateChunk\tName\n", stdout); PrintObjectListHeader(full_detail);
}, },
[&fileinfo](size_t index, const LibCmo::CK2::CKFileObject& obj) -> void { [&fileinfo, full_detail](size_t index, const LibCmo::CK2::CKFileObject& obj) -> void {
fprintf(stdout, "0x%08" PRIxCKDWORD "\t", obj.SaveFlags); PrintObjectListEntry(obj, fileinfo, index, full_detail);
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);
} }
); );
} }
void PrintSearchedObjectList(
const LibCmo::XContainer::XArray<size_t>& idxls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& 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<size_t>(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( void PrintManagerList(
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls, const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls,
size_t page, size_t pageitems) { size_t page, size_t pageitems,
bool full_detail) {
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileManager\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileManager\n")), stdout);
GeneralPrintList<LibCmo::CK2::CKFileManagerData>(ls, page, pageitems, GeneralPrintList<LibCmo::CK2::CKFileManagerData>(ls, page, pageitems,
[]() -> void { [full_detail]() -> void {
// print header // 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 // print body
fprintf(stdout, "#%" PRIuSIZET "\t", index); PrintManagerListEntry(mgr, index, full_detail);
PrintCKGUID(mgr.Manager);
fputc('\t', stdout);
PrintPointer(mgr.Data);
fputc('\n', stdout);
} }
); );
} }
void PrintSearchedManagerList(
const LibCmo::XContainer::XArray<size_t>& idxls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls,
size_t page, size_t pageitems,
bool full_detail) {
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKFileManager Searching Result\n")), stdout);
GeneralPrintList<size_t>(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) { void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject* obj) {
if (obj == nullptr) { if (obj == nullptr) {
@ -506,6 +592,7 @@ namespace Unvirt::StructFormatter {
} }
} }
void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager* mgr) { void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager* mgr) {
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKBaseManager\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKBaseManager\n")), stdout);
if (mgr == nullptr) { if (mgr == nullptr) {
@ -515,6 +602,7 @@ namespace Unvirt::StructFormatter {
fputs(UNVIRT_TERMCOL_LIGHT_RED(("Not Implemented.\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_RED(("Not Implemented.\n")), stdout);
} }
void PrintCKStateChunk(const LibCmo::CK2::CKStateChunk* chunk) { void PrintCKStateChunk(const LibCmo::CK2::CKStateChunk* chunk) {
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKStateChunk\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKStateChunk\n")), stdout);
if (chunk == nullptr) { if (chunk == nullptr) {

View File

@ -4,16 +4,32 @@
#include <CK2/CKFile.hpp> #include <CK2/CKFile.hpp>
namespace Unvirt::StructFormatter { namespace Unvirt::StructFormatter {
#define PRIuSIZET "zu"
void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo); void PrintCKFileInfo(const LibCmo::CK2::CKFileInfo& fileinfo);
void PrintObjectList( void PrintObjectList(
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls, const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls,
const LibCmo::CK2::CKFileInfo& fileinfo, 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<size_t>& idxls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileObject>& ls,
const LibCmo::CK2::CKFileInfo& fileinfo,
size_t page, size_t pageitems,
bool full_detail);
void PrintManagerList( void PrintManagerList(
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls, const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls,
size_t page, size_t pageitems); size_t page, size_t pageitems,
bool full_detail);
void PrintSearchedManagerList(
const LibCmo::XContainer::XArray<size_t>& idxls,
const LibCmo::XContainer::XArray<LibCmo::CK2::CKFileManagerData>& ls,
size_t page, size_t pageitems,
bool full_detail);
void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject*); void PrintCKObject(const LibCmo::CK2::ObjImpls::CKObject*);
void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager*); void PrintCKBaseManager(const LibCmo::CK2::MgrImpls::CKBaseManager*);

View File

@ -1,6 +1,7 @@
#include "UnvirtContext.hpp" #include "UnvirtContext.hpp"
#include <CK2/MgrImpls/CKPathManager.hpp> #include <CK2/MgrImpls/CKPathManager.hpp>
#include <cstdarg> #include <cstdarg>
#include <regex>
namespace Unvirt::Context { namespace Unvirt::Context {
@ -8,7 +9,8 @@ namespace Unvirt::Context {
UnvirtContext::UnvirtContext() : UnvirtContext::UnvirtContext() :
m_Root(), m_Splitter(), m_Help(nullptr), 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) { m_Ctx(nullptr), m_FileReader(nullptr), m_IsShallowRead(true) {
// create command root // create command root
@ -49,7 +51,7 @@ namespace Unvirt::Context {
) )
) )
->Then((new CmdHelper::Literal("ls")) ->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.") ->Comment("Which list you want to list.")
->Then((new CmdHelper::IntArgument("page", [](int32_t v) -> bool { return v > 0; })) ->Then((new CmdHelper::IntArgument("page", [](int32_t v) -> bool { return v > 0; }))
->Comment("The page index. Start with 1.") ->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::Literal("items"))
->Then((new CmdHelper::IntArgument("count", [](int32_t v) -> bool { return v > 0; })) ->Then((new CmdHelper::IntArgument("count", [](int32_t v) -> bool { return v > 0; }))
->Comment("The count of items you want to show in one page.") ->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::Literal("encoding"))
->Then((new CmdHelper::EncodingArgument("enc")) ->Then((new CmdHelper::EncodingArgument("enc"))
->Comment("CKContext used encoding splitted by ','. Support mutiple encoding.") ->Comment("CKContext used encoding splitted by ','. Support mutiple encoding.")
@ -173,6 +199,9 @@ namespace Unvirt::Context {
void UnvirtContext::ClearDocument() { void UnvirtContext::ClearDocument() {
if (m_FileReader == nullptr) return; if (m_FileReader == nullptr) return;
// clear search result
m_SearchPart = SearchPart::None;
m_SearchIdxResult.clear();
// delete reader // delete reader
delete m_FileReader; delete m_FileReader;
m_FileReader = nullptr; m_FileReader = nullptr;
@ -186,6 +215,14 @@ namespace Unvirt::Context {
fprintf(stdout, UNVIRT_TERMCOL_LIGHT_YELLOW(("[CKContext] ")) "%s\n", msg); 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, ...) { void UnvirtContext::PrintCommonError(const char* u8_fmt, ...) {
va_list argptr; va_list argptr;
@ -321,7 +358,7 @@ namespace Unvirt::Context {
return; return;
} }
// get page // get 0 based page (-1)
size_t page = *amap->Get<CmdHelper::IntArgument::vType>("page") - 1; size_t page = *amap->Get<CmdHelper::IntArgument::vType>("page") - 1;
// show list // show list
@ -329,21 +366,55 @@ namespace Unvirt::Context {
case 0: case 0:
{ {
// obj list // obj list
if (page * m_PageLen >= m_FileReader->GetFileObjects().size()) { Unvirt::StructFormatter::PrintObjectList(
PrintCommonError("Page out of range."); m_FileReader->GetFileObjects(),
return; m_FileReader->GetFileInfo(),
} page, this->m_PageLen,
Unvirt::StructFormatter::PrintObjectList(m_FileReader->GetFileObjects(), m_FileReader->GetFileInfo(), page, this->m_PageLen); m_ListStyleIsFull
);
break; break;
} }
case 1: case 1:
{ {
// mgr list // mgr list
if (page * m_PageLen >= m_FileReader->GetManagersData().size()) { Unvirt::StructFormatter::PrintManagerList(
PrintCommonError("Page out of range."); m_FileReader->GetManagersData(),
return; 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; break;
} }
} }
@ -376,7 +447,8 @@ namespace Unvirt::Context {
PrintCommonError("Index out of range."); PrintCommonError("Index out of range.");
return; return;
} }
PrintCommonError("WIP function."); // todo: finish manager display
PrintCommonError("Not supported now.");
//Unvirt::StructFormatter::PrintCKBaseManager(m_FileReader->GetManagersData()[index].Data); //Unvirt::StructFormatter::PrintCKBaseManager(m_FileReader->GetManagersData()[index].Data);
break; 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<CmdHelper::StringArgument::vType>("text"));
// analyse search mode
std::function<bool(const LibCmo::XContainer::XString&)> search_fct = [](const LibCmo::XContainer::XString&) -> bool { return false; };
switch (*amap->Get<CmdHelper::Choice::vType>("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<CmdHelper::Choice::vType>("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) { void UnvirtContext::ProcItems(const CmdHelper::ArgumentsMap* amap) {
// assign // assign
m_PageLen = *amap->Get<CmdHelper::IntArgument::vType>("count"); m_PageLen = *amap->Get<CmdHelper::IntArgument::vType>("count");
} }
void UnvirtContext::ProcStyle(const CmdHelper::ArgumentsMap* amap) {
// set list style level
switch (*amap->Get<CmdHelper::Choice::vType>("level")) {
case 0:
{
// full level
m_ListStyleIsFull = true;
break;
}
case 1:
{
// simple level
m_ListStyleIsFull = false;
break;
}
}
}
void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap* amap) { void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap* amap) {
const auto& encodings = *amap->Get<CmdHelper::EncodingArgument::vType>("enc"); const auto& encodings = *amap->Get<CmdHelper::EncodingArgument::vType>("enc");
m_Ctx->SetEncoding(encodings); m_Ctx->SetEncoding(encodings);

View File

@ -22,9 +22,10 @@ namespace Unvirt::Context {
void Run(); void Run();
protected: protected:
enum class ViewPart { enum class SearchPart {
Objects, Managers None, Object, Manager
}; };
void PrintCommonInfo(const char* u8_fmt, ...);
void PrintCommonError(const char* u8_fmt, ...); void PrintCommonError(const char* u8_fmt, ...);
void ProcLoad(const CmdHelper::ArgumentsMap* amap); void ProcLoad(const CmdHelper::ArgumentsMap* amap);
@ -34,7 +35,9 @@ namespace Unvirt::Context {
void ProcLs(const CmdHelper::ArgumentsMap* amap); void ProcLs(const CmdHelper::ArgumentsMap* amap);
void ProcData(const CmdHelper::ArgumentsMap* amap); void ProcData(const CmdHelper::ArgumentsMap* amap);
void ProcChunk(const CmdHelper::ArgumentsMap* amap); void ProcChunk(const CmdHelper::ArgumentsMap* amap);
void ProcSearch(const CmdHelper::ArgumentsMap* amap);
void ProcItems(const CmdHelper::ArgumentsMap* amap); void ProcItems(const CmdHelper::ArgumentsMap* amap);
void ProcStyle(const CmdHelper::ArgumentsMap* amap);
void ProcEncoding(const CmdHelper::ArgumentsMap* amap); void ProcEncoding(const CmdHelper::ArgumentsMap* amap);
void ProcTemp(const CmdHelper::ArgumentsMap* amap); void ProcTemp(const CmdHelper::ArgumentsMap* amap);
void ProcRsc(const CmdHelper::ArgumentsMap* amap, bool isClear); void ProcRsc(const CmdHelper::ArgumentsMap* amap, bool isClear);
@ -52,6 +55,10 @@ namespace Unvirt::Context {
CmdHelper::CmdSplitter m_Splitter; CmdHelper::CmdSplitter m_Splitter;
size_t m_PageLen; size_t m_PageLen;
bool m_ListStyleIsFull;
SearchPart m_SearchPart;
LibCmo::XContainer::XArray<size_t> m_SearchIdxResult;
bool m_OrderExit; bool m_OrderExit;
LibCmo::CK2::CKContext* m_Ctx; LibCmo::CK2::CKContext* m_Ctx;
LibCmo::CK2::CKFileReader* m_FileReader; LibCmo::CK2::CKFileReader* m_FileReader;