update cmd. improve encoding
This commit is contained in:
parent
e166b8ec5b
commit
79aaf6b1ea
|
@ -14,8 +14,7 @@ namespace LibCmo::CK2 {
|
||||||
#pragma region Ctor Dtor
|
#pragma region Ctor Dtor
|
||||||
|
|
||||||
CKMinContext::CKMinContext() :
|
CKMinContext::CKMinContext() :
|
||||||
m_NameEncoding(), m_NameEncodingToken(EncodingHelper::ENCODING_TOKEN_DEFAULT),
|
m_NameEncoding(), m_TempFolder(),
|
||||||
m_TempFolder(),
|
|
||||||
m_PrintCallback(nullptr),
|
m_PrintCallback(nullptr),
|
||||||
m_CKObjectMaxID(0u),
|
m_CKObjectMaxID(0u),
|
||||||
// register CKObjects
|
// register CKObjects
|
||||||
|
@ -106,6 +105,15 @@ namespace LibCmo::CK2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CKMinContext::ClearCKObject(void) {
|
||||||
|
// free all created objects
|
||||||
|
for (const auto& [key, value] : this->m_ObjectsList) {
|
||||||
|
delete value;
|
||||||
|
}
|
||||||
|
// clear list
|
||||||
|
this->m_ObjectsList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
CK_ID CKMinContext::GetObjectMaxID(void) {
|
CK_ID CKMinContext::GetObjectMaxID(void) {
|
||||||
return this->m_CKObjectMaxID;
|
return this->m_CKObjectMaxID;
|
||||||
}
|
}
|
||||||
|
@ -122,17 +130,45 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
#pragma region Misc Funcs
|
#pragma region Misc Funcs
|
||||||
|
|
||||||
void CKMinContext::GetUtf8String(std::string& native_name, std::string& u8_name) {
|
void CKMinContext::GetUtf8String(const std::string& native_name, std::string& u8_name) {
|
||||||
EncodingHelper::GetUtf8VirtoolsName(native_name, u8_name, this->m_NameEncodingToken);
|
bool success = false;
|
||||||
|
for (const auto& token : this->m_NameEncoding) {
|
||||||
|
success = LibCmo::EncodingHelper::GetUtf8VirtoolsName(native_name, u8_name, token);
|
||||||
|
if (success) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKMinContext::GetNativeString(std::string& u8_name, std::string& native_name) {
|
// fallback
|
||||||
EncodingHelper::GetNativeVirtoolsName(u8_name, native_name, this->m_NameEncodingToken);
|
if (!success) {
|
||||||
|
u8_name = native_name;
|
||||||
|
this->Printf("Error when converting to UTF8 string.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKMinContext::SetEncoding(CKSTRING encoding) {
|
void CKMinContext::GetNativeString(const std::string& u8_name, std::string& native_name) {
|
||||||
this->m_NameEncoding = encoding;
|
bool success = false;
|
||||||
this->RefetchEncodingToken();
|
for (const auto& token : this->m_NameEncoding) {
|
||||||
|
success = LibCmo::EncodingHelper::GetNativeVirtoolsName(u8_name, native_name, token);
|
||||||
|
if (success) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
if (!success) {
|
||||||
|
native_name = u8_name;
|
||||||
|
this->Printf("Error when converting to native string.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CKMinContext::SetEncoding(const std::vector<std::string> encoding_series) {
|
||||||
|
// free all current series
|
||||||
|
for (const auto& encoding : this->m_NameEncoding) {
|
||||||
|
LibCmo::EncodingHelper::DestroyEncodingToken(encoding);
|
||||||
|
}
|
||||||
|
this->m_NameEncoding.clear();
|
||||||
|
|
||||||
|
// add new encoding
|
||||||
|
for (const auto& encoding_str : encoding_series) {
|
||||||
|
this->m_NameEncoding.push_back(LibCmo::EncodingHelper::CreateEncodingToken(encoding_str));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKMinContext::SetTempPath(CKSTRING u8_temp) {
|
void CKMinContext::SetTempPath(CKSTRING u8_temp) {
|
||||||
|
@ -147,10 +183,6 @@ namespace LibCmo::CK2 {
|
||||||
return EncodingHelper::OpenStdPathFile(realfile, is_read);
|
return EncodingHelper::OpenStdPathFile(realfile, is_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CKMinContext::RefetchEncodingToken(void) {
|
|
||||||
EncodingHelper::DestroyEncodingToken(this->m_NameEncodingToken);
|
|
||||||
this->m_NameEncodingToken = EncodingHelper::CreateEncodingToken(this->m_NameEncoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,14 @@ namespace LibCmo::CK2 {
|
||||||
CKMinContext& operator=(const CKMinContext&) = delete;
|
CKMinContext& operator=(const CKMinContext&) = delete;
|
||||||
~CKMinContext();
|
~CKMinContext();
|
||||||
|
|
||||||
using PrintCallback = void (*)(std::string&);
|
using PrintCallback = std::function<void(const std::string&)>;
|
||||||
void Printf(CKSTRING fmt, ...);
|
void Printf(CKSTRING fmt, ...);
|
||||||
void SetPrintCallback(PrintCallback cb);
|
void SetPrintCallback(PrintCallback cb);
|
||||||
|
|
||||||
CKObjectImplements::CKObject* CreateCKObject(CK_ID id, CK_CLASSID cls, CKSTRING name);
|
CKObjectImplements::CKObject* CreateCKObject(CK_ID id, CK_CLASSID cls, CKSTRING name);
|
||||||
CKObjectImplements::CKObject* GetCKObject(CK_ID id);
|
CKObjectImplements::CKObject* GetCKObject(CK_ID id);
|
||||||
void DestroyCKObject(CK_ID id);
|
void DestroyCKObject(CK_ID id);
|
||||||
|
void ClearCKObject(void);
|
||||||
|
|
||||||
//CKManagerImplements::CKBaseManager* CreateCKManager(CKGUID guid);
|
//CKManagerImplements::CKBaseManager* CreateCKManager(CKGUID guid);
|
||||||
//CKManagerImplements::CKBaseManager* GetCKManager(CK_ID guid);
|
//CKManagerImplements::CKBaseManager* GetCKManager(CK_ID guid);
|
||||||
|
@ -31,17 +32,15 @@ namespace LibCmo::CK2 {
|
||||||
CK_ID GetObjectMaxID(void);
|
CK_ID GetObjectMaxID(void);
|
||||||
void SetObjectMaxID(CK_ID id);
|
void SetObjectMaxID(CK_ID id);
|
||||||
|
|
||||||
void GetUtf8String(std::string& native_name, std::string& u8_name);
|
void GetUtf8String(const std::string& native_name, std::string& u8_name);
|
||||||
void GetNativeString(std::string& u8_name, std::string& native_name);
|
void GetNativeString(const std::string& u8_name, std::string& native_name);
|
||||||
|
|
||||||
void SetEncoding(CKSTRING encoding);
|
void SetEncoding(const std::vector<std::string> encoding_series);
|
||||||
void SetTempPath(CKSTRING u8_temp);
|
void SetTempPath(CKSTRING u8_temp);
|
||||||
|
|
||||||
FILE* OpenTempFile(CKSTRING u8_filename, bool is_read);
|
FILE* OpenTempFile(CKSTRING u8_filename, bool is_read);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RefetchEncodingToken(void);
|
|
||||||
|
|
||||||
std::map<CK_ID, CKObjectImplements::CKObject*> m_ObjectsList;
|
std::map<CK_ID, CKObjectImplements::CKObject*> m_ObjectsList;
|
||||||
std::map<CK_ID, CKManagerImplements::CKBaseManager*> m_ManagersList;
|
std::map<CK_ID, CKManagerImplements::CKBaseManager*> m_ManagersList;
|
||||||
|
|
||||||
|
@ -50,8 +49,7 @@ namespace LibCmo::CK2 {
|
||||||
|
|
||||||
CK_ID m_CKObjectMaxID;
|
CK_ID m_CKObjectMaxID;
|
||||||
|
|
||||||
std::string m_NameEncoding;
|
std::vector<EncodingHelper::ENCODING_TOKEN> m_NameEncoding;
|
||||||
EncodingHelper::ENCODING_TOKEN m_NameEncodingToken;
|
|
||||||
std::filesystem::path m_TempFolder;
|
std::filesystem::path m_TempFolder;
|
||||||
PrintCallback m_PrintCallback;
|
PrintCallback m_PrintCallback;
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace LibCmo::EncodingHelper {
|
||||||
}
|
}
|
||||||
#undef LIBCMO_STR_EQUAL
|
#undef LIBCMO_STR_EQUAL
|
||||||
|
|
||||||
bool WcharToChar(const wchar_t* src, std::string& dest, UINT codepage) {
|
bool WcharToChar(const wchar_t* src, std::string& dest, const UINT codepage) {
|
||||||
int count, write_result;
|
int count, write_result;
|
||||||
|
|
||||||
//converter to CHAR
|
//converter to CHAR
|
||||||
|
@ -38,11 +38,11 @@ namespace LibCmo::EncodingHelper {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool WcharToChar(std::wstring& src, std::string& dest, UINT codepage) {
|
bool WcharToChar(const std::wstring& src, std::string& dest, const UINT codepage) {
|
||||||
return WcharToChar(src.c_str(), dest, codepage);
|
return WcharToChar(src.c_str(), dest, codepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharToWchar(const char* src, std::wstring& dest, UINT codepage) {
|
bool CharToWchar(const char* src, std::wstring& dest, const UINT codepage) {
|
||||||
int wcount, write_result;
|
int wcount, write_result;
|
||||||
|
|
||||||
// convert to WCHAR
|
// convert to WCHAR
|
||||||
|
@ -55,17 +55,17 @@ namespace LibCmo::EncodingHelper {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool CharToWchar(std::string& src, std::wstring& dest, UINT codepage) {
|
bool CharToWchar(const std::string& src, std::wstring& dest, const UINT codepage) {
|
||||||
return CharToWchar(src.c_str(), dest, codepage);
|
return CharToWchar(src.c_str(), dest, codepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharToChar(const char* src, std::string& dest, UINT src_codepage, UINT dest_codepage) {
|
bool CharToChar(const char* src, std::string& dest, const UINT src_codepage, const UINT dest_codepage) {
|
||||||
std::wstring intermediary;
|
std::wstring intermediary;
|
||||||
if (!CharToWchar(src, intermediary, src_codepage)) return false;
|
if (!CharToWchar(src, intermediary, src_codepage)) return false;
|
||||||
if (!WcharToChar(intermediary, dest, dest_codepage)) return false;
|
if (!WcharToChar(intermediary, dest, dest_codepage)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool CharToChar(std::string& src, std::string& dest, UINT src_codepage, UINT dest_codepage) {
|
bool CharToChar(const std::string& src, std::string& dest, const UINT src_codepage, const UINT dest_codepage) {
|
||||||
return CharToChar(src.c_str(), dest, src_codepage, dest_codepage);
|
return CharToChar(src.c_str(), dest, src_codepage, dest_codepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ namespace LibCmo::EncodingHelper {
|
||||||
|
|
||||||
#if defined(LIBCMO_OS_WIN32)
|
#if defined(LIBCMO_OS_WIN32)
|
||||||
|
|
||||||
ENCODING_TOKEN CreateEncodingToken(std::string& token_string) {
|
ENCODING_TOKEN CreateEncodingToken(const std::string& token_string) {
|
||||||
ENCODING_TOKEN token = new(std::nothrow) UINT();
|
ENCODING_TOKEN token = new(std::nothrow) UINT();
|
||||||
if (token == nullptr) return ENCODING_TOKEN_DEFAULT;
|
if (token == nullptr) return ENCODING_TOKEN_DEFAULT;
|
||||||
|
|
||||||
|
@ -153,34 +153,20 @@ namespace LibCmo::EncodingHelper {
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
void DestroyEncodingToken(ENCODING_TOKEN token) {
|
void DestroyEncodingToken(const ENCODING_TOKEN& token) {
|
||||||
if (token != ENCODING_TOKEN_DEFAULT) {
|
if (token != ENCODING_TOKEN_DEFAULT) {
|
||||||
delete token;
|
delete token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetUtf8VirtoolsName(std::string& native_name, std::string& u8_name, ENCODING_TOKEN token) {
|
bool GetUtf8VirtoolsName(const std::string& native_name, std::string& u8_name, const ENCODING_TOKEN& token) {
|
||||||
if (token == ENCODING_TOKEN_DEFAULT) {
|
if (token == ENCODING_TOKEN_DEFAULT) return false;
|
||||||
u8_name = native_name.c_str();
|
return CharToChar(native_name, u8_name, *token, CP_UTF8);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert with fallback
|
bool GetNativeVirtoolsName(const std::string& u8_name, std::string& native_name, const ENCODING_TOKEN& token) {
|
||||||
if (!CharToChar(native_name, u8_name, *token, CP_UTF8)) {
|
if (token == ENCODING_TOKEN_DEFAULT) return false;
|
||||||
u8_name = native_name.c_str();
|
return CharToChar(u8_name, native_name, CP_UTF8, *token);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetNativeVirtoolsName(std::string& u8_name, std::string& native_name, ENCODING_TOKEN token) {
|
|
||||||
if (token == ENCODING_TOKEN_DEFAULT) {
|
|
||||||
native_name = u8_name.c_str();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert with fallback
|
|
||||||
if (!CharToChar(u8_name, native_name, CP_UTF8, *token)) {
|
|
||||||
native_name = u8_name.c_str();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStdPathFromU8Path(std::filesystem::path& stdpath, const char* u8_path) {
|
void SetStdPathFromU8Path(std::filesystem::path& stdpath, const char* u8_path) {
|
||||||
|
|
|
@ -19,14 +19,14 @@ namespace LibCmo::EncodingHelper {
|
||||||
|
|
||||||
bool GetWindowsCodePage(const char* u8_encoding_spec, UINT* result);
|
bool GetWindowsCodePage(const char* u8_encoding_spec, UINT* result);
|
||||||
|
|
||||||
bool WcharToChar(const wchar_t* src, std::string& dest, UINT codepage);
|
bool WcharToChar(const wchar_t* src, std::string& dest, const UINT codepage);
|
||||||
bool WcharToChar(std::wstring& src, std::string& dest, UINT codepage);
|
bool WcharToChar(const std::wstring& src, std::string& dest, const UINT codepage);
|
||||||
|
|
||||||
bool CharToWchar(const char* src, std::wstring& dest, UINT codepage);
|
bool CharToWchar(const char* src, std::wstring& dest, const UINT codepage);
|
||||||
bool CharToWchar(std::string& src, std::wstring& dest, UINT codepage);
|
bool CharToWchar(const std::string& src, std::wstring& dest, const UINT codepage);
|
||||||
|
|
||||||
bool CharToChar(const char* src, std::string& dest, UINT src_codepage, UINT dest_codepage);
|
bool CharToChar(const char* src, std::string& dest, const UINT src_codepage, const UINT dest_codepage);
|
||||||
bool CharToChar(std::string& src, std::string& dest, UINT src_codepage, UINT dest_codepage);
|
bool CharToChar(const std::string& src, std::string& dest, const UINT src_codepage, const UINT dest_codepage);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ namespace LibCmo::EncodingHelper {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ENCODING_TOKEN CreateEncodingToken(std::string& token_string);
|
ENCODING_TOKEN CreateEncodingToken(const std::string& token_string);
|
||||||
void DestroyEncodingToken(ENCODING_TOKEN token);
|
void DestroyEncodingToken(const ENCODING_TOKEN& token);
|
||||||
|
|
||||||
void GetUtf8VirtoolsName(std::string& native_name, std::string& u8_name, ENCODING_TOKEN token);
|
bool GetUtf8VirtoolsName(const std::string& native_name, std::string& u8_name, const ENCODING_TOKEN& token);
|
||||||
void GetNativeVirtoolsName(std::string& u8_name, std::string& native_name, ENCODING_TOKEN token);
|
bool GetNativeVirtoolsName(const std::string& u8_name, std::string& native_name, const ENCODING_TOKEN& token);
|
||||||
|
|
||||||
void SetStdPathFromU8Path(std::filesystem::path& stdpath, const char* u8_path);
|
void SetStdPathFromU8Path(std::filesystem::path& stdpath, const char* u8_path);
|
||||||
FILE* OpenStdPathFile(std::filesystem::path& u8_filepath, bool is_read);
|
FILE* OpenStdPathFile(std::filesystem::path& u8_filepath, bool is_read);
|
||||||
|
|
|
@ -9,17 +9,12 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
#include <functional>
|
||||||
/* TODO:
|
|
||||||
do not re-allocated ctx and file for each loading in future.
|
|
||||||
this will be implemented by free all objects within doc.
|
|
||||||
|
|
||||||
split encoding and temp folder setting
|
|
||||||
and load command only have file name arg.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Unvirt::CmdHelper {
|
namespace Unvirt::CmdHelper {
|
||||||
|
|
||||||
|
static FILE* fout = stdout;
|
||||||
|
|
||||||
#pragma region CmdSplitter
|
#pragma region CmdSplitter
|
||||||
|
|
||||||
CmdSplitter::CmdSplitter() :
|
CmdSplitter::CmdSplitter() :
|
||||||
|
@ -42,7 +37,11 @@ namespace Unvirt::CmdHelper {
|
||||||
// split
|
// split
|
||||||
for (auto it = u8cmd.begin(); it != u8cmd.end(); ++it) {
|
for (auto it = u8cmd.begin(); it != u8cmd.end(); ++it) {
|
||||||
mCmdChar = (*it);
|
mCmdChar = (*it);
|
||||||
if (!std::isprint(mCmdChar)) continue; // skip all invalid characters
|
|
||||||
|
// skip all invalid characters, \0 and etc.
|
||||||
|
// mCmdChar >= 0 to ensure all non-ASCII UTF8 char can be accepted directly.
|
||||||
|
if (mCmdChar >= 0 && (!std::isprint(mCmdChar)))
|
||||||
|
continue;
|
||||||
|
|
||||||
switch (mState) {
|
switch (mState) {
|
||||||
case StateType::SPACE:
|
case StateType::SPACE:
|
||||||
|
@ -135,20 +134,54 @@ namespace Unvirt::CmdHelper {
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region InteractiveCmd
|
#pragma region InteractiveCmd Misc
|
||||||
|
|
||||||
InteractiveCmd::InteractiveCmd() :
|
InteractiveCmd::InteractiveCmd() :
|
||||||
m_CmdSplitter(), m_PageLen(10),
|
m_CmdSplitter(), m_PageLen(10),
|
||||||
m_Ctx(nullptr), m_File(nullptr), m_Doc(nullptr) {
|
m_Ctx(nullptr), m_File(nullptr), m_Doc(nullptr) {
|
||||||
|
|
||||||
|
// create context and file
|
||||||
|
m_Ctx = new LibCmo::CK2::CKMinContext();
|
||||||
|
m_File = new LibCmo::CK2::CKFile(m_Ctx);
|
||||||
|
|
||||||
|
// bind callback
|
||||||
|
m_Ctx->SetPrintCallback(std::bind(&InteractiveCmd::PrintMinContextMsg, this, std::placeholders::_1));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractiveCmd::~InteractiveCmd() {
|
InteractiveCmd::~InteractiveCmd() {
|
||||||
|
// delete doc if necessary
|
||||||
if (m_Doc != nullptr) delete m_Doc;
|
if (m_Doc != nullptr) delete m_Doc;
|
||||||
if (m_File != nullptr) delete m_File;
|
// delete file and ctx
|
||||||
if (m_Ctx != nullptr) delete m_Ctx;
|
delete m_File;
|
||||||
|
delete m_Ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InteractiveCmd::HasOpenedFile(void) {
|
||||||
|
return m_Doc != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractiveCmd::ClearDocument(void) {
|
||||||
|
if (m_Doc == nullptr) return;
|
||||||
|
|
||||||
|
// clear doc
|
||||||
|
delete m_Doc;
|
||||||
|
m_Doc = nullptr;
|
||||||
|
|
||||||
|
// clear all loaded objects
|
||||||
|
m_Ctx->ClearCKObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractiveCmd::PrintMinContextMsg(const std::string& msg) {
|
||||||
|
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("[CKMinContext] ")), fout);
|
||||||
|
fputs(msg.c_str(), fout);
|
||||||
|
fputc('\n', fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region InteractiveCmd Dispatch
|
||||||
|
|
||||||
void InteractiveCmd::Run(void) {
|
void InteractiveCmd::Run(void) {
|
||||||
std::string u8cmd;
|
std::string u8cmd;
|
||||||
|
|
||||||
|
@ -174,6 +207,8 @@ namespace Unvirt::CmdHelper {
|
||||||
else if (subcmd == "info") this->ProcInfo(cmds);
|
else if (subcmd == "info") this->ProcInfo(cmds);
|
||||||
else if (subcmd == "ls") this->ProcLs(cmds);
|
else if (subcmd == "ls") this->ProcLs(cmds);
|
||||||
else if (subcmd == "items") this->ProcItems(cmds);
|
else if (subcmd == "items") this->ProcItems(cmds);
|
||||||
|
else if (subcmd == "encoding") this->ProcEncoding(cmds);
|
||||||
|
else if (subcmd == "temp") this->ProcTemp(cmds);
|
||||||
else if (subcmd == "help") this->PrintHelp();
|
else if (subcmd == "help") this->PrintHelp();
|
||||||
else if (subcmd == "exit") break;
|
else if (subcmd == "exit") break;
|
||||||
else {
|
else {
|
||||||
|
@ -185,7 +220,7 @@ namespace Unvirt::CmdHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InteractiveCmd::GetCmdLine(std::string& u8cmd) {
|
void InteractiveCmd::GetCmdLine(std::string& u8cmd) {
|
||||||
fputs("Unvirt> ", stdout);
|
fputs("Unvirt> ", fout);
|
||||||
#if defined(LIBCMO_OS_WIN32)
|
#if defined(LIBCMO_OS_WIN32)
|
||||||
std::wstring wcmd;
|
std::wstring wcmd;
|
||||||
std::getline(std::wcin, wcmd);
|
std::getline(std::wcin, wcmd);
|
||||||
|
@ -195,45 +230,48 @@ namespace Unvirt::CmdHelper {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InteractiveCmd::HasOpenedFile(void) {
|
|
||||||
return (m_Ctx != nullptr || m_File != nullptr || m_Doc != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InteractiveCmd::PrintHelp(void) {
|
void InteractiveCmd::PrintHelp(void) {
|
||||||
FILE* f = stdout;
|
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Subcommands: \n")), fout);
|
||||||
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Subcommands: \n")), f);
|
|
||||||
|
|
||||||
fputs("load\n", f);
|
fputs("load\n", fout);
|
||||||
fputs("\tDescription: Load a Virtools composition.\n", f);
|
fputs("\tDescription: Load a Virtools composition.\n", fout);
|
||||||
fputs("\tSyntax: load <file path> [encoding] [temp path]\n", f);
|
fputs("\tSyntax: load <file path>\n", fout);
|
||||||
|
|
||||||
fputs("unload\n", f);
|
fputs("unload\n", fout);
|
||||||
fputs("\tDescription: Release loaded Virtools composition.\n", f);
|
fputs("\tDescription: Release loaded Virtools composition.\n", fout);
|
||||||
fputs("\tSyntax: unload\n", f);
|
fputs("\tSyntax: unload\n", fout);
|
||||||
|
|
||||||
fputs("info\n", f);
|
fputs("info\n", fout);
|
||||||
fputs("\tDescription: Show the header info of loaded Virtools composition.\n", f);
|
fputs("\tDescription: Show the header info of loaded Virtools composition.\n", fout);
|
||||||
fputs("\tSyntax: info\n", f);
|
fputs("\tSyntax: info\n", fout);
|
||||||
|
|
||||||
fputs("ls\n", f);
|
fputs("ls\n", fout);
|
||||||
fputs("\tDescription: List something about loaded Virtools composition.\n", f);
|
fputs("\tDescription: List something about loaded Virtools composition.\n", fout);
|
||||||
fputs("\tSyntax: ls <obj | mgr> [page]\n", f);
|
fputs("\tSyntax: ls <obj | mgr> [page]\n", fout);
|
||||||
|
|
||||||
fputs("items\n", f);
|
fputs("items\n", fout);
|
||||||
fputs("\tDescription: Set up how many items should be listed in one page when using \"ls\" command.\n", f);
|
fputs("\tDescription: Set up how many items should be listed in one page when using \"ls\" command.\n", fout);
|
||||||
fputs("\tSyntax: items <num>\n", f);
|
fputs("\tSyntax: items <num>\n", fout);
|
||||||
|
|
||||||
fputs("exit\n", f);
|
fputs("encoding\n", fout);
|
||||||
fputs("\tDescription: Exit program\n", f);
|
fputs("\tDescription: Set the encoding series for CKMinContext.\n", fout);
|
||||||
fputs("\tSyntax: exit\n", f);
|
fputs("\tSyntax: encoding [encoding name1] [encoding name2] [encoding name3] ...\n", fout);
|
||||||
|
|
||||||
|
fputs("temp\n", fout);
|
||||||
|
fputs("\tDescription: Set the Temp path for CKMinContext.\n", fout);
|
||||||
|
fputs("\tSyntax: temp <temp path>\n", fout);
|
||||||
|
|
||||||
|
fputs("exit\n", fout);
|
||||||
|
fputs("\tDescription: Exit program\n", fout);
|
||||||
|
fputs("\tSyntax: exit\n", fout);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InteractiveCmd::PrintArgParseError(const std::deque<std::string>& cmd, size_t pos) {
|
void InteractiveCmd::PrintArgParseError(const std::deque<std::string>& cmd, size_t pos) {
|
||||||
if (pos >= cmd.size()) {
|
if (pos >= cmd.size()) {
|
||||||
fprintf(stdout, UNVIRT_TERMCOL_LIGHT_RED(("Lost argument at position %zu.\n")), pos);
|
fprintf(fout, UNVIRT_TERMCOL_LIGHT_RED(("Lost argument at position %zu.\n")), pos);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stdout, UNVIRT_TERMCOL_LIGHT_RED(("Unexpected argument \"%s\".\n")), cmd[pos].c_str());
|
fprintf(fout, UNVIRT_TERMCOL_LIGHT_RED(("Unexpected argument \"%s\".\n")), cmd[pos].c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// arg error always print help
|
// arg error always print help
|
||||||
|
@ -243,17 +281,17 @@ namespace Unvirt::CmdHelper {
|
||||||
void InteractiveCmd::PrintCommonError(const char* u8_fmt, ...) {
|
void InteractiveCmd::PrintCommonError(const char* u8_fmt, ...) {
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
va_start(argptr, u8_fmt);
|
va_start(argptr, u8_fmt);
|
||||||
std::fputs(UNVIRT_TERMCOLHDR_LIGHT_RED, stdout);
|
std::fputs(UNVIRT_TERMCOLHDR_LIGHT_RED, fout);
|
||||||
std::vfprintf(stdout, u8_fmt, argptr);
|
std::vfprintf(fout, u8_fmt, argptr);
|
||||||
std::fputs(UNVIRT_TERMCOLTAIL, stdout);
|
std::fputs(UNVIRT_TERMCOLTAIL, fout);
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
std::fputc('\n', stdout);
|
std::fputc('\n', fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Command Processors
|
#pragma region InteractiveCmd Processors
|
||||||
|
|
||||||
void InteractiveCmd::ProcLoad(const std::deque<std::string>& cmd) {
|
void InteractiveCmd::ProcLoad(const std::deque<std::string>& cmd) {
|
||||||
// check pre-requirement
|
// check pre-requirement
|
||||||
|
@ -269,25 +307,8 @@ namespace Unvirt::CmdHelper {
|
||||||
this->PrintArgParseError(cmd, pos);
|
this->PrintArgParseError(cmd, pos);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
++pos;
|
|
||||||
std::string encoding;
|
|
||||||
if (!ArgParser::ParseString(cmd, pos, encoding)) {
|
|
||||||
this->PrintArgParseError(cmd, pos);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++pos;
|
|
||||||
std::string temppath;
|
|
||||||
if (!ArgParser::ParseString(cmd, pos, temppath)) {
|
|
||||||
this->PrintArgParseError(cmd, pos);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// proc
|
// proc
|
||||||
m_Ctx = new LibCmo::CK2::CKMinContext();
|
|
||||||
m_Ctx->SetEncoding(encoding.c_str());
|
|
||||||
m_Ctx->SetTempPath(temppath.c_str());
|
|
||||||
|
|
||||||
m_File = new LibCmo::CK2::CKFile(m_Ctx);
|
|
||||||
m_Doc = new LibCmo::CK2::CKFileDocument();
|
m_Doc = new LibCmo::CK2::CKFileDocument();
|
||||||
LibCmo::CK2::CKERROR err = m_File->DeepLoad(filepath.c_str(), &m_Doc);
|
LibCmo::CK2::CKERROR err = m_File->DeepLoad(filepath.c_str(), &m_Doc);
|
||||||
if (err != LibCmo::CK2::CKERROR::CKERR_OK) {
|
if (err != LibCmo::CK2::CKERROR::CKERR_OK) {
|
||||||
|
@ -297,13 +318,7 @@ namespace Unvirt::CmdHelper {
|
||||||
Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str()
|
Unvirt::AccessibleValue::GetCkErrorDescription(err).c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (m_Doc != nullptr) delete m_Doc;
|
this->ClearDocument();
|
||||||
if (m_File != nullptr) delete m_File;
|
|
||||||
if (m_Ctx != nullptr) delete m_Ctx;
|
|
||||||
|
|
||||||
m_Doc = nullptr;
|
|
||||||
m_File = nullptr;
|
|
||||||
m_Ctx = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,13 +330,7 @@ namespace Unvirt::CmdHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// free all
|
// free all
|
||||||
if (m_Doc != nullptr) delete m_Doc;
|
this->ClearDocument();
|
||||||
if (m_File != nullptr) delete m_File;
|
|
||||||
if (m_Ctx != nullptr) delete m_Ctx;
|
|
||||||
|
|
||||||
m_Doc = nullptr;
|
|
||||||
m_File = nullptr;
|
|
||||||
m_Ctx = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InteractiveCmd::ProcInfo(const std::deque<std::string>& cmd) {
|
void InteractiveCmd::ProcInfo(const std::deque<std::string>& cmd) {
|
||||||
|
@ -356,10 +365,14 @@ namespace Unvirt::CmdHelper {
|
||||||
}
|
}
|
||||||
++pos;
|
++pos;
|
||||||
int32_t gotten_page;
|
int32_t gotten_page;
|
||||||
if (!ArgParser::ParseInt(cmd, pos, gotten_page) || gotten_page <= 0) {
|
if (!ArgParser::ParseInt(cmd, pos, gotten_page)) {
|
||||||
gotten_page = 0; // asssume as zero
|
gotten_page = 1; // asssume as 1
|
||||||
}
|
}
|
||||||
size_t page = static_cast<size_t>(gotten_page);
|
if (gotten_page <= 0) {
|
||||||
|
this->PrintCommonError("Page out of range.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t page = static_cast<size_t>(gotten_page) - 1;
|
||||||
|
|
||||||
// show list
|
// show list
|
||||||
if (sw == c_AllowedSwitches[0]) {
|
if (sw == c_AllowedSwitches[0]) {
|
||||||
|
@ -396,383 +409,40 @@ namespace Unvirt::CmdHelper {
|
||||||
m_PageLen = static_cast<size_t>(count);
|
m_PageLen = static_cast<size_t>(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
void InteractiveCmd::ProcEncoding(const std::deque<std::string>& cmd) {
|
||||||
|
// create list first
|
||||||
|
std::vector<std::string> encoding_list;
|
||||||
|
|
||||||
|
// get list item
|
||||||
/*
|
size_t pos = 0u;
|
||||||
|
|
||||||
#pragma region OptionsDescription
|
|
||||||
|
|
||||||
OptionsDescription::OptionsDescription() :
|
|
||||||
mLongNameDict(), mShortNameMapping(), mPositionalArgMapping() {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
OptionsDescription::~OptionsDescription() { ; }
|
|
||||||
|
|
||||||
void OptionsDescription::AddOption(
|
|
||||||
const char* fullname, char shortname, CmdArgType type, const char* description) {
|
|
||||||
// pre-check
|
|
||||||
if (fullname == nullptr ||
|
|
||||||
fullname[0] == '\0' ||
|
|
||||||
fullname[0] == '-')
|
|
||||||
throw std::invalid_argument("Invalid Option Long Name.");
|
|
||||||
|
|
||||||
// construct data
|
|
||||||
std::string sfullname(fullname);
|
|
||||||
OptionDescription data{
|
|
||||||
fullname, shortname, type, (description != nullptr ? description : "")
|
|
||||||
};
|
|
||||||
|
|
||||||
// check requirement
|
|
||||||
if (mLongNameDict.contains(sfullname)) throw std::invalid_argument("Duplicated Option Long Name.");
|
|
||||||
if (shortname != '\0')
|
|
||||||
if (mShortNameMapping.contains(shortname)) throw std::invalid_argument("Duplicated Option Short Name.");
|
|
||||||
|
|
||||||
// add them
|
|
||||||
mShortNameMapping.emplace(shortname, sfullname);
|
|
||||||
mLongNameDict.emplace(sfullname, std::move(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
void OptionsDescription::AddPositionalOption(const char* corresponding_longname) {
|
|
||||||
// pre-check
|
|
||||||
if (corresponding_longname == nullptr) throw std::invalid_argument("Invalid Option Long Name.");
|
|
||||||
|
|
||||||
// construct data
|
|
||||||
std::string fullname(corresponding_longname);
|
|
||||||
|
|
||||||
// check requirement
|
|
||||||
if (!mLongNameDict.contains(fullname)) throw std::invalid_argument("No Matched Option.");
|
|
||||||
if (!mPositionalArgMapping.empty()) {
|
|
||||||
for (const auto& i : mPositionalArgMapping) {
|
|
||||||
if (i == fullname)throw std::invalid_argument("Duplicated Option.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set value
|
|
||||||
mPositionalArgMapping.push_back(std::move(fullname));
|
|
||||||
}
|
|
||||||
|
|
||||||
OptionDescription* OptionsDescription::GetDescByLongName(const std::string& longname) {
|
|
||||||
const auto search = mLongNameDict.find(longname);
|
|
||||||
if (search == mLongNameDict.end()) return nullptr;
|
|
||||||
return &(*search).second;
|
|
||||||
}
|
|
||||||
OptionDescription* OptionsDescription::GetDescByShortName(const char shortname) {
|
|
||||||
const auto search = mShortNameMapping.find(shortname);
|
|
||||||
if (search == mShortNameMapping.end()) return nullptr;
|
|
||||||
return GetDescByLongName((*search).second);
|
|
||||||
}
|
|
||||||
OptionDescription* OptionsDescription::GetDescByPosition(size_t pos) {
|
|
||||||
if (pos >= mPositionalArgMapping.size()) return nullptr;
|
|
||||||
return GetDescByLongName(mPositionalArgMapping[pos]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OptionsDescription::PrintHelp(FILE* f) {
|
|
||||||
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Options: \n")), f);
|
|
||||||
for (const auto& [key, value] : mLongNameDict) {
|
|
||||||
fprintf(f, "--%s\t%s\n", value.mLongName.c_str(), value.mDescription.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mPositionalArgMapping.empty()) {
|
|
||||||
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("\nPositional Options: \n")), f);
|
|
||||||
for (const auto& i : mPositionalArgMapping) {
|
|
||||||
fprintf(f, "[%s] ", i.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
#pragma region VariablesMap
|
|
||||||
|
|
||||||
VariablesMap::VariablesMap() : mDataPair() {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
VariablesMap::~VariablesMap() {
|
|
||||||
this->Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VariablesMap::Clear(void) {
|
|
||||||
for (const auto& [key, value] : mDataPair) {
|
|
||||||
if (value.mData != nullptr) free(value.mData);
|
|
||||||
}
|
|
||||||
mDataPair.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VariablesMap::AddPair(const std::string& name, CmdArgType t, const std::string& val) {
|
|
||||||
if (mDataPair.contains(name)) return false;
|
|
||||||
|
|
||||||
AnyVariable var;
|
|
||||||
switch (t) {
|
|
||||||
case Unvirt::CmdHelper::CmdArgType::NONE:
|
|
||||||
{
|
|
||||||
var.mDataBasicSize = 1;
|
|
||||||
var.mData = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Unvirt::CmdHelper::CmdArgType::STRING:
|
|
||||||
{
|
|
||||||
var.mDataBasicSize = sizeof(char);
|
|
||||||
var.mData = malloc(val.size() + 1);
|
|
||||||
if (var.mData == nullptr) break;
|
|
||||||
|
|
||||||
memcpy(var.mData, val.c_str(), val.size() + 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Unvirt::CmdHelper::CmdArgType::INT:
|
|
||||||
{
|
|
||||||
var.mDataBasicSize = sizeof(int);
|
|
||||||
var.mData = malloc(sizeof(int));
|
|
||||||
if (var.mData == nullptr) break;
|
|
||||||
|
|
||||||
char* pend = nullptr;
|
|
||||||
errno = 0;
|
|
||||||
int64_t v = std::strtoll(val.c_str(), &pend, 10);
|
|
||||||
|
|
||||||
if (pend == val.c_str() || errno == ERANGE) v = INT64_C(0);
|
|
||||||
*((int*)var.mData) = static_cast<int>(v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument("Invalid Option Type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
mDataPair.emplace(name, std::move(var));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
#pragma region ExecEnvironment
|
|
||||||
|
|
||||||
ExecEnvironment::ExecEnvironment() :
|
|
||||||
mVtFile(nullptr), mVtFileEnv(nullptr) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecEnvironment::~ExecEnvironment() {
|
|
||||||
if (mVtFile != nullptr) delete mVtFile;
|
|
||||||
if (mVtFileEnv != nullptr) delete mVtFileEnv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecEnvironment::ProcLoad(OptionsDescription& od, VariablesMap& vm) {
|
|
||||||
if (mVtFile != nullptr || mVtFileEnv != nullptr) {
|
|
||||||
printf(UNVIRT_TERMCOL_LIGHT_RED(("Please close current opened Vrtools file first.\n")));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* filename = vm.GetData<char>("file");
|
|
||||||
if (filename == nullptr) {
|
|
||||||
printf(UNVIRT_TERMCOL_LIGHT_RED(("You should specify a file first.\n")));
|
|
||||||
od.PrintHelp(stdout);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mVtFileEnv = new LibCmo::Utils::VirtoolsContext();
|
|
||||||
const char* enc = vm.GetData<char>("encoding");
|
|
||||||
mVtFileEnv->NameEncoding = enc == nullptr ? "" : enc;
|
|
||||||
|
|
||||||
mVtFile = new LibCmo::CKFile(*mVtFileEnv);
|
|
||||||
mVtFile->Load(filename, LibCmo::CK_LOAD_FLAGS::CK_LOAD_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecEnvironment::ProcInfo(OptionsDescription& od, VariablesMap& vm) {
|
|
||||||
printf(UNVIRT_TERMCOL_LIGHT_RED(("Sorry. This feature is not supported now.\n")));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecEnvironment::ProcClear(OptionsDescription& od, VariablesMap& vm) {
|
|
||||||
if (mVtFile == nullptr && mVtFileEnv == nullptr) {
|
|
||||||
printf(UNVIRT_TERMCOL_LIGHT_RED(("Virtools file already is empty.\n")));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mVtFile != nullptr) delete mVtFile;
|
|
||||||
if (mVtFileEnv != nullptr) delete mVtFileEnv;
|
|
||||||
|
|
||||||
mVtFile = nullptr;
|
|
||||||
mVtFileEnv = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecEnvironment::ProcExportSql(OptionsDescription& od, VariablesMap& vm) {
|
|
||||||
printf(UNVIRT_TERMCOL_LIGHT_RED(("Sorry. This feature is not supported now.\n")));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma endregion
|
|
||||||
|
|
||||||
#pragma region InteractiveCmd
|
|
||||||
|
|
||||||
InteractiveCmd::InteractiveCmd() :
|
|
||||||
mCmdDispatcher(), mExecEnv(), mVm(), mBlank(), mExitRunFlag(false), mCmdSplitter() {
|
|
||||||
// add load subcommand
|
|
||||||
CmdRegisteryEntry entryLoad;
|
|
||||||
const std::string entryLoadName = "load";
|
|
||||||
entryLoad.mSubCmdDesc = "Load Virtools file.";
|
|
||||||
entryLoad.mOptDesc.AddOption("file", 'f', CmdArgType::STRING, "The loaded Virtools file.");
|
|
||||||
entryLoad.mOptDesc.AddPositionalOption("file");
|
|
||||||
entryLoad.mOptDesc.AddOption("encoding", 'e', CmdArgType::STRING, "The encoding to decode Virtools string.");
|
|
||||||
entryLoad.mOptDesc.AddPositionalOption("encoding");
|
|
||||||
entryLoad.mOptDesc.AddOption("temp", 't', CmdArgType::STRING, "The temp folder used by engine.");
|
|
||||||
entryLoad.mOptDesc.AddPositionalOption("temp");
|
|
||||||
entryLoad.mBindProc = std::bind(&ExecEnvironment::ProcLoad, &this->mExecEnv, std::placeholders::_1, std::placeholders::_2);
|
|
||||||
//mCmdDispatcher.emplace("load", std::move(entryLoad));
|
|
||||||
|
|
||||||
CmdRegisteryEntry entryInfo;
|
|
||||||
entryInfo.mSubCmdDesc = "Show loaded Virtools file header info.";
|
|
||||||
entryInfo.mBindProc = std::bind(&ExecEnvironment::ProcInfo, &this->mExecEnv, std::placeholders::_1, std::placeholders::_2);
|
|
||||||
//mCmdDispatcher.emplace("info", std::move(entryInfo));
|
|
||||||
|
|
||||||
CmdRegisteryEntry entryClear;
|
|
||||||
entryClear.mSubCmdDesc = "Clear current loaded Virtools file.";
|
|
||||||
entryClear.mBindProc = std::bind(&ExecEnvironment::ProcClear, &this->mExecEnv, std::placeholders::_1, std::placeholders::_2);
|
|
||||||
//mCmdDispatcher.emplace("clear", std::move(entryClear));
|
|
||||||
|
|
||||||
CmdRegisteryEntry entryExportSql;
|
|
||||||
entryExportSql.mSubCmdDesc = "Export loaded Virtools file as a SQList database file.";
|
|
||||||
entryExportSql.mOptDesc.AddOption("file", 'f', CmdArgType::STRING, "The exported SQL file.");
|
|
||||||
entryExportSql.mOptDesc.AddPositionalOption("file");
|
|
||||||
entryExportSql.mBindProc = std::bind(&ExecEnvironment::ProcExportSql, &this->mExecEnv, std::placeholders::_1, std::placeholders::_2);
|
|
||||||
//mCmdDispatcher.emplace("sql", std::move(entryExportSql));
|
|
||||||
|
|
||||||
CmdRegisteryEntry entryExit;
|
|
||||||
entryExit.mSubCmdDesc = "Exit this interactive commander.";
|
|
||||||
entryExit.mBindProc = std::bind(&InteractiveCmd::ProcExit, this, std::placeholders::_1, std::placeholders::_2);
|
|
||||||
//mCmdDispatcher.emplace("exit", std::move(entryExit));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
InteractiveCmd::~InteractiveCmd() {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InteractiveCmd::Run(void) {
|
|
||||||
std::string u8cmd;
|
|
||||||
|
|
||||||
mExitRunFlag = false;
|
|
||||||
while (!mExitRunFlag) {
|
|
||||||
// get command
|
|
||||||
GetCmdLine(u8cmd);
|
|
||||||
|
|
||||||
// split cmd and parse it
|
|
||||||
CmdParser(mCmdSplitter.Convert(u8cmd));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InteractiveCmd::GetCmdLine(std::string& u8cmd) {
|
|
||||||
#if defined(LIBCMO_OS_WIN32)
|
|
||||||
std::wstring wcmd;
|
|
||||||
std::getline(std::wcin, wcmd);
|
|
||||||
LibCmo::Encoding::WcharToChar(wcmd, u8cmd, CP_UTF8);
|
|
||||||
#else
|
|
||||||
std::getline(std::cin, u8cmd);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void InteractiveCmd::CmdParser(const std::vector<std::string>& args) {
|
|
||||||
FILE* f = stdout;
|
|
||||||
|
|
||||||
if (args.size() == 0) {
|
|
||||||
fputs(UNVIRT_TERMCOL_LIGHT_RED(("Error! Fail to get subcommand token.\n")), f);
|
|
||||||
PrintHelp(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto arg = args.begin();
|
|
||||||
auto subcmd = mCmdDispatcher.find(*arg);
|
|
||||||
if (subcmd == mCmdDispatcher.end()) {
|
|
||||||
fprintf(f, UNVIRT_TERMCOL_LIGHT_RED(("Error! No such subcommand \"%s\"! \n")), arg->c_str());
|
|
||||||
PrintHelp(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// analyze options
|
|
||||||
++arg;
|
|
||||||
auto& optsDesc = subcmd->second.mOptDesc;
|
|
||||||
mVm.Clear();
|
|
||||||
int position_counter = 0;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (arg == args.end()) break;
|
std::string pending;
|
||||||
|
if (!ArgParser::ParseString(cmd, pos, pending)) {
|
||||||
const std::string& opt = *arg;
|
break; // no more encoding, break
|
||||||
OptionDescription* optDesc;
|
|
||||||
if (opt.starts_with("--")) {
|
|
||||||
// long name
|
|
||||||
optDesc = optsDesc.GetDescByLongName(opt.substr(2));
|
|
||||||
} else if (opt.starts_with("-")) {
|
|
||||||
// short name
|
|
||||||
if (opt.size() != 2u) {
|
|
||||||
// invalid short name
|
|
||||||
fprintf(f, UNVIRT_TERMCOL_LIGHT_RED(("Error! Invalid short name option \"%s\"! \n")), opt.c_str());
|
|
||||||
optsDesc.PrintHelp(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
optDesc = optsDesc.GetDescByShortName(opt[1]);
|
|
||||||
} else {
|
|
||||||
// position
|
|
||||||
optDesc = optsDesc.GetDescByPosition(position_counter++);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalid option
|
// add and move to next
|
||||||
if (optDesc == nullptr) {
|
++pos;
|
||||||
fprintf(f, UNVIRT_TERMCOL_LIGHT_RED(("Error! Invalid option \"%s\"! \n")), opt.c_str());
|
encoding_list.push_back(std::move(pending));
|
||||||
optsDesc.PrintHelp(f);
|
}
|
||||||
|
|
||||||
|
// apply list
|
||||||
|
this->m_Ctx->SetEncoding(encoding_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InteractiveCmd::ProcTemp(const std::deque<std::string>& cmd) {
|
||||||
|
// check requirement
|
||||||
|
size_t pos = 0u;
|
||||||
|
std::string temppath;
|
||||||
|
if (!ArgParser::ParseString(cmd, pos, temppath)) {
|
||||||
|
this->PrintArgParseError(cmd, pos);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get value
|
// assign
|
||||||
bool add_success = true;
|
m_Ctx->SetTempPath(temppath.c_str());
|
||||||
switch (optDesc->mType) {
|
|
||||||
case CmdArgType::NONE:
|
|
||||||
// just a switch
|
|
||||||
add_success = mVm.AddPair(optDesc->mLongName, optDesc->mType, this->mBlank);
|
|
||||||
++arg;
|
|
||||||
if (!add_success) {
|
|
||||||
fprintf(f, UNVIRT_TERMCOL_LIGHT_RED(("Error! Duplicated option \"%s\"! \n")), opt.c_str());
|
|
||||||
optsDesc.PrintHelp(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CmdArgType::INT:
|
|
||||||
case CmdArgType::STRING:
|
|
||||||
// check next value
|
|
||||||
++arg;
|
|
||||||
if (arg == args.end()) {
|
|
||||||
fprintf(f, UNVIRT_TERMCOL_LIGHT_RED(("Error! Option \"%s\" lost parameter! \n")), opt.c_str());
|
|
||||||
optsDesc.PrintHelp(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
add_success = mVm.AddPair(optDesc->mLongName, optDesc->mType, *arg);
|
|
||||||
++arg;
|
|
||||||
if (!add_success) {
|
|
||||||
fprintf(f, UNVIRT_TERMCOL_LIGHT_RED(("Error! Duplicated option \"%s\"! \n")), opt.c_str());
|
|
||||||
optsDesc.PrintHelp(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument("Invalid Option Type.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute proc
|
|
||||||
subcmd->second.mBindProc(optsDesc, mVm);
|
|
||||||
}
|
|
||||||
|
|
||||||
void InteractiveCmd::PrintHelp(FILE* f) {
|
|
||||||
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Subcommands: \n")), f);
|
|
||||||
for (const auto& [key, value] : mCmdDispatcher) {
|
|
||||||
fprintf(f, "%s\t- %s\n", key.c_str(), value.mSubCmdDesc.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InteractiveCmd::ProcExit(OptionsDescription&, VariablesMap&) {
|
|
||||||
mExitRunFlag = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,6 @@ namespace Unvirt::CmdHelper {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GetCmdLine(std::string& u8cmd);
|
void GetCmdLine(std::string& u8cmd);
|
||||||
bool HasOpenedFile(void);
|
|
||||||
void PrintHelp(void);
|
void PrintHelp(void);
|
||||||
void PrintArgParseError(const std::deque<std::string>& cmd, size_t pos);
|
void PrintArgParseError(const std::deque<std::string>& cmd, size_t pos);
|
||||||
void PrintCommonError(const char* u8_fmt, ...);
|
void PrintCommonError(const char* u8_fmt, ...);
|
||||||
|
@ -153,6 +152,12 @@ namespace Unvirt::CmdHelper {
|
||||||
void ProcInfo(const std::deque<std::string>& cmd);
|
void ProcInfo(const std::deque<std::string>& cmd);
|
||||||
void ProcLs(const std::deque<std::string>& cmd);
|
void ProcLs(const std::deque<std::string>& cmd);
|
||||||
void ProcItems(const std::deque<std::string>& cmd);
|
void ProcItems(const std::deque<std::string>& cmd);
|
||||||
|
void ProcEncoding(const std::deque<std::string>& cmd);
|
||||||
|
void ProcTemp(const std::deque<std::string>& cmd);
|
||||||
|
|
||||||
|
bool HasOpenedFile(void);
|
||||||
|
void ClearDocument(void);
|
||||||
|
void PrintMinContextMsg(const std::string& msg);
|
||||||
|
|
||||||
CmdSplitter m_CmdSplitter;
|
CmdSplitter m_CmdSplitter;
|
||||||
size_t m_PageLen;
|
size_t m_PageLen;
|
||||||
|
@ -161,132 +166,4 @@ namespace Unvirt::CmdHelper {
|
||||||
LibCmo::CK2::CKFileDocument* m_Doc;
|
LibCmo::CK2::CKFileDocument* m_Doc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
enum class CmdArgType {
|
|
||||||
NONE,
|
|
||||||
STRING,
|
|
||||||
INT
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OptionDescription {
|
|
||||||
std::string mLongName;
|
|
||||||
char mShortName;
|
|
||||||
CmdArgType mType;
|
|
||||||
std::string mDescription;
|
|
||||||
};
|
|
||||||
|
|
||||||
class OptionsDescription {
|
|
||||||
public:
|
|
||||||
OptionsDescription();
|
|
||||||
OptionsDescription(const OptionsDescription&) = delete;
|
|
||||||
OptionsDescription& operator=(const OptionsDescription&) = delete;
|
|
||||||
~OptionsDescription();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add an option
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fullname">The long name of this option. Should NOT be blank or NULL.</param>
|
|
||||||
/// <param name="shortname">A single char for the short name of this option. Leave ZERO to omit this.</param>
|
|
||||||
/// <param name="type">The value type of this option. Set to CmdArgType::NONE to indicate this is a switch (no value).</param>
|
|
||||||
/// <param name="sescription">The description of this option. This can be NULL.</param>
|
|
||||||
void AddOption(const char* fullname, char shortname, CmdArgType type, const char* sescription);
|
|
||||||
void AddPositionalOption(const char* corresponding_longname);
|
|
||||||
|
|
||||||
OptionDescription* GetDescByLongName(const std::string& longname);
|
|
||||||
OptionDescription* GetDescByShortName(char shortname);
|
|
||||||
OptionDescription* GetDescByPosition(size_t pos);
|
|
||||||
|
|
||||||
void PrintHelp(FILE* f);
|
|
||||||
private:
|
|
||||||
std::unordered_map<std::string, OptionDescription> mLongNameDict;
|
|
||||||
std::unordered_map<char, std::string> mShortNameMapping;
|
|
||||||
std::vector<std::string> mPositionalArgMapping;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AnyVariable {
|
|
||||||
size_t mDataBasicSize;
|
|
||||||
void* mData;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VariablesMap {
|
|
||||||
private:
|
|
||||||
std::unordered_map<std::string, AnyVariable> mDataPair;
|
|
||||||
|
|
||||||
public:
|
|
||||||
VariablesMap();
|
|
||||||
VariablesMap(const VariablesMap&) = delete;
|
|
||||||
VariablesMap& operator=(const VariablesMap&) = delete;
|
|
||||||
~VariablesMap();
|
|
||||||
|
|
||||||
void Clear(void);
|
|
||||||
/// <summary>
|
|
||||||
/// Add option key value pair.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name"></param>
|
|
||||||
/// <param name="t"></param>
|
|
||||||
/// <param name="val"></param>
|
|
||||||
/// <returns>return false when this opt is existed.</returns>
|
|
||||||
bool AddPair(const std::string& name, CmdArgType t, const std::string& val);
|
|
||||||
bool Contain(const char* opt) {
|
|
||||||
if (opt == nullptr) throw std::invalid_argument("Invalid Option Name.");
|
|
||||||
return mDataPair.contains(opt);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
T* GetData(const char* opt) {
|
|
||||||
if (opt == nullptr) throw std::invalid_argument("Invalid Option Name.");
|
|
||||||
const auto search = mDataPair.find(opt);
|
|
||||||
if (search == mDataPair.end()) return nullptr;
|
|
||||||
|
|
||||||
if (sizeof(T) > search->second.mDataBasicSize) throw std::invalid_argument("Memory Violation.");
|
|
||||||
return reinterpret_cast<T*>(search->second.mData);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CmdRegisteryEntry {
|
|
||||||
std::string mSubCmdDesc;
|
|
||||||
OptionsDescription mOptDesc;
|
|
||||||
std::function<void(OptionsDescription&, VariablesMap&)> mBindProc;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExecEnvironment {
|
|
||||||
public:
|
|
||||||
ExecEnvironment();
|
|
||||||
ExecEnvironment(const ExecEnvironment&) = delete;
|
|
||||||
ExecEnvironment& operator=(const ExecEnvironment&) = delete;
|
|
||||||
~ExecEnvironment();
|
|
||||||
|
|
||||||
void ProcLoad(OptionsDescription&, VariablesMap&);
|
|
||||||
void ProcInfo(OptionsDescription&, VariablesMap&);
|
|
||||||
void ProcClear(OptionsDescription&, VariablesMap&);
|
|
||||||
void ProcExportSql(OptionsDescription&, VariablesMap&);
|
|
||||||
private:
|
|
||||||
LibCmo::CKFile* mVtFile;
|
|
||||||
LibCmo::Utils::VirtoolsContext* mVtFileEnv;
|
|
||||||
};
|
|
||||||
|
|
||||||
class InteractiveCmd {
|
|
||||||
public:
|
|
||||||
InteractiveCmd();
|
|
||||||
InteractiveCmd(const InteractiveCmd&) = delete;
|
|
||||||
InteractiveCmd& operator=(const InteractiveCmd&) = delete;
|
|
||||||
~InteractiveCmd();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void GetCmdLine(std::string& u8cmd);
|
|
||||||
void CmdParser(const std::vector<std::string>& args);
|
|
||||||
void PrintHelp(FILE* f);
|
|
||||||
|
|
||||||
void ProcExit(OptionsDescription&, VariablesMap&);
|
|
||||||
|
|
||||||
std::unordered_map<std::string, CmdRegisteryEntry> mCmdDispatcher;
|
|
||||||
CmdSplitter mCmdSplitter;
|
|
||||||
ExecEnvironment mExecEnv;
|
|
||||||
VariablesMap mVm;
|
|
||||||
std::string mBlank;
|
|
||||||
bool mExitRunFlag;
|
|
||||||
};
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
|
@ -78,13 +78,14 @@ namespace Unvirt::StructFormatter {
|
||||||
fullpage = fulllen / pageitems;
|
fullpage = fulllen / pageitems;
|
||||||
|
|
||||||
// print header
|
// print header
|
||||||
fputs("Index\tCK ID\tCKObject\tCKStateChunk\tName\n", fout);
|
fputs("CK ID\tType\tCKObject\tCKStateChunk\tName\n", fout);
|
||||||
|
|
||||||
// print body
|
// print body
|
||||||
for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) {
|
for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) {
|
||||||
const auto& obj = ls[counter];
|
const auto& obj = ls[counter];
|
||||||
|
|
||||||
fprintf(stdout, "%zu\t%" PRIu32 "\t", counter, obj.ObjectId);
|
fprintf(fout, "%" PRIu32 "\t", obj.ObjectId);
|
||||||
|
fprintf(fout, "%s\t", Unvirt::AccessibleValue::GetClassIdName(obj.ObjectCid).c_str());
|
||||||
PrintPointer(obj.ObjPtr);
|
PrintPointer(obj.ObjPtr);
|
||||||
fputc('\t', fout);
|
fputc('\t', fout);
|
||||||
PrintPointer(obj.Data);
|
PrintPointer(obj.Data);
|
||||||
|
@ -93,7 +94,7 @@ namespace Unvirt::StructFormatter {
|
||||||
fputc('\n', fout);
|
fputc('\n', fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fout, "Page %zu of %zu\n", page, fullpage);
|
fprintf(fout, "Page %zu of %zu\n", page + 1, fullpage + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintManagerList(const LibCmo::CK2::XArray<LibCmo::CK2::CKFileManagerData>& ls, size_t page, size_t pageitems) {
|
void PrintManagerList(const LibCmo::CK2::XArray<LibCmo::CK2::CKFileManagerData>& ls, size_t page, size_t pageitems) {
|
||||||
|
@ -104,13 +105,12 @@ namespace Unvirt::StructFormatter {
|
||||||
fullpage = fulllen / pageitems;
|
fullpage = fulllen / pageitems;
|
||||||
|
|
||||||
// print header
|
// print header
|
||||||
fputs("Index\tCKGUID\tCKBaseManager\tCKStateChunk\n", fout);
|
fputs("CKGUID\tCKBaseManager\tCKStateChunk\n", fout);
|
||||||
|
|
||||||
// print body
|
// print body
|
||||||
for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) {
|
for (size_t counter = startpos; counter < fulllen && (counter - startpos) < pageitems; ++counter) {
|
||||||
const auto& mgr = ls[counter];
|
const auto& mgr = ls[counter];
|
||||||
|
|
||||||
fprintf(stdout, "%zu\t", counter);
|
|
||||||
PrintCKGUID(mgr.Manager);
|
PrintCKGUID(mgr.Manager);
|
||||||
fputc('\t', fout);
|
fputc('\t', fout);
|
||||||
PrintPointer(mgr.MgrPtr);
|
PrintPointer(mgr.MgrPtr);
|
||||||
|
@ -119,7 +119,7 @@ namespace Unvirt::StructFormatter {
|
||||||
fputc('\n', fout);
|
fputc('\n', fout);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fout, "Page %zu of %zu\n", page, fullpage);
|
fprintf(fout, "Page %zu of %zu\n", page + 1, fullpage + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user