fix: fix build issue in Unvirt

This commit is contained in:
yyc12345 2024-08-24 21:27:23 +08:00
parent d74b4645f0
commit 88ce33c358
6 changed files with 344 additions and 379 deletions

View File

@ -6,7 +6,6 @@ PRIVATE
AccessibleValue.cpp AccessibleValue.cpp
CmdHelper.cpp CmdHelper.cpp
StructFormatter.cpp StructFormatter.cpp
TerminalHelper.cpp
UnvirtContext.cpp UnvirtContext.cpp
Unvirt.cpp Unvirt.cpp
) )
@ -18,7 +17,6 @@ FILES
AccessibleValue.hpp AccessibleValue.hpp
CmdHelper.hpp CmdHelper.hpp
StructFormatter.hpp StructFormatter.hpp
TerminalHelper.hpp
UnvirtContext.hpp UnvirtContext.hpp
) )
# Setup header infomation # Setup header infomation

View File

@ -4,24 +4,30 @@ namespace Unvirt::CmdHelper {
#pragma region CmdSplitter #pragma region CmdSplitter
std::deque<std::string> CmdSplitter::Convert(const std::string& u8cmd) { const std::deque<std::u8string>& CmdSplitter::GetResult() const {
// set up variables if (!m_ValidResult)
std::deque<std::string> result; throw std::runtime_error("try to get result from an invalid CmdSplitter.");
std::string buffer; return m_Result;
mBuffer = &buffer; }
mResult = &result;
mState = mPreState = StateType::SPACE; bool CmdSplitter::Convert(const std::u8string& u8cmd) {
// Clear variables
m_ValidResult = false;
m_Result.clear();
m_Buffer.clear();
m_CurrentChar = u8'\0';
m_State = m_PrevState = StateType::SPACE;
// split // split
for (auto& c : u8cmd) { for (char8_t c : u8cmd) {
mCmdChar = c; m_CurrentChar = c;
// skip all invalid characters, \0 and etc. // skip all invalid characters (ascii code unit lower than space char)
// mCmdChar >= 0 to ensure all non-ASCII UTF8 char can be accepted directly. // thus UTF8 code unit can directly accepted.
if (mCmdChar >= 0 && (!std::isprint(mCmdChar))) if (m_CurrentChar < u8' ')
continue; continue;
switch (mState) { switch (m_State) {
case StateType::SPACE: case StateType::SPACE:
ProcSpace(); ProcSpace();
break; break;
@ -41,157 +47,183 @@ namespace Unvirt::CmdHelper {
} }
// final proc // final proc
switch (mState) { bool is_success = false;
switch (m_State) {
case StateType::SPACE: case StateType::SPACE:
is_success = true;
break; break;
case StateType::NORMAL: case StateType::NORMAL:
// push the last one // push the last one
mResult->push_back(*mBuffer); m_Result.emplace_back(m_Buffer);
is_success = true;
break; break;
case StateType::SINGLE: case StateType::SINGLE:
case StateType::DOUBLE: case StateType::DOUBLE:
case StateType::ESCAPE: case StateType::ESCAPE:
// error // error
result.clear(); is_success = false;
break; break;
default:
throw std::runtime_error("unreachable code.");
} }
// return value // check success
return result; if (is_success) {
m_ValidResult = true;
return true;
} else {
m_Result.clear();
return false;
}
} }
void CmdSplitter::ProcSpace(void) { void CmdSplitter::ProcSpace() {
switch (mCmdChar) { switch (m_CurrentChar) {
case '\'': case u8'\'':
mState = StateType::SINGLE; m_State = StateType::SINGLE;
break; break;
case '"': case u8'"':
mState = StateType::DOUBLE; m_State = StateType::DOUBLE;
break; break;
case '\\': case u8'\\':
mState = StateType::ESCAPE; m_State = StateType::ESCAPE;
mPreState = StateType::NORMAL; m_PrevState = StateType::NORMAL;
break; break;
case ' ': case u8' ':
break; // skip blank break; // skip blank
default: default:
mBuffer->push_back(mCmdChar); m_Buffer.push_back(m_CurrentChar);
mState = StateType::NORMAL; m_State = StateType::NORMAL;
break; break;
} }
} }
void CmdSplitter::ProcSingle(void) { void CmdSplitter::ProcSingle() {
switch (mCmdChar) { switch (m_CurrentChar) {
case '\'': case u8'\'':
mState = StateType::NORMAL; m_State = StateType::NORMAL;
break; break;
case '"': case u8'"':
mBuffer->push_back('"'); m_Buffer.push_back('"');
break; break;
case '\\': case u8'\\':
mState = StateType::ESCAPE; m_State = StateType::ESCAPE;
mPreState = StateType::SINGLE; m_PrevState = StateType::SINGLE;
break; break;
case ' ': case u8' ':
mBuffer->push_back(' '); m_Buffer.push_back(u8' ');
break; break;
default: default:
mBuffer->push_back(mCmdChar); m_Buffer.push_back(m_CurrentChar);
break; break;
} }
} }
void CmdSplitter::ProcDouble(void) { void CmdSplitter::ProcDouble() {
switch (mCmdChar) { switch (m_CurrentChar) {
case '\'': case u8'\'':
mBuffer->push_back('\''); m_Buffer.push_back(u8'\'');
break; break;
case '"': case u8'"':
mState = StateType::NORMAL; m_State = StateType::NORMAL;
break; break;
case '\\': case u8'\\':
mState = StateType::ESCAPE; m_State = StateType::ESCAPE;
mPreState = StateType::DOUBLE; m_PrevState = StateType::DOUBLE;
break; break;
case ' ': case u8' ':
mBuffer->push_back(' '); m_Buffer.push_back(u8' ');
break; break;
default: default:
mBuffer->push_back(mCmdChar); m_Buffer.push_back(m_CurrentChar);
break; break;
} }
} }
void CmdSplitter::ProcEscape(void) { void CmdSplitter::ProcEscape() {
// add itself // add itself
mBuffer->push_back(mCmdChar); m_Buffer.push_back(m_CurrentChar);
// restore state // restore state
mState = mPreState; m_State = m_PrevState;
} }
void CmdSplitter::ProcNormal(void) { void CmdSplitter::ProcNormal() {
switch (mCmdChar) { switch (m_CurrentChar) {
case '\'': case u8'\'':
mBuffer->push_back('\''); m_Buffer.push_back(u8'\'');
break; break;
case '"': case u8'"':
mBuffer->push_back('"'); m_Buffer.push_back(u8'"');
break; break;
case '\\': case u8'\\':
mState = StateType::ESCAPE; m_State = StateType::ESCAPE;
mPreState = StateType::NORMAL; m_PrevState = StateType::NORMAL;
break; break;
case ' ': case u8' ':
mResult->push_back(*mBuffer); m_Result.emplace_back(m_Buffer);
mBuffer->clear(); m_Buffer.clear();
mState = StateType::SPACE; m_State = StateType::SPACE;
break; break;
default: default:
mBuffer->push_back(mCmdChar); m_Buffer.push_back(m_CurrentChar);
break; break;
} }
} }
#pragma endregion #pragma endregion
#pragma region Arguments Map
#pragma endregion
#pragma region Help Document #pragma region Help Document
HelpDocument::HelpDocument() : m_Stack(), m_Results() {} HelpDocument::HelpDocument() : m_Stack(), m_Results() {}
HelpDocument::~HelpDocument() {} HelpDocument::~HelpDocument() {}
void HelpDocument::Push(const std::string& arg_name, const std::string& arg_desc) { HelpDocument::StackItem::StackItem() : m_Name(), m_Desc() {}
HelpDocument::StackItem::StackItem(const std::u8string& name, const std::u8string& desc) : m_Name(name), m_Desc(desc) {}
HelpDocument::ResultItem::ResultItem() : m_CmdDesc(), m_ArgDesc() {}
HelpDocument::ResultItem::ResultItem(const std::u8string& cmd_desc, const std::deque<StackItem>& arg_desc) :
m_CmdDesc(cmd_desc), m_ArgDesc(arg_desc.begin(), arg_desc.end()) {}
void HelpDocument::Push(const std::u8string& arg_name, const std::u8string& arg_desc) {
m_Stack.emplace_back(StackItem { arg_name, arg_desc }); m_Stack.emplace_back(StackItem { arg_name, arg_desc });
} }
void HelpDocument::Pop() { void HelpDocument::Pop() {
if (m_Stack.empty())
throw std::runtime_error("try pop back on an empty help document.");
m_Stack.pop_back(); m_Stack.pop_back();
} }
void HelpDocument::Terminate(std::string& command_desc) { void HelpDocument::Terminate(std::u8string& command_desc) {
// create new result and copy stack // create new result
ResultItem result(command_desc); ResultItem result(command_desc, this->m_Stack);
result.m_ArgDesc.insert(result.m_ArgDesc.end(), m_Stack.begin(), m_Stack.end());
// add into result // add into result
m_Results.emplace_back(std::move(result)); m_Results.emplace_back(std::move(result));
} }
void HelpDocument::Print() { void HelpDocument::Print() {
for (auto& item : m_Results) { for (auto& cmd : m_Results) {
fputs("Syntax: ", stdout); // syntax
for (auto& cmd : item.m_ArgDesc) { YYCC::ConsoleHelper::WriteLine(u8"Syntax: ");
fputs(cmd.m_Name.c_str(), stdout); for (const auto& arg : cmd.m_ArgDesc) {
fputc(' ', stdout); YYCC::ConsoleHelper::Format(u8"%s ", arg.m_Name.c_str());
} }
fputc('\n', stdout); YYCC::ConsoleHelper::WriteLine(u8"");
// command description
if (!item.m_CmdDesc.empty()) { if (!cmd.m_CmdDesc.empty()) {
fprintf(stdout, "Description: %s\n", item.m_CmdDesc.c_str()); YYCC::ConsoleHelper::FormatLine(u8"Description: %s", cmd.m_CmdDesc.c_str());
} }
// argument description
for (auto& cmd : item.m_ArgDesc) { YYCC::ConsoleHelper::WriteLine(u8"Arguments:");
if (!cmd.m_Desc.empty()) { for (auto& arg : cmd.m_ArgDesc) {
fprintf(stdout, "\t%s: %s\n", cmd.m_Name.c_str(), cmd.m_Desc.c_str()); if (!arg.m_Desc.empty()) {
YYCC::ConsoleHelper::FormatLine(u8"\t%s: %s", arg.m_Name.c_str(), arg.m_Desc.c_str());
} }
} }
// space between each commands
fputc('\n', stdout); YYCC::ConsoleHelper::WriteLine(u8"");
} }
} }
@ -406,8 +438,8 @@ namespace Unvirt::CmdHelper {
#pragma region Literal #pragma region Literal
Literal::Literal(const char* words) : Literal::Literal(const char* words) :
AbstractNode(), AbstractNode(),
m_Literal(words == nullptr ? "" : words) { m_Literal(words == nullptr ? "" : words) {
if (words == nullptr || m_Literal.empty()) if (words == nullptr || m_Literal.empty())
throw std::invalid_argument("Invalid literal."); throw std::invalid_argument("Invalid literal.");
@ -536,7 +568,7 @@ namespace Unvirt::CmdHelper {
AbstractArgument::AbstractArgument(const char* argname) : AbstractArgument::AbstractArgument(const char* argname) :
AbstractNode(), AbstractNode(),
m_ArgName(argname == nullptr ? "" : argname), m_ArgName(argname == nullptr ? "" : argname),
m_Accepted(false), m_ParsedData(nullptr) { m_Accepted(false), m_ParsedData(nullptr) {
if (argname == nullptr || m_ArgName.empty()) if (argname == nullptr || m_ArgName.empty())
throw std::invalid_argument("Invalid argument name."); throw std::invalid_argument("Invalid argument name.");
@ -652,16 +684,4 @@ namespace Unvirt::CmdHelper {
#pragma endregion #pragma endregion
#pragma region Argument Map
void ArgumentsMap::Add(const std::string& k, AbstractNode* v) {
m_Data.emplace(std::make_pair(k, v));
}
void ArgumentsMap::Remove(const std::string& k) {
m_Data.erase(k);
}
#pragma endregion
} }

View File

@ -5,15 +5,19 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <deque> #include <deque>
#include <unordered_map> #include <map>
#include <stdexcept> #include <stdexcept>
#include <cinttypes> #include <cinttypes>
#include <initializer_list> #include <initializer_list>
#include <type_traits>
#include <memory>
namespace Unvirt::CmdHelper { namespace Unvirt::CmdHelper {
class CmdSplitter { class CmdSplitter {
public: public:
using Result_t = std::deque<std::u8string>;
private:
enum class StateType : int { enum class StateType : int {
SPACE, SPACE,
SINGLE, SINGLE,
@ -21,86 +25,194 @@ namespace Unvirt::CmdHelper {
ESCAPE, ESCAPE,
NORMAL NORMAL
}; };
public: public:
CmdSplitter() : CmdSplitter() :
mCmdChar(0), mBuffer(nullptr), mResult(nullptr), m_CurrentChar(u8'\0'), m_Buffer(), m_Result(), m_ValidResult(false),
mState(StateType::NORMAL), mPreState(StateType::NORMAL) {} m_State(StateType::NORMAL), m_PrevState(StateType::NORMAL) {}
~CmdSplitter() {} ~CmdSplitter() {}
YYCC_DEL_CLS_COPY_MOVE(CmdSplitter); YYCC_DEL_CLS_COPY_MOVE(CmdSplitter);
std::deque<std::string> Convert(const std::string& u8cmd); bool Convert(const std::u8string& u8cmd);
protected: const Result_t& GetResult() const;
char mCmdChar;
std::string* mBuffer;
std::deque<std::string>* mResult;
StateType mState, mPreState; private:
void ProcSpace();
void ProcSingle();
void ProcDouble();
void ProcEscape();
void ProcNormal();
void ProcSpace(void); char8_t m_CurrentChar;
void ProcSingle(void); std::u8string m_Buffer;
void ProcDouble(void); Result_t m_Result;
void ProcEscape(void); bool m_ValidResult;
void ProcNormal(void); StateType m_State, m_PrevState;
}; };
#pragma region ArgumentsMap
namespace ArgumentsMapItem {
class AbstractItem {
public:
AbstractItem() {}
virtual ~AbstractItem() {}
YYCC_DEF_CLS_COPY_MOVE(AbstractItem);
};
template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty>, int> = 0>
class ArithmeticItem : public AbstractItem {
public:
ArithmeticItem(_Ty value) : AbstractItem(), m_Data(value) {}
virtual ~ArithmeticItem() {}
YYCC_DEF_CLS_COPY_MOVE(ArithmeticItem);
public:
_Ty Get() const { return m_Data; }
protected:
_Ty m_Data;
};
template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty>, int> = 0>
class ArithmeticArrayItem : public AbstractItem {
public:
ArithmeticArrayItem(const std::vector<_Ty>& values) : AbstractItem(), m_Data(values) {}
virtual ~ArithmeticArrayItem() {}
YYCC_DEF_CLS_COPY_MOVE(ArithmeticArrayItem);
public:
const std::vector<_Ty>& Get() const { return m_Data; }
protected:
std::vector<_Ty> m_Data;
};
class StringItem : public AbstractItem {
public:
StringItem(const std::u8string_view& value) : AbstractItem(), m_Data(value) {}
virtual ~StringItem() {}
YYCC_DEF_CLS_COPY_MOVE(StringItem);
public:
const std::u8string& Get() const { return m_Data; }
protected:
std::u8string m_Data;
};
class StringArrayItem : public AbstractItem {
public:
StringArrayItem(const std::vector<std::u8string>& value) : AbstractItem(), m_Data(value) {}
virtual ~StringArrayItem() {}
YYCC_DEF_CLS_COPY_MOVE(StringArrayItem);
public:
const std::vector<std::u8string>& Get() const { return m_Data; }
protected:
std::vector<std::u8string> m_Data;
};
}
class ArgumentsMap {
public:
ArgumentsMap() : m_Data() {}
~ArgumentsMap() {}
YYCC_DEF_CLS_COPY_MOVE(ArgumentsMap);
protected:
std::map<std::u8string, std::unique_ptr<ArgumentsMapItem::AbstractItem>> m_Data;
public:
template<class _Ty, class... _Types, std::enable_if_t<std::is_base_of_v<ArgumentsMapItem::AbstractItem, _Ty>, int> = 0>
void Add(const std::u8string_view& key, _Types&&... args) {
// check argument
if (key.empty())
throw std::invalid_argument("argument key should not be empty");
// insert into data
auto result = m_Data.try_emplace(std::u8string(key), std::make_unique<_Ty>(std::forward<_Types>(args)...));
if (!result.second)
throw std::runtime_error("try to add an existing key.");
}
template<class _Ty, std::enable_if_t<std::is_base_of_v<ArgumentsMapItem::AbstractItem, _Ty>, int> = 0>
const _Ty& Get() const {
// check argument
if (key.empty())
throw std::invalid_argument("argument key should not be empty");
// find key first
auto finder = m_Data.find(std::u8string(key));
if (finder == m_Data.end())
throw std::runtime_error("try to get a non-existent key.");
// get stored value data
const ArgumentsMapItem::AbstractItem& value = *finder->second.get();
return static_cast<const _Ty&>(value);
}
void Remove(const std::u8string_view& key) {
// check argument
if (key.empty())
throw std::invalid_argument("argument key should not be empty");
// remove and return remove result.
if (m_Data.erase(std::u8string(key)) == 0u)
throw std::runtime_error("try to delete a non-existent key.");
}
};
#pragma endregion
class HelpDocument { class HelpDocument {
public: public:
HelpDocument(); HelpDocument();
~HelpDocument(); ~HelpDocument();
YYCC_DEL_CLS_COPY_MOVE(HelpDocument); YYCC_DEF_CLS_COPY_MOVE(HelpDocument);
void Push(const std::string& arg_name, const std::string& arg_desc); public:
void Push(const std::u8string& arg_name, const std::u8string& arg_desc);
void Pop(); void Pop();
void Terminate(std::string& command_desc); void Terminate(std::u8string& command_desc);
void Print(); void Print();
protected: protected:
struct StackItem { struct StackItem {
StackItem() : m_Name(), m_Desc() {} StackItem();
StackItem(const std::string& name, const std::string& desc) : m_Name(name), m_Desc(desc) {} StackItem(const std::u8string& name, const std::u8string& desc);
YYCC_DEF_CLS_COPY_MOVE(StackItem); YYCC_DEF_CLS_COPY_MOVE(StackItem);
std::string m_Name;
std::string m_Desc; std::u8string m_Name;
std::u8string m_Desc;
}; };
std::deque<StackItem> m_Stack; std::deque<StackItem> m_Stack;
struct ResultItem { struct ResultItem {
ResultItem() : m_CmdDesc(), m_ArgDesc() {} ResultItem();
ResultItem(const std::string& desc) : m_CmdDesc(desc), m_ArgDesc() {} ResultItem(const std::u8string& cmd_desc, const std::deque<StackItem>& arg_desc);
YYCC_DEF_CLS_COPY_MOVE(ResultItem); YYCC_DEF_CLS_COPY_MOVE(ResultItem);
std::string m_CmdDesc;
std::u8string m_CmdDesc;
std::vector<StackItem> m_ArgDesc; std::vector<StackItem> m_ArgDesc;
}; };
std::vector<ResultItem> m_Results; std::vector<ResultItem> m_Results;
}; };
enum class NodeType {
Literal, Choice, Argument
};
class ArgumentsMap;
using ExecutionFct = std::function<void(const ArgumentsMap*)>;
class AbstractNode { class AbstractNode {
friend class CommandRoot;
public:
using ExecutionFct = void(*)(const ArgumentsMap&);
public: public:
AbstractNode(); AbstractNode();
virtual ~AbstractNode(); virtual ~AbstractNode();
YYCC_DEL_CLS_COPY_MOVE(AbstractNode); YYCC_DEF_CLS_COPY_MOVE(AbstractNode);
AbstractNode* Then(AbstractNode*); AbstractNode* Then(AbstractNode*);
AbstractNode* Executes(ExecutionFct, const char* = nullptr); AbstractNode* Executes(ExecutionFct, const char* = nullptr);
AbstractNode* Comment(const char*); AbstractNode* Comment(const char*);
public:
void Help(HelpDocument*);
bool Consume(std::deque<std::string>&, ArgumentsMap*);
virtual NodeType GetNodeType() = 0;
virtual bool IsConflictWith(AbstractNode*) = 0;
protected: protected:
virtual std::string GetHelpSymbol() = 0; void Help(HelpDocument& doc);
virtual bool BeginAccept(const std::string&, ArgumentsMap*) = 0; bool Consume(CmdSplitter::Result_t& cmds, ArgumentsMap& am);
virtual void EndAccept(ArgumentsMap*) = 0; virtual bool IsConflictWith(AbstractNode* node) = 0;
virtual bool IsArgument() = 0;
virtual std::u8string HelpSymbol() = 0;
virtual bool BeginConsume(const std::u8string& cur_cmd, ArgumentsMap& am) = 0;
virtual void EndConsume(ArgumentsMap*) = 0;
std::vector<AbstractNode*> m_Literals; protected:
std::vector<AbstractNode*> m_Choices; std::vector<std::unique_ptr<AbstractNode>> m_Nodes;
std::vector<AbstractNode*> m_Args;
ExecutionFct m_Execution; ExecutionFct m_Execution;
std::string m_ExecutionDesc; std::string m_ExecutionDesc;
std::string m_Comment; std::string m_Comment;
@ -178,8 +290,8 @@ namespace Unvirt::CmdHelper {
YYCC_DEL_CLS_COPY_MOVE(AbstractArgument); YYCC_DEL_CLS_COPY_MOVE(AbstractArgument);
template<class T> template<class T>
T GetData() { T GetData() {
return reinterpret_cast<T>(m_ParsedData); return reinterpret_cast<T>(m_ParsedData);
} }
public: public:
@ -220,7 +332,7 @@ namespace Unvirt::CmdHelper {
class StringArgument : public AbstractArgument { class StringArgument : public AbstractArgument {
public: public:
using vType = std::string; using vType = std::string;
StringArgument(const char* argname) : StringArgument(const char* argname) :
AbstractArgument(argname) {} AbstractArgument(argname) {}
virtual ~StringArgument() {} virtual ~StringArgument() {}
YYCC_DEL_CLS_COPY_MOVE(StringArgument); YYCC_DEL_CLS_COPY_MOVE(StringArgument);
@ -233,7 +345,7 @@ namespace Unvirt::CmdHelper {
class EncodingArgument : public AbstractArgument { class EncodingArgument : public AbstractArgument {
public: public:
using vType = std::vector<std::string>; using vType = std::vector<std::string>;
EncodingArgument(const char* argname) : EncodingArgument(const char* argname) :
AbstractArgument(argname) {} AbstractArgument(argname) {}
virtual ~EncodingArgument() {} virtual ~EncodingArgument() {}
YYCC_DEL_CLS_COPY_MOVE(EncodingArgument); YYCC_DEL_CLS_COPY_MOVE(EncodingArgument);
@ -243,36 +355,4 @@ namespace Unvirt::CmdHelper {
virtual void EndParse() override; virtual void EndParse() override;
}; };
class ArgumentsMap {
public:
ArgumentsMap() : m_Data() {}
~ArgumentsMap() {}
YYCC_DEL_CLS_COPY_MOVE(ArgumentsMap);
void Add(const std::string& k, AbstractNode* v);
void Remove(const std::string& k);
template<class _Ty>
_Ty* Get(const char* k) const {
if (k == nullptr) throw std::invalid_argument("Null argument name.");
std::string conv(k);
auto finder = m_Data.find(conv);
if (finder == m_Data.end()) throw std::invalid_argument("No such argument name.");
AbstractNode* node = finder->second;
switch (node->GetNodeType()) {
case NodeType::Argument:
return reinterpret_cast<_Ty*>(dynamic_cast<AbstractArgument*>(node)->GetData<_Ty*>());
case NodeType::Choice:
return reinterpret_cast<_Ty*>(dynamic_cast<Choice*>(node)->GetIndex());
case NodeType::Literal:
default:
throw std::runtime_error("No such argument type.");
}
}
protected:
std::unordered_map<std::string, AbstractNode*> m_Data;
};
} }

View File

@ -132,7 +132,7 @@ namespace Unvirt::StructFormatter {
beobj->GetID(), beobj->GetID(),
AccessibleValue::GetClassIdName(beobj->GetClassID()).c_str(), AccessibleValue::GetClassIdName(beobj->GetClassID()).c_str(),
PrintPointer(beobj).c_str(), PrintPointer(beobj).c_str(),
PrintCKSTRING(beobj->GetName()).c_str() (beobj != nullptr ? PrintCKSTRING(beobj->GetName()).c_str() : u8"")
); );
} }
} }
@ -166,16 +166,10 @@ namespace Unvirt::StructFormatter {
// print current mesh // print current mesh
{ {
auto curmesh = obj->GetCurrentMesh(); auto curmesh = obj->GetCurrentMesh();
Console::Format(u8"->\t%s", Console::Format(u8"->\t%s\t%s",
PrintPointer(curmesh).c_str() PrintPointer(curmesh).c_str(),
(curmesh != nullptr ? PrintCKSTRING(curmesh->GetName()).c_str() : u8"")
); );
if (curmesh != nullptr) {
Console::FormatLine(u8"\t%s",
PrintCKSTRING(curmesh->GetName()).c_str()
);
} else {
Console::WriteLine(u8"");
}
} }
// print other meshes // print other meshes
for (LibCmo::CKDWORD i = 0; i < obj->GetPotentialMeshCount(); ++i) { for (LibCmo::CKDWORD i = 0; i < obj->GetPotentialMeshCount(); ++i) {
@ -183,7 +177,7 @@ namespace Unvirt::StructFormatter {
Console::FormatLine(u8"#%" PRIuCKDWORD "\t%s\t%s", Console::FormatLine(u8"#%" PRIuCKDWORD "\t%s\t%s",
i, i,
PrintPointer(thismesh).c_str(), PrintPointer(thismesh).c_str(),
PrintCKSTRING(thismesh->GetName()).c_str() (thismesh != nullptr ? PrintCKSTRING(thismesh->GetName()).c_str() : u8"")
); );
} }
@ -239,26 +233,16 @@ namespace Unvirt::StructFormatter {
// color // color
Console::WriteLine(u8"== Color =="); Console::WriteLine(u8"== Color ==");
Console::Write(u8"Diffuse: "); Console::FormatLine(u8"Diffuse: %s", PrintColor(obj->GetDiffuse()).c_str());
PrintColor(obj->GetDiffuse()); Console::FormatLine(u8"Ambient: %s", PrintColor(obj->GetAmbient()).c_str());
Console::Write(u8"\n"); Console::FormatLine(u8"Specular: %s", PrintColor(obj->GetSpecular()).c_str());
Console::Write(u8"Ambient: "); Console::FormatLine(u8"Emissive: %s", PrintColor(obj->GetEmissive()).c_str());
PrintColor(obj->GetAmbient());
Console::Write(u8"\n");
Console::Write(u8"Specular: ");
PrintColor(obj->GetSpecular());
Console::Write(u8"\n");
Console::Write(u8"Emissive: ");
PrintColor(obj->GetEmissive());
Console::Write(u8"\n");
Console::FormatLine(u8"Specular Power: %.2" PRIfCKFLOAT, obj->GetSpecularPower()); Console::FormatLine(u8"Specular Power: %.2" PRIfCKFLOAT, obj->GetSpecularPower());
// basic data // basic data
Console::WriteLine(u8"== Basic =="); Console::WriteLine(u8"== Basic ==");
Console::Write(u8"Both Sided: "); Console::FormatLine(u8"Both Sided: %s", PrintBool(obj->GetTwoSidedEnabled()).c_str());
PrintBool(obj->GetTwoSidedEnabled());
Console::Write(u8"\n");
Console::FormatLine(u8"Fill Mode: %s", AccessibleValue::GetEnumName(obj->GetFillMode(), AccessibleValue::EnumDesc::VXFILL_MODE).c_str()); Console::FormatLine(u8"Fill Mode: %s", AccessibleValue::GetEnumName(obj->GetFillMode(), AccessibleValue::EnumDesc::VXFILL_MODE).c_str());
Console::FormatLine(u8"Shade Mode: %s", AccessibleValue::GetEnumName(obj->GetShadeMode(), AccessibleValue::EnumDesc::VXSHADE_MODE).c_str()); Console::FormatLine(u8"Shade Mode: %s", AccessibleValue::GetEnumName(obj->GetShadeMode(), AccessibleValue::EnumDesc::VXSHADE_MODE).c_str());
@ -268,48 +252,33 @@ namespace Unvirt::StructFormatter {
Console::WriteLine(u8"Index\tAddress\tName"); Console::WriteLine(u8"Index\tAddress\tName");
for (LibCmo::CKDWORD i = 0; i < 4; ++i) { for (LibCmo::CKDWORD i = 0; i < 4; ++i) {
auto tex = obj->GetTexture(i); auto tex = obj->GetTexture(i);
if (tex != nullptr) { Console::FormatLine(u8"#%" PRIuCKDWORD "\t%s\t%s",
Console::FormatLine(u8"#%" PRIuCKDWORD "\t%s\t%s", i,
i, PrintPointer(tex).c_str(),
PrintPointer(tex), (tex != nullptr ? PrintCKSTRING(tex->GetName()).c_str() : u8"")
PrintCKSTRING(tex->GetName()).c_str() );
);
} else {
Console::FormatLine(u8"#%" PRIuCKDWORD "\t%s",
i,
PrintPointer(tex)
);
}
} }
Console::FormatLine(u8"Texture Blend: %s", AccessibleValue::GetEnumName(obj->GetTextureBlendMode(), AccessibleValue::EnumDesc::VXTEXTURE_BLENDMODE).c_str()); Console::FormatLine(u8"Texture Blend: %s", AccessibleValue::GetEnumName(obj->GetTextureBlendMode(), AccessibleValue::EnumDesc::VXTEXTURE_BLENDMODE).c_str());
Console::FormatLine(u8"Filter Min: %s", AccessibleValue::GetEnumName(obj->GetTextureMinMode(), AccessibleValue::EnumDesc::VXTEXTURE_FILTERMODE).c_str()); Console::FormatLine(u8"Filter Min: %s", AccessibleValue::GetEnumName(obj->GetTextureMinMode(), AccessibleValue::EnumDesc::VXTEXTURE_FILTERMODE).c_str());
Console::FormatLine(u8"Filter Mag: %s", AccessibleValue::GetEnumName(obj->GetTextureMagMode(), AccessibleValue::EnumDesc::VXTEXTURE_FILTERMODE).c_str()); Console::FormatLine(u8"Filter Mag: %s", AccessibleValue::GetEnumName(obj->GetTextureMagMode(), AccessibleValue::EnumDesc::VXTEXTURE_FILTERMODE).c_str());
Console::FormatLine(u8"Address Mode: %s", AccessibleValue::GetEnumName(obj->GetTextureAddressMode(), AccessibleValue::EnumDesc::VXTEXTURE_ADDRESSMODE).c_str()); Console::FormatLine(u8"Address Mode: %s", AccessibleValue::GetEnumName(obj->GetTextureAddressMode(), AccessibleValue::EnumDesc::VXTEXTURE_ADDRESSMODE).c_str());
Console::Write(u8"Perspective Correct: "); Console::FormatLine(u8"Perspective Correct: %s", PrintBool(obj->GetPerspectiveCorrectionEnabled()).c_str());
PrintBool(obj->GetPerspectiveCorrectionEnabled());
Console::Write(u8"\n");
// alpha test // alpha test
Console::WriteLine(u8"== Alpha Test =="); Console::WriteLine(u8"== Alpha Test ==");
Console::Write(u8"Enabled: "); Console::FormatLine(u8"Enabled: %s", PrintBool(obj->GetAlphaTestEnabled()).c_str());
PrintBool(obj->GetAlphaTestEnabled());
Console::Write(u8"\n");
Console::FormatLine(u8"Alpha Function: %s", AccessibleValue::GetEnumName(obj->GetAlphaFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str()); Console::FormatLine(u8"Alpha Function: %s", AccessibleValue::GetEnumName(obj->GetAlphaFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str());
Console::FormatLine(u8"Alpha Ref Value: %" PRIuCKBYTE, obj->GetAlphaRef()); Console::FormatLine(u8"Alpha Ref Value: %" PRIuCKBYTE, obj->GetAlphaRef());
// alpha blend // alpha blend
Console::WriteLine(u8"== Alpha Blend =="); Console::WriteLine(u8"== Alpha Blend ==");
Console::Write(u8"Enabled: "); Console::FormatLine(u8"Enabled: %s", PrintBool(obj->GetAlphaBlendEnabled()).c_str());
PrintBool(obj->GetAlphaBlendEnabled());
Console::Write(u8"\n");
Console::FormatLine(u8"Source Blend: %s", AccessibleValue::GetEnumName(obj->GetSourceBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str()); Console::FormatLine(u8"Source Blend: %s", AccessibleValue::GetEnumName(obj->GetSourceBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str());
Console::FormatLine(u8"Destination Blend: %s", AccessibleValue::GetEnumName(obj->GetDestBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str()); Console::FormatLine(u8"Destination Blend: %s", AccessibleValue::GetEnumName(obj->GetDestBlend(), AccessibleValue::EnumDesc::VXBLEND_MODE).c_str());
// z buffer // z buffer
Console::WriteLine(u8"== Z-Buffer Write =="); Console::WriteLine(u8"== Z-Buffer Write ==");
Console::Write(u8"Enabled: "); Console::FormatLine(u8"Enabled: %s", PrintBool(obj->GetZWriteEnabled()).c_str());
PrintBool(obj->GetZWriteEnabled());
Console::Write(u8"\n");
Console::FormatLine(u8"Z Compare Function: %s", AccessibleValue::GetEnumName(obj->GetZFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str()); Console::FormatLine(u8"Z Compare Function: %s", AccessibleValue::GetEnumName(obj->GetZFunc(), AccessibleValue::EnumDesc::VXCMPFUNC).c_str());
// effect // effect
@ -324,7 +293,7 @@ namespace Unvirt::StructFormatter {
Console::WriteLine(u8"== Flags =="); Console::WriteLine(u8"== Flags ==");
Console::WriteLine(u8"Mesh Flags:"); Console::WriteLine(u8"Mesh Flags:");
Console::WriteLine(AccessibleValue::GetFlagEnumName(obj->GetMeshFlags(), AccessibleValue::EnumDesc::VXMESH_FLAGS, u8"\n").c_str()); Console::WriteLine(AccessibleValue::GetFlagEnumName(obj->GetMeshFlags(), AccessibleValue::EnumDesc::VXMESH_FLAGS, u8"\n", u8"\t").c_str());
Console::FormatLine(u8"Lit Mode: %s", AccessibleValue::GetEnumName(obj->GetLitMode(), AccessibleValue::EnumDesc::VXMESH_LITMODE).c_str()); Console::FormatLine(u8"Lit Mode: %s", AccessibleValue::GetEnumName(obj->GetLitMode(), AccessibleValue::EnumDesc::VXMESH_LITMODE).c_str());
Console::FormatLine(u8"Wrap Mode: %s", AccessibleValue::GetEnumName(obj->GetWrapMode(), AccessibleValue::EnumDesc::VXTEXTURE_WRAPMODE).c_str()); Console::FormatLine(u8"Wrap Mode: %s", AccessibleValue::GetEnumName(obj->GetWrapMode(), AccessibleValue::EnumDesc::VXTEXTURE_WRAPMODE).c_str());
@ -333,26 +302,40 @@ namespace Unvirt::StructFormatter {
Console::FormatLine(u8"Vertex Count: %" PRIuCKDWORD, obj->GetVertexCount()); Console::FormatLine(u8"Vertex Count: %" PRIuCKDWORD, obj->GetVertexCount());
Console::WriteLine(u8"Address\tSize\tType"); Console::WriteLine(u8"Address\tSize\tType");
PrintPointer(obj->GetVertexPositions()); Console::FormatLine(u8"%s\t0x%" PRIxCKDWORD " bytes\tPositions",
Console::FormatLine(u8"\t0x%" PRIxCKDWORD " bytes\tPositions", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3)); PrintPointer(obj->GetVertexPositions()).c_str(),
PrintPointer(obj->GetVertexNormals()); obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3)
Console::FormatLine(u8"\t0x%" PRIxCKDWORD " bytes\tNormals", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3)); );
PrintPointer(obj->GetVertexUVs()); Console::FormatLine(u8"%s\t0x%" PRIxCKDWORD " bytes\tNormals",
Console::FormatLine(u8"\t0x%" PRIxCKDWORD " bytes\tUVs", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector2)); PrintPointer(obj->GetVertexNormals()).c_str(),
PrintPointer(obj->GetVertexColors()); obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3)
Console::FormatLine(u8"\t0x%" PRIxCKDWORD " bytes\tColors", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)); );
PrintPointer(obj->GetVertexSpecularColors()); Console::FormatLine(u8"%s\t0x%" PRIxCKDWORD " bytes\tUVs",
Console::FormatLine(u8"\t0x%" PRIxCKDWORD " bytes\tSpecularColors", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)); PrintPointer(obj->GetVertexUVs()).c_str(),
obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector2)
);
Console::FormatLine(u8"%s\t0x%" PRIxCKDWORD " bytes\tColors",
PrintPointer(obj->GetVertexColors()).c_str(),
obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)
);
Console::FormatLine(u8"%s\t0x%" PRIxCKDWORD " bytes\tSpecularColors",
PrintPointer(obj->GetVertexSpecularColors()).c_str(),
obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)
);
// face data // face data
Console::WriteLine(u8"== Face =="); Console::WriteLine(u8"== Face ==");
Console::FormatLine(u8"Face Count: %" PRIuCKDWORD, obj->GetFaceCount()); Console::FormatLine(u8"Face Count: %" PRIuCKDWORD, obj->GetFaceCount());
Console::WriteLine(u8"Address\tSize\tType"); Console::WriteLine(u8"Address\tSize\tType");
PrintPointer(obj->GetFaceIndices()); Console::FormatLine(u8"%s\t0x%" PRIxCKDWORD " bytes\tIndices",
Console::FormatLine(u8"\t0x%" PRIxCKDWORD " bytes\tIndices", obj->GetFaceCount() * 3 * CKSizeof(LibCmo::CKWORD)); PrintPointer(obj->GetFaceIndices()).c_str(),
PrintPointer(obj->GetFaceMaterialSlotIndexs()); obj->GetFaceCount() * 3 * CKSizeof(LibCmo::CKWORD)
Console::FormatLine(u8"\t0x%" PRIxCKDWORD " bytes\tMaterialSlotIndexs", obj->GetFaceCount() * CKSizeof(LibCmo::CKWORD)); );
Console::FormatLine(u8"%s\t0x%" PRIxCKDWORD " bytes\tMaterialSlotIndexs",
PrintPointer(obj->GetFaceMaterialSlotIndexs()).c_str(),
obj->GetFaceCount() * CKSizeof(LibCmo::CKWORD)
);
// mtl slot data // mtl slot data
Console::WriteLine(u8"== Material Slot =="); Console::WriteLine(u8"== Material Slot ==");
@ -363,12 +346,11 @@ namespace Unvirt::StructFormatter {
for (LibCmo::CKDWORD i = 0; i < slotcount; ++i) { for (LibCmo::CKDWORD i = 0; i < slotcount; ++i) {
LibCmo::CK2::ObjImpls::CKMaterial* mtl = pMtlSlots[i]; LibCmo::CK2::ObjImpls::CKMaterial* mtl = pMtlSlots[i];
Console::Format(u8"#%" PRIuCKDWORD "\t", i); Console::FormatLine(u8"#%" PRIuCKDWORD "\t%s\t%s",
PrintPointer(mtl); i,
Console::Write(u8"\t"); PrintPointer(mtl).c_str(),
if (mtl != nullptr) (mtl != nullptr ? PrintCKSTRING(mtl->GetName()).c_str() : u8"")
PrintCKSTRING(mtl->GetName()); );
Console::Write(u8"\n");
} }
} }
@ -437,27 +419,27 @@ namespace Unvirt::StructFormatter {
} }
static void PrintObjectListEntry(const LibCmo::CK2::CKFileObject& obj, const LibCmo::CK2::CKFileInfo& fileinfo, size_t entry_index, bool full_detail) { static void PrintObjectListEntry(const LibCmo::CK2::CKFileObject& obj, const LibCmo::CK2::CKFileInfo& fileinfo, size_t entry_index, bool full_detail) {
if (full_detail) { if (full_detail) {
Console::FormatLine(u8"0x%08" PRIxCKDWORD, obj.SaveFlags); Console::Format(u8"0x%08" PRIxCKDWORD "\t", obj.SaveFlags);
Console::FormatLine(u8"\t%s", AccessibleValue::GetEnumName(obj.Options, AccessibleValue::EnumDesc::CK_FO_OPTIONS).c_str()); Console::Format(u8"%s\t", AccessibleValue::GetEnumName(obj.Options, AccessibleValue::EnumDesc::CK_FO_OPTIONS).c_str());
Console::FormatLine(u8"\t%" PRIuCKID "\t%" PRIuCKID, Console::Format(u8"%" PRIuCKID "\t%" PRIuCKID "\t",
obj.CreatedObjectId, obj.CreatedObjectId,
obj.ObjectId obj.ObjectId
); );
Console::FormatLine(u8"\t0x%08" PRIxCKDWORD " (Rel: 0x%08" PRIxCKDWORD ")", Console::Format(u8"0x%08" PRIxCKDWORD " (Rel: 0x%08" PRIxCKDWORD ")\t",
obj.FileIndex, obj.FileIndex,
obj.FileIndex - CKSizeof(LibCmo::CK2::CKRawFileInfo) - fileinfo.Hdr1UnPackSize obj.FileIndex - CKSizeof(LibCmo::CK2::CKRawFileInfo) - fileinfo.Hdr1UnPackSize
); );
Console::FormatLine(u8"\t0x%08" PRIxCKDWORD, obj.PackSize); Console::Format(u8"0x%08" PRIxCKDWORD "\t", obj.PackSize);
} }
// following items are shared by full details and simple layout // following items are shared by full details and simple layout
Console::FormatLine(u8"\t#%" PRIuSIZET "\t%s\t%s\t%s\t%s", Console::FormatLine(u8"#%" PRIuSIZET "\t%s\t%s\t%s\t%s",
entry_index, entry_index,
AccessibleValue::GetClassIdName(obj.ObjectCid).c_str(), AccessibleValue::GetClassIdName(obj.ObjectCid).c_str(),
PrintColorfulBool(obj.ObjPtr != nullptr).c_str(), PrintColorfulBool(obj.ObjPtr != nullptr).c_str(),
PrintColorfulBool(obj.Data != nullptr).c_str(), PrintColorfulBool(obj.Data != nullptr).c_str(),
PrintCKSTRING(LibCmo::XContainer::NSXString::ToCKSTRING(obj.Name)) PrintCKSTRING(LibCmo::XContainer::NSXString::ToCKSTRING(obj.Name)).c_str()
); );
} }
void PrintObjectList( void PrintObjectList(
@ -648,7 +630,7 @@ namespace Unvirt::StructFormatter {
Console::WriteLine(YYCC_COLOR_LIGHT_YELLOW(u8"Identifiers")); Console::WriteLine(YYCC_COLOR_LIGHT_YELLOW(u8"Identifiers"));
Console::WriteLine(u8"Identifier\tData Pointer\tData Size"); Console::WriteLine(u8"Identifier\tData Pointer\tData Size");
for (const auto& ident : collection) { for (const auto& ident : collection) {
Console::FormatLine(u8"0x%08" PRIxCKDWORD "\t%s\t%" PRIuCKDWORD " (%" PRIuCKDWORD " DWORD + %" PRIuCKDWORD ")\n", Console::FormatLine(u8"0x%08" PRIxCKDWORD "\t%s\t%" PRIuCKDWORD " (%" PRIuCKDWORD " DWORD + %" PRIuCKDWORD ")",
ident.m_Identifier, ident.m_Identifier,
PrintPointer(ident.m_DataPtr).c_str(), PrintPointer(ident.m_DataPtr).c_str(),
ident.m_AreaSize, ident.m_AreaSize,

View File

@ -1,61 +0,0 @@
#include "TerminalHelper.hpp"
#include <VTUtils.hpp>
#include <VTEncoding.hpp>
#include <cstdarg>
#include <iostream>
#include <cstdio>
#if YYCC_OS == YYCC_OS_WINDOWS
#include <Windows.h>
#include <cstdio>
#include <io.h>
#include <fcntl.h>
#endif
namespace Unvirt {
namespace TerminalHelper {
// all of these functions only works on Windows platform
// due to shitty Windows implementations.
bool EnsureTerminalColor(void) {
#if YYCC_OS == YYCC_OS_WINDOWS
if (_isatty(_fileno(stdout))) {
HANDLE h_output;
DWORD dw_mode;
h_output = (HANDLE)_get_osfhandle(_fileno(stdout));
if (!GetConsoleMode(h_output, &dw_mode)) return false;
if (!SetConsoleMode(h_output, dw_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) return false;
return true;
} else return false;
#else
return true;
#endif
}
bool EnsureTerminalEncoding(void) {
#if YYCC_OS == YYCC_OS_WINDOWS
if (!SetConsoleCP(CP_UTF8)) return false;
if (!SetConsoleOutputCP(CP_UTF8)) return false;
/*_setmode(_fileno(stdout), _O_U8TEXT);*/
_setmode(_fileno(stdin), _O_U16TEXT);
#endif
return true;
}
void GetCmdLine(std::string& u8cmd) {
fputs(UNVIRT_TERMCOL_LIGHT_GREEN(("Unvirt> ")), stdout);
#if YYCC_OS == YYCC_OS_WINDOWS
std::wstring wcmd;
std::getline(std::wcin, wcmd);
LibCmo::EncodingHelper::WcharToChar(wcmd, u8cmd, CP_UTF8);
#else
std::getline(std::cin, u8cmd);
#endif
}
}
}

View File

@ -1,54 +0,0 @@
#pragma once
#include <string>
namespace Unvirt::TerminalHelper {
#define UNVIRT_REMOVE_PARENS_IMPL(...) __VA_ARGS__
#define UNVIRT_REMOVE_PARENS(T) UNVIRT_REMOVE_PARENS_IMPL T
#define UNVIRT_TERMCOLHDR_BLACK "\033[30m"
#define UNVIRT_TERMCOLHDR_RED "\033[31m"
#define UNVIRT_TERMCOLHDR_GREEN "\033[32m"
#define UNVIRT_TERMCOLHDR_YELLOW "\033[33m"
#define UNVIRT_TERMCOLHDR_BLUE "\033[34m"
#define UNVIRT_TERMCOLHDR_MAGENTA "\033[35m"
#define UNVIRT_TERMCOLHDR_CYAN "\033[36m"
#define UNVIRT_TERMCOLHDR_WHITE "\033[37m"
#define UNVIRT_TERMCOLHDR_LIGHT_BLACK "\033[90m"
#define UNVIRT_TERMCOLHDR_LIGHT_RED "\033[91m"
#define UNVIRT_TERMCOLHDR_LIGHT_GREEN "\033[92m"
#define UNVIRT_TERMCOLHDR_LIGHT_YELLOW "\033[93m"
#define UNVIRT_TERMCOLHDR_LIGHT_BLUE "\033[94m"
#define UNVIRT_TERMCOLHDR_LIGHT_MAGENTA "\033[95m"
#define UNVIRT_TERMCOLHDR_LIGHT_CYAN "\033[96m"
#define UNVIRT_TERMCOLHDR_LIGHT_WHITE "\033[97m"
#define UNVIRT_TERMCOLTAIL "\033[0m"
#define UNVIRT_TERMCOL_BLACK(T) "\033[30m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_RED(T) "\033[31m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_GREEN(T) "\033[32m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_YELLOW(T) "\033[33m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_BLUE(T) "\033[34m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_MAGENTA(T) "\033[35m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_CYAN(T) "\033[36m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_WHITE(T) "\033[37m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_BLACK(T) "\033[90m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_RED(T) "\033[91m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_GREEN(T) "\033[92m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_YELLOW(T) "\033[93m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_BLUE(T) "\033[94m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_MAGENTA(T) "\033[95m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_CYAN(T) "\033[96m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
#define UNVIRT_TERMCOL_LIGHT_WHITE(T) "\033[97m" UNVIRT_REMOVE_PARENS(T) "\033[0m"
bool EnsureTerminalColor(void);
bool EnsureTerminalEncoding(void);
void GetCmdLine(std::string&);
}