fix: fix Unvirt build issue, but it doesn't work

This commit is contained in:
yyc12345 2024-08-26 21:28:13 +08:00
parent 34015d2d1c
commit 3735a202f3
8 changed files with 343 additions and 238 deletions

View File

@ -153,7 +153,7 @@ namespace LibCmo::CK2 {
* @details It accept a CKSTRING representing the string need to be printed.
* The passed CKSTRING is guaranteen that it can not be nullptr.
*/
using OutputCallback = void(*)(CKSTRING);
using OutputCallback = std::function<void(CKSTRING)>;
/**
* @brief Output plain message.
* @param[in] str Plain message. nullptr is allowed but not suggested.

View File

@ -403,6 +403,9 @@ namespace LibCmo::EncodingHelper {
#if YYCC_OS == YYCC_OS_WINDOWS
struct WindowsEncodingToken {
WindowsEncodingToken(const std::u8string_view& universal_code, UINT cp) :
m_Name(universal_code), m_CodePage(cp) {}
std::u8string m_Name;
UINT m_CodePage;
};
@ -412,7 +415,8 @@ namespace LibCmo::EncodingHelper {
static const iconv_t c_InvalidIconvType = reinterpret_cast<iconv_t>(-1);
struct IconvEncodingToken {
IconvEncodingToken(const std::string_view& iconv_code) :
IconvEncodingToken(const std::u8string_view& universal_code, const std::string_view& iconv_code) :
m_Name(universal_code),
m_FromUTF8(c_InvalidIconvType), m_ToUTF8(c_InvalidIconvType) {
// if iconv code is empty, do nothing
if (iconv_code.empty()) return;
@ -426,6 +430,8 @@ namespace LibCmo::EncodingHelper {
if (this->m_ToUTF8 != c_InvalidIconvType)
iconv_close(token_cast->m_ToUTF8);
}
std::u8string m_Name;
iconv_t m_FromUTF8;
iconv_t m_ToUTF8;
};
@ -508,7 +514,7 @@ namespace LibCmo::EncodingHelper {
if (!YYCC::WinFctHelper::IsValidCodePage(cp))
return INVALID_ENCODING_TOKEN;
// create token and return
WindowsEncodingToken* token = new WindowsEncodingToken { cp };
WindowsEncodingToken* token = new WindowsEncodingToken(enc_name, cp);
return token;
#else
// get iconv code first
@ -516,7 +522,7 @@ namespace LibCmo::EncodingHelper {
if (!GetIconvCode(enc_name, code))
return INVALID_ENCODING_TOKEN;
// create token and set default value
IconvEncodingToken* token = new IconvEncodingToken(code);
IconvEncodingToken* token = new IconvEncodingToken(enc_name, code);
// check whether token has been initialized correctly
if (token->m_FromUTF8 == c_InvalidIconvType || token->m_ToUTF8 == c_InvalidIconvType) {
// failed. free resource and return
@ -541,6 +547,34 @@ namespace LibCmo::EncodingHelper {
#endif
}
std::u8string GetEncodingTokenAssociatedName(EncodingToken token) {
// prepare return value
std::u8string ret;
// if token is invalid, return directly
if (token == INVALID_ENCODING_TOKEN) return ret;
// get associated name
#if YYCC_OS == YYCC_OS_WINDOWS
WindowsEncodingToken* token_cast = static_cast<WindowsEncodingToken*>(token);
ret = token_cast->m_Name;
#else
IconvEncodingToken* token_cast = static_cast<IconvEncodingToken*>(token);
ret = token_cast->m_Name;
#endif
// return value
return ret;
}
bool IsValidEncodingName(const std::u8string_view& enc_name) {
#if YYCC_OS == YYCC_OS_WINDOWS
UINT cp = CP_ACP;
return GetWindowsCodePage(enc_name, cp);
#else
std::string code;
return GetIconvCode(enc_name, code);
#endif
}
#pragma endregion
#pragma region Exposed Convertion Functions

View File

@ -55,6 +55,23 @@ namespace LibCmo::EncodingHelper {
* If token is #INVALID_ENCODING_TOKEN, this function does nothing.
*/
void DestroyEncodingToken(EncodingToken token);
/**
* @brief Get associated universal encoding name of given encoding token.
* @param[in] token The encoding token for getting name.
* @return Encoding token associated name (the universal encoding name used to create this token).
* Blank if given token is invalid or fail to get.
*/
std::u8string GetEncodingTokenAssociatedName(EncodingToken token);
/**
* @brief Check whether given universal encoding name can be used to produce token.
* @param[in] enc_name Universal encoding name.
* @return True if it is, otherwise false.
* @remarks
* Please note this function only check whether given encoding name is acceptable by token creator.
* Hoewver it doesn't mean that the token must be created if this function return true.
* Because there are some runtime issues which can cause that fail to create encoding token.
*/
bool IsValidEncodingName(const std::u8string_view& enc_name);
/**
* @brief Convert native string to UTF8 string by given encoding.

View File

@ -1,4 +1,5 @@
#include "CmdHelper.hpp"
#include <VTAll.hpp>
#include <algorithm>
namespace Unvirt::CmdHelper {
@ -11,7 +12,7 @@ namespace Unvirt::CmdHelper {
return m_Result;
}
bool CmdSplitter::Convert(const std::u8string& u8cmd) {
bool CmdSplitter::Lex(const std::u8string& u8cmd) {
// Clear variables
m_ValidResult = false;
m_Result.clear();
@ -537,7 +538,12 @@ if (!this->IsRootNode()) { \
bool EncodingListArgument::BeginConsume(const std::u8string& cur_cmd, ArgumentsMap& am) {
// split given argument
std::vector<std::u8string> encs = YYCC::StringHelper::Split(cur_cmd, u8",");
// add into map
// check each parts is a valid encoding name
for (const auto& item : encs) {
if (!LibCmo::EncodingHelper::IsValidEncodingName(item))
return false;
}
// okey, add into map
am.Add<ArgValue_t>(m_ArgumentName, encs);
return true;
}

View File

@ -31,9 +31,9 @@ namespace Unvirt::CmdHelper {
m_CurrentChar(u8'\0'), m_Buffer(), m_Result(), m_ValidResult(false),
m_State(StateType::NORMAL), m_PrevState(StateType::NORMAL) {}
~CmdSplitter() {}
YYCC_DEL_CLS_COPY_MOVE(CmdSplitter);
YYCC_DEF_CLS_COPY_MOVE(CmdSplitter);
bool Convert(const std::u8string& u8cmd);
bool Lex(const std::u8string& u8cmd);
const Result_t& GetResult() const;
private:
@ -241,7 +241,7 @@ namespace Unvirt::CmdHelper {
class AbstractNode {
public:
using FctExecution_t = void(*)(const ArgumentsMap&);
using FctExecution_t = std::function<void(const ArgumentsMap&)>;
public:
AbstractNode();

View File

@ -2,7 +2,6 @@
#include <YYCCommonplace.hpp>
#include "AccessibleValue.hpp"
#include "TerminalHelper.hpp"
namespace Console = YYCC::ConsoleHelper;

View File

@ -1,193 +1,208 @@
#include "UnvirtContext.hpp"
#include <YYCCommonplace.hpp>
#include <CK2/MgrImpls/CKPathManager.hpp>
#include <cstdarg>
#include <regex>
namespace Unvirt::Context {
#pragma region Constraint Help Function
static YYCC::Constraints::Constraint<size_t> GetOneBasedIndexConstraint() {
return YYCC::Constraints::Constraint<size_t> {
[](const size_t& val) -> bool {
return val > 0u;
}
};
}
#pragma endregion
#pragma region UnvirtContext Misc
UnvirtContext::UnvirtContext() :
m_Root(), m_Splitter(), m_Help(nullptr),
m_Splitter(), m_Parser(), m_Help(),
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
CmdHelper::CommandRoot* root = &m_Root;
// Setup command parser
// get root node first
CmdHelper::Nodes::RootNode& root = m_Parser.GetRoot();
// setup tree
root
->Then((new CmdHelper::Literal("load"))
->Then((new CmdHelper::Choice("stage", { "deep", "shallow"}))
->Comment("The stage of loading. 'deep' will load to CKObject stage. 'shallow' will load to CKStateChunk stage.")
->Then((new CmdHelper::StringArgument("filepath"))
->Comment("The path to loading file.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"load")
.Then<CmdHelper::Nodes::Choice>(CmdHelper::Nodes::Choice(u8"stage", { u8"deep", u8"shallow"})
.Comment(u8"The stage of loading. 'deep' will load to CKObject stage. 'shallow' will load to CKStateChunk stage.")
.Then<CmdHelper::Nodes::StringArgument>(CmdHelper::Nodes::StringArgument(u8"filepath")
.Comment(u8"The path to loading file.")
.Executes(
std::bind(&UnvirtContext::ProcLoad, this, std::placeholders::_1),
"Load a Virtools composition."
u8"Load a Virtools composition."
)
)
)
)
->Then((new CmdHelper::Literal("unload"))
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"unload")
.Executes(
std::bind(&UnvirtContext::ProcUnLoad, this, std::placeholders::_1),
"Release loaded Virtools composition."
u8"Release loaded Virtools composition."
)
)
->Then((new CmdHelper::Literal("save"))
->Then((new CmdHelper::StringArgument("filepath"))
->Comment("The path to save file.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"save")
.Then<CmdHelper::Nodes::StringArgument>(CmdHelper::Nodes::StringArgument(u8"filepath")
.Comment(u8"The path to save file.")
.Executes(
std::bind(&UnvirtContext::ProcSave, this, std::placeholders::_1),
"Save the loaded file into a new file."
u8"Save the loaded file into a new file."
)
)
)
->Then((new CmdHelper::Literal("info"))
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"info")
.Executes(
std::bind(&UnvirtContext::ProcInfo, this, std::placeholders::_1),
"Show the header info of loaded Virtools composition."
u8"Show the header info of loaded Virtools composition."
)
)
->Then((new CmdHelper::Literal("ls"))
->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.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"ls")
.Then<CmdHelper::Nodes::Choice>(CmdHelper::Nodes::Choice(u8"part", { u8"obj", u8"mgr", u8"search"})
.Comment(u8"Which list you want to list.")
.Then<CmdHelper::Nodes::ArithmeticArgument<size_t>>(CmdHelper::Nodes::ArithmeticArgument<size_t>(u8"page", GetOneBasedIndexConstraint())
.Comment(u8"The page index. Start with 1.")
.Executes(
std::bind(&UnvirtContext::ProcLs, this, std::placeholders::_1),
"List something about loaded Virtools composition."
u8"List something about loaded Virtools composition."
)
)
)
)
->Then((new CmdHelper::Literal("data"))
->Then((new CmdHelper::Choice("part", { "obj", "mgr"}))
->Comment("Which list you want to show data.")
->Then((new CmdHelper::IntArgument("index", [](int32_t v) -> bool { return v >= 0; }))
->Comment("The index. Start with 0.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"data")
.Then<CmdHelper::Nodes::Choice>(CmdHelper::Nodes::Choice(u8"part", { u8"obj", u8"mgr"})
.Comment(u8"Which list you want to show data.")
.Then<CmdHelper::Nodes::ArithmeticArgument<size_t>>(CmdHelper::Nodes::ArithmeticArgument<size_t>(u8"index")
.Comment(u8"The index. Start with 0.")
.Executes(
std::bind(&UnvirtContext::ProcData, this, std::placeholders::_1),
"Show the specific CKObject / CKBaseManager data."
u8"Show the specific CKObject / CKBaseManager data."
)
)
)
)
->Then((new CmdHelper::Literal("chunk"))
->Then((new CmdHelper::Choice("part", { "obj", "mgr"}))
->Comment("Which list you want to show chunk.")
->Then((new CmdHelper::IntArgument("index", [](int32_t v) -> bool { return v >= 0; }))
->Comment("The index. Start with 0.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"chunk")
.Then<CmdHelper::Nodes::Choice>(CmdHelper::Nodes::Choice(u8"part", { u8"obj", u8"mgr"})
.Comment(u8"Which list you want to show chunk.")
.Then<CmdHelper::Nodes::ArithmeticArgument<size_t>>(CmdHelper::Nodes::ArithmeticArgument<size_t>(u8"index")
.Comment(u8"The index. Start with 0.")
.Executes(
std::bind(&UnvirtContext::ProcChunk, this, std::placeholders::_1),
"Show the specific CKStateChunk data."
u8"Show the specific CKStateChunk data."
)
)
)
)
->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(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"search")
.Then<CmdHelper::Nodes::Choice>(CmdHelper::Nodes::Choice(u8"part", { u8"obj", u8"mgr"})
.Comment(u8"Which list you want to search.")
.Then<CmdHelper::Nodes::Choice>(CmdHelper::Nodes::Choice(u8"mode", { u8"plain", u8"re"})
.Comment(u8"The search mode. `plain` will search by substring and `re` will do regex search.")
.Then<CmdHelper::Nodes::StringArgument>(CmdHelper::Nodes::StringArgument(u8"text")
.Comment(u8"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."
u8"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.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"items")
.Then<CmdHelper::Nodes::ArithmeticArgument<size_t>>(CmdHelper::Nodes::ArithmeticArgument<size_t>(u8"count", GetOneBasedIndexConstraint())
.Comment(u8"The count of items you want to show in one page.")
.Executes(
std::bind(&UnvirtContext::ProcItems, this, std::placeholders::_1),
"Set up how many items should be listed in one page when using 'ls' command."
u8"Set up how many items should be listed in one page when using 'ls' command."
)
)
)
->Then((new CmdHelper::Literal("style"))
->Then((new CmdHelper::Choice("level", { "full", "simple"}))
->Comment("The amount of showen content.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"style")
.Then<CmdHelper::Nodes::Choice>(CmdHelper::Nodes::Choice(u8"level", { u8"full", u8"simple"})
.Comment(u8"The amount of showen content.")
.Executes(
std::bind(&UnvirtContext::ProcStyle, this, std::placeholders::_1),
"Change the detail level of showen data in `ls` command."
u8"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.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"encoding")
.Then<CmdHelper::Nodes::EncodingListArgument>(CmdHelper::Nodes::EncodingListArgument(u8"enc")
.Comment(u8"CKContext used encoding splitted by ','. Support mutiple encoding.")
.Executes(
std::bind(&UnvirtContext::ProcEncoding, this, std::placeholders::_1),
"Set the encoding series for CKContext."
u8"Set the encoding series for CKContext."
)
)
)
->Then((new CmdHelper::Literal("temp"))
->Then((new CmdHelper::StringArgument("temppath"))
->Comment("The path to Temp folder.")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"temp")
.Then<CmdHelper::Nodes::StringArgument>(CmdHelper::Nodes::StringArgument(u8"temppath")
.Comment(u8"The path to Temp folder.")
.Executes(
std::bind(&UnvirtContext::ProcTemp, this, std::placeholders::_1),
"Set the Temp path for CKContext."
u8"Set the Temp path for CKContext."
)
)
)
->Then((new CmdHelper::Literal("rsc"))
->Then((new CmdHelper::Literal("clear"))
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"rsc")
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"clear")
.Executes(
std::bind(&UnvirtContext::ProcRsc, this, std::placeholders::_1, true),
"Clear all data resources paths."
u8"Clear all data resources paths."
)
)
->Then((new CmdHelper::Literal("add"))
->Then((new CmdHelper::StringArgument("datares"))
->Comment("The data resources path .")
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"add")
.Then<CmdHelper::Nodes::StringArgument>(CmdHelper::Nodes::StringArgument(u8"datares")
.Comment(u8"The data resources path .")
.Executes(
std::bind(&UnvirtContext::ProcRsc, this, std::placeholders::_1, false),
"Add a path to let Virtools find resources."
u8"Add a path to let Virtools find resources."
)
)
)
)
->Then((new CmdHelper::Literal("test"))
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"test")
.Executes(
std::bind(&UnvirtContext::ProcTest, this, std::placeholders::_1),
"Call custom debugging function (only available in Debug mode)."
u8"Call custom debugging function (only available in Debug mode)."
)
)
->Then((new CmdHelper::Literal("help"))
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"help")
.Executes(
std::bind(&UnvirtContext::ProcHelp, this, std::placeholders::_1),
"Output this help page."
u8"Output this help page."
)
)
->Then((new CmdHelper::Literal("exit"))
->Executes(
.Then<CmdHelper::Nodes::Literal>(CmdHelper::Nodes::Literal(u8"exit")
.Executes(
std::bind(&UnvirtContext::ProcExit, this, std::placeholders::_1),
"Exit program."
u8"Exit program."
)
);
// create help
m_Help = root->RootHelp();
// create help document
m_Help = m_Parser.Help();
// create context
LibCmo::CK2::CKStartUp();
// initialize CK engine and create context
LibCmo::CK2::CKERROR err = LibCmo::CK2::CKStartUp();
if (err != LibCmo::CK2::CKERROR::CKERR_OK)
throw std::runtime_error("fail to initialize CK2 engine.");
m_Ctx = new LibCmo::CK2::CKContext();
m_Ctx->SetOutputCallback(std::bind(&UnvirtContext::PrintContextMsg, this, std::placeholders::_1));
m_Ctx->SetGlobalImagesSaveOptions(LibCmo::CK2::CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_EXTERNAL);
}
UnvirtContext::~UnvirtContext() {
if (m_Help != nullptr)
delete m_Help;
// free context
// free context and shutdown CK engine.
ClearDocument();
delete m_Ctx;
LibCmo::CK2::CKShutdown();
@ -212,26 +227,26 @@ namespace Unvirt::Context {
void UnvirtContext::PrintContextMsg(LibCmo::CKSTRING msg) {
if (msg != nullptr) {
fprintf(stdout, UNVIRT_TERMCOL_LIGHT_YELLOW(("[CKContext] ")) "%s\n", msg);
YYCC::ConsoleHelper::FormatLine(YYCC_COLOR_LIGHT_YELLOW(u8"[CKContext] ") "%s", msg);
}
}
void UnvirtContext::PrintCommonInfo(const char* u8_fmt, ...) {
void UnvirtContext::PrintCommonInfo(const char8_t* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
std::vfprintf(stdout, u8_fmt, argptr);
YYCC::ConsoleHelper::WriteLine(
YYCC::StringHelper::VPrintf(u8_fmt, argptr).c_str()
);
va_end(argptr);
std::fputc('\n', stdout);
}
void UnvirtContext::PrintCommonError(const char* u8_fmt, ...) {
void UnvirtContext::PrintCommonError(const char8_t* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
std::fputs(UNVIRT_TERMCOLHDR_LIGHT_RED, stdout);
std::vfprintf(stdout, u8_fmt, argptr);
std::fputs(UNVIRT_TERMCOLTAIL, stdout);
YYCC::ConsoleHelper::FormatLine(YYCC_COLOR_LIGHT_RED(u8"%s"),
YYCC::StringHelper::VPrintf(u8_fmt, argptr).c_str()
);
va_end(argptr);
std::fputc('\n', stdout);
}
#pragma endregion
@ -239,23 +254,34 @@ namespace Unvirt::Context {
#pragma region Main Run
void UnvirtContext::Run() {
Unvirt::TerminalHelper::EnsureTerminalColor();
Unvirt::TerminalHelper::EnsureTerminalEncoding();
std::string u8cmd;
// Enable terminal color feature
YYCC::ConsoleHelper::EnableColorfulConsole();
// Show banner
YYCC::ConsoleHelper::WriteLine(YYCC_COLOR_LIGHT_YELLOW(u8"Unvirt"));
YYCC::ConsoleHelper::WriteLine(YYCC_COLOR_LIGHT_YELLOW(u8"Type 'help' for more infomation. Type 'exit' to quit."));
// start process loop
while (true) {
// get command
TerminalHelper::GetCmdLine(u8cmd);
YYCC::ConsoleHelper::Write(YYCC_COLOR_GREEN(u8"> "));
std::u8string u8cmd = YYCC::ConsoleHelper::ReadLine();
// split cmd and parse it
auto cmds = m_Splitter.Convert(u8cmd);
// lex command line first
if (!m_Splitter.Lex(u8cmd)) {
this->PrintCommonError(u8"Lexer error \"%s\".\nType 'help' for usage.", u8cmd.c_str());
continue;
}
// if result is empty, skip to next one
auto cmds = m_Splitter.GetResult();
if (cmds.empty()) continue;
// get sub command
if (!m_Root.RootConsume(cmds)) {
this->PrintCommonError("Syntax error \"%s\".\nType 'help' for usage.", u8cmd.c_str());
// run command parser
if (!m_Parser.Parse(cmds)) {
this->PrintCommonError(u8"Parser error \"%s\".\nType 'help' for usage.", u8cmd.c_str());
}
// check whether sub processor need exit.
if (m_OrderExit) {
break;
}
@ -266,15 +292,20 @@ namespace Unvirt::Context {
#pragma region Proc Detail
void UnvirtContext::ProcLoad(const CmdHelper::ArgumentsMap* amap) {
void UnvirtContext::ProcLoad(const CmdHelper::ArgumentsMap& amap) {
// check pre-requirement
if (HasOpenedFile()) {
PrintCommonError("Already have a opened file. Close it before calling 'load'.");
PrintCommonError(u8"Already have a opened file. Close it before calling 'load'.");
return;
}
if (!m_Ctx->IsValidEncoding()) {
PrintCommonError(u8"You have not set encoding properly. Set it before loading by calling 'encoding'.");
return;
}
std::string filepath = *amap->Get<CmdHelper::StringArgument::vType>("filepath");
bool is_deep = *amap->Get<CmdHelper::Choice::vType>("stage") == 0;
// get argument
std::u8string filepath = amap.Get<CmdHelper::Nodes::StringArgument::ArgValue_t>(u8"filepath").Get();
bool is_deep = amap.Get<CmdHelper::Nodes::Choice::ArgValue_t>(u8"stage").Get() == 0u;
// proc
m_FileReader = new LibCmo::CK2::CKFileReader(m_Ctx);
@ -288,7 +319,7 @@ namespace Unvirt::Context {
}
if (err != LibCmo::CK2::CKERROR::CKERR_OK) {
// fail to load. release all.
PrintCommonError("Fail to load file. Function return: %s\n\t%s",
PrintCommonError(u8"Fail to load file. Function return: %s\n\t%s",
Unvirt::AccessibleValue::GetCkErrorName(err).c_str(),
Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str()
);
@ -297,10 +328,10 @@ namespace Unvirt::Context {
}
}
void UnvirtContext::ProcUnLoad(const CmdHelper::ArgumentsMap*) {
void UnvirtContext::ProcUnLoad(const CmdHelper::ArgumentsMap&) {
// check pre-requirement
if (!HasOpenedFile()) {
this->PrintCommonError("No loaded file.");
this->PrintCommonError(u8"No loaded file.");
return;
}
@ -308,14 +339,18 @@ namespace Unvirt::Context {
ClearDocument();
}
void Unvirt::Context::UnvirtContext::ProcSave(const CmdHelper::ArgumentsMap* amap) {
void Unvirt::Context::UnvirtContext::ProcSave(const CmdHelper::ArgumentsMap& amap) {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
PrintCommonError(u8"No loaded file.");
return;
}
if (!m_Ctx->IsValidEncoding()) {
PrintCommonError(u8"You have not set encoding properly. Set it before saving by calling 'encoding'.");
return;
}
std::string filepath = *amap->Get<CmdHelper::StringArgument::vType>("filepath");
std::u8string filepath = amap.Get<CmdHelper::Nodes::StringArgument::ArgValue_t>(u8"filepath").Get();
// construct writer from reader
LibCmo::CK2::CKFileWriter writer(m_Ctx, m_FileReader, m_IsShallowRead);
@ -329,7 +364,7 @@ namespace Unvirt::Context {
LibCmo::CK2::CKERROR err = writer.Save(filepath.c_str());
if (err != LibCmo::CK2::CKERROR::CKERR_OK) {
// fail to load. release all.
PrintCommonError("Fail to save file. Function return: %s\n\t%s",
PrintCommonError(u8"Fail to save file. Function return: %s\n\t%s",
Unvirt::AccessibleValue::GetCkErrorName(err).c_str(),
Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str()
);
@ -340,10 +375,10 @@ namespace Unvirt::Context {
}
void UnvirtContext::ProcInfo(const CmdHelper::ArgumentsMap*) {
void UnvirtContext::ProcInfo(const CmdHelper::ArgumentsMap&) {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
PrintCommonError(u8"No loaded file.");
return;
}
@ -351,19 +386,19 @@ namespace Unvirt::Context {
Unvirt::StructFormatter::PrintCKFileInfo(m_FileReader->GetFileInfo());
}
void UnvirtContext::ProcLs(const CmdHelper::ArgumentsMap* amap) {
void UnvirtContext::ProcLs(const CmdHelper::ArgumentsMap& amap) {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
PrintCommonError(u8"No loaded file.");
return;
}
// get 0 based page (-1)
size_t page = *amap->Get<CmdHelper::IntArgument::vType>("page") - 1;
size_t page = amap.Get<CmdHelper::Nodes::ArithmeticArgument<size_t>::ArgValue_t>(u8"page").Get() - 1u;
// show list
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
case 0:
switch (amap.Get<CmdHelper::Nodes::Choice::ArgValue_t>(u8"part").Get()) {
case 0u:
{
// obj list
Unvirt::StructFormatter::PrintObjectList(
@ -374,7 +409,7 @@ namespace Unvirt::Context {
);
break;
}
case 1:
case 1u:
{
// mgr list
Unvirt::StructFormatter::PrintManagerList(
@ -384,13 +419,13 @@ namespace Unvirt::Context {
);
break;
}
case 2:
case 2u:
{
// search list
switch (m_SearchPart) {
case SearchPart::None:
{
PrintCommonError("No search result to list.");
PrintCommonError(u8"No search result to list.");
break;
}
case SearchPart::Object:
@ -417,60 +452,64 @@ namespace Unvirt::Context {
}
break;
}
default:
throw std::runtime_error("unreachable code");
}
}
void UnvirtContext::ProcData( const CmdHelper::ArgumentsMap* amap) {
void UnvirtContext::ProcData(const CmdHelper::ArgumentsMap& amap) {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
PrintCommonError(u8"No loaded file.");
return;
}
// get index
size_t index = *amap->Get<CmdHelper::IntArgument::vType>("index");
size_t index = amap.Get<CmdHelper::Nodes::ArithmeticArgument<size_t>::ArgValue_t>(u8"index").Get();
// show data
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
case 0:
switch (amap.Get<CmdHelper::Nodes::Choice::ArgValue_t>(u8"part").Get()) {
case 0u:
{
if (index >= m_FileReader->GetFileObjects().size()) {
PrintCommonError("Index out of range.");
PrintCommonError(u8"Index out of range.");
return;
}
Unvirt::StructFormatter::PrintCKObject(m_FileReader->GetFileObjects()[index].ObjPtr);
break;
}
case 1:
case 1u:
{
if (index >= m_FileReader->GetManagersData().size()) {
PrintCommonError("Index out of range.");
PrintCommonError(u8"Index out of range.");
return;
}
// todo: finish manager display
PrintCommonError("Not supported now.");
PrintCommonError(u8"Not supported now.");
//Unvirt::StructFormatter::PrintCKBaseManager(m_FileReader->GetManagersData()[index].Data);
break;
}
default:
throw std::runtime_error("unreachable code");
}
}
void UnvirtContext::ProcChunk(const CmdHelper::ArgumentsMap* amap) {
void UnvirtContext::ProcChunk(const CmdHelper::ArgumentsMap& amap) {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
PrintCommonError(u8"No loaded file.");
return;
}
// get index
size_t index = *amap->Get<CmdHelper::IntArgument::vType>("index");
size_t index = amap.Get<CmdHelper::Nodes::ArithmeticArgument<size_t>::ArgValue_t>(u8"index").Get();
// show data
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
switch (amap.Get<CmdHelper::Nodes::Choice::ArgValue_t>(u8"part").Get()) {
case 0:
{
if (index >= m_FileReader->GetFileObjects().size()) {
PrintCommonError("Index out of range.");
PrintCommonError(u8"Index out of range.");
return;
}
Unvirt::StructFormatter::PrintCKStateChunk(m_FileReader->GetFileObjects()[index].Data);
@ -479,29 +518,31 @@ namespace Unvirt::Context {
case 1:
{
if (index >= m_FileReader->GetManagersData().size()) {
PrintCommonError("Index out of range.");
PrintCommonError(u8"Index out of range.");
return;
}
Unvirt::StructFormatter::PrintCKStateChunk(m_FileReader->GetManagersData()[index].Data);
break;
}
default:
throw std::runtime_error("unreachable code");
}
}
void UnvirtContext::ProcSearch(const CmdHelper::ArgumentsMap* amap) {
void UnvirtContext::ProcSearch(const CmdHelper::ArgumentsMap& amap) {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
PrintCommonError(u8"No loaded file.");
return;
}
// get search text
std::string search_text(*amap->Get<CmdHelper::StringArgument::vType>("text"));
// get search text *amap->Get<CmdHelper::StringArgument::vType>("text")
std::u8string search_text = amap.Get<CmdHelper::Nodes::StringArgument::ArgValue_t>(u8"text").Get();
// 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:
std::function<bool(const LibCmo::XContainer::XString&)> search_fct = nullptr;
switch (amap.Get<CmdHelper::Nodes::Choice::ArgValue_t>(u8"mode").Get()) {
case 0u:
{
// plain mode
search_fct = [&search_text](const LibCmo::XContainer::XString& cmp) -> bool {
@ -509,31 +550,37 @@ namespace Unvirt::Context {
};
break;
}
case 1:
case 1u:
{
// regex mode
// get ordinary search text
std::string ordinary_search_text = YYCC::EncodingHelper::ToOrdinary(search_text);
// try construct regex
std::regex re;
try {
re = std::regex(search_text, std::regex_constants::ECMAScript);
re = std::regex(ordinary_search_text, std::regex_constants::ECMAScript);
} catch (const std::regex_error& e) {
PrintCommonError("Invalid regular expressions: %s", e.what());
PrintCommonError(u8"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);
// get ordinary name and comapre
std::string ordinary_cmp = YYCC::EncodingHelper::ToOrdinary(cmp);
return std::regex_search(ordinary_cmp, re);
};
break;
}
default:
throw std::runtime_error("unreachable code");
}
// start search
switch (*amap->Get<CmdHelper::Choice::vType>("part")) {
case 0:
switch (amap.Get<CmdHelper::Nodes::Choice::ArgValue_t>(u8"part").Get()) {
case 0u:
{
// object
m_SearchPart = SearchPart::Object;
@ -549,72 +596,78 @@ namespace Unvirt::Context {
break;
}
case 1:
case 1u:
{
// manager
m_SearchPart = SearchPart::Manager;
m_SearchIdxResult.clear();
PrintCommonError("Not supported now.");
PrintCommonError(u8"Not supported now.");
// todo: remove this return when fixing manager searching.
return;
break;
}
default:
throw std::runtime_error("unreachable code");
}
// report search result
if (m_SearchIdxResult.empty()) {
PrintCommonInfo("Search done, but no result.");
PrintCommonInfo(u8"Search done, but no result.");
} else {
PrintCommonInfo("Search done with %" PRIuSIZET " results. Use `ls search` to check them.", m_SearchIdxResult.size());
PrintCommonInfo(u8"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
m_PageLen = *amap->Get<CmdHelper::IntArgument::vType>("count");
m_PageLen = amap.Get<CmdHelper::Nodes::ArithmeticArgument<size_t>::ArgValue_t>(u8"count").Get();
}
void UnvirtContext::ProcStyle(const CmdHelper::ArgumentsMap* amap) {
void UnvirtContext::ProcStyle(const CmdHelper::ArgumentsMap& amap) {
// set list style level
switch (*amap->Get<CmdHelper::Choice::vType>("level")) {
case 0:
switch (amap.Get<CmdHelper::Nodes::Choice::ArgValue_t>(u8"level").Get()) {
case 0u:
{
// full level
m_ListStyleIsFull = true;
break;
}
case 1:
case 1u:
{
// simple level
m_ListStyleIsFull = false;
break;
}
default:
throw std::runtime_error("unreachable code");
}
}
void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap* amap) {
const auto& encodings = *amap->Get<CmdHelper::EncodingArgument::vType>("enc");
void UnvirtContext::ProcEncoding(const CmdHelper::ArgumentsMap& amap) {
const auto& encodings = amap.Get<CmdHelper::Nodes::EncodingListArgument::ArgValue_t>(u8"enc").Get();
m_Ctx->SetEncoding(encodings);
}
void UnvirtContext::ProcTemp(const CmdHelper::ArgumentsMap* amap) {
void UnvirtContext::ProcTemp(const CmdHelper::ArgumentsMap& amap) {
// assign
if (!m_Ctx->GetPathManager()->SetTempFolder(amap->Get<CmdHelper::StringArgument::vType>("temppath")->c_str())) {
PrintCommonError("Set temp folder failed. Check your path first.");
std::u8string temp_path = amap.Get<CmdHelper::Nodes::StringArgument::ArgValue_t>(u8"temppath").Get();
if (!m_Ctx->GetPathManager()->SetTempFolder(temp_path.c_str())) {
PrintCommonError(u8"Set temp folder failed. Check your path first.");
}
}
void Unvirt::Context::UnvirtContext::ProcRsc(const CmdHelper::ArgumentsMap* amap, bool isClear) {
if (isClear) {
void Unvirt::Context::UnvirtContext::ProcRsc(const CmdHelper::ArgumentsMap& amap, bool is_clear) {
if (is_clear) {
m_Ctx->GetPathManager()->ClearPath();
} else {
if (!m_Ctx->GetPathManager()->AddPath(amap->Get<CmdHelper::StringArgument::vType>("datares")->c_str())) {
PrintCommonError("Set data resource folder failed. Check your path first.");
std::u8string data_res = amap.Get<CmdHelper::Nodes::StringArgument::ArgValue_t>(u8"datares").Get();
if (!m_Ctx->GetPathManager()->AddPath(data_res.c_str())) {
PrintCommonError(u8"Set data resource folder failed. Check your path first.");
}
}
}
void Unvirt::Context::UnvirtContext::ProcTest(const CmdHelper::ArgumentsMap* amap) {
void Unvirt::Context::UnvirtContext::ProcTest(const CmdHelper::ArgumentsMap& amap) {
#if defined(LIBCMO_BUILD_DEBUG)
// MARK: Add the debug code here.
@ -623,11 +676,11 @@ namespace Unvirt::Context {
// check pre-requirement
if (!HasOpenedFile()) {
PrintCommonError("No loaded file.");
PrintCommonError(u8"No loaded file.");
return;
}
if (!m_IsShallowRead) {
PrintCommonError("Transparent Column Fixer only accept shallow loaded file.");
PrintCommonError(u8"Transparent Column Fixer only accept shallow loaded file.");
return;
}
@ -653,21 +706,21 @@ namespace Unvirt::Context {
}
}
}
}
}
#else
PrintCommonError("Test command only available in Debug mode.");
PrintCommonError(u8"Test command only available in Debug mode.");
#endif
}
void Unvirt::Context::UnvirtContext::ProcHelp(const CmdHelper::ArgumentsMap&) {
m_Help.Print();
}
void Unvirt::Context::UnvirtContext::ProcHelp(const CmdHelper::ArgumentsMap*) {
m_Help->Print();
}
void UnvirtContext::ProcExit(const CmdHelper::ArgumentsMap*) {
void UnvirtContext::ProcExit(const CmdHelper::ArgumentsMap&) {
m_OrderExit = true;
}
#pragma endregion
}
}

View File

@ -2,13 +2,9 @@
#include <VTAll.hpp>
#include "AccessibleValue.hpp"
#include "TerminalHelper.hpp"
#include "StructFormatter.hpp"
#include "CmdHelper.hpp"
#include <cstdio>
#include <iostream>
namespace Unvirt::Context {
class UnvirtContext {
@ -23,39 +19,39 @@ namespace Unvirt::Context {
enum class SearchPart {
None, Object, Manager
};
void PrintCommonInfo(const char* u8_fmt, ...);
void PrintCommonError(const char* u8_fmt, ...);
void PrintCommonInfo(const char8_t* u8_fmt, ...);
void PrintCommonError(const char8_t* u8_fmt, ...);
void ProcLoad(const CmdHelper::ArgumentsMap* amap);
void ProcUnLoad(const CmdHelper::ArgumentsMap* amap);
void ProcSave(const CmdHelper::ArgumentsMap* amap);
void ProcInfo(const CmdHelper::ArgumentsMap* amap);
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);
void ProcTest(const CmdHelper::ArgumentsMap* amap);
void ProcHelp(const CmdHelper::ArgumentsMap* amap);
void ProcExit(const CmdHelper::ArgumentsMap* amap);
void ProcLoad(const CmdHelper::ArgumentsMap& amap);
void ProcUnLoad(const CmdHelper::ArgumentsMap& amap);
void ProcSave(const CmdHelper::ArgumentsMap& amap);
void ProcInfo(const CmdHelper::ArgumentsMap& amap);
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 is_clear);
void ProcTest(const CmdHelper::ArgumentsMap& amap);
void ProcHelp(const CmdHelper::ArgumentsMap& amap);
void ProcExit(const CmdHelper::ArgumentsMap& amap);
protected:
bool HasOpenedFile();
void ClearDocument();
void PrintContextMsg(LibCmo::CKSTRING msg);
CmdHelper::CommandRoot m_Root;
CmdHelper::HelpDocument* m_Help;
CmdHelper::CmdSplitter m_Splitter;
CmdHelper::CommandParser m_Parser;
CmdHelper::HelpDocument m_Help;
size_t m_PageLen;
bool m_ListStyleIsFull;
SearchPart m_SearchPart;
LibCmo::XContainer::XArray<size_t> m_SearchIdxResult;
std::vector<size_t> m_SearchIdxResult;
bool m_OrderExit;
LibCmo::CK2::CKContext* m_Ctx;