diff --git a/Unvirt/CmdHelper.cpp b/Unvirt/CmdHelper.cpp index 3e6acb8..0ad12e9 100644 --- a/Unvirt/CmdHelper.cpp +++ b/Unvirt/CmdHelper.cpp @@ -1,4 +1,6 @@ #include "CmdHelper.hpp" +#include "TerminalHelper.hpp" +#include namespace Unvirt { namespace CmdHelper { @@ -14,7 +16,7 @@ namespace Unvirt { ; } - std::vector CmdSplitter::Convert(std::string& u8cmd) { + std::vector CmdSplitter::Convert(const std::string& u8cmd) { // set up variables std::vector result; std::string buffer; @@ -69,12 +71,78 @@ namespace Unvirt { #pragma region interactive cmd helper classes - SubCmd::SubCmd() { + + 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)); } - SubCmd::~SubCmd() { + 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)); } + 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()); + } + } + } + + + VariablesMap::VariablesMap() { + } + + VariablesMap::~VariablesMap() { + } + + #pragma endregion diff --git a/Unvirt/CmdHelper.hpp b/Unvirt/CmdHelper.hpp index 3ef3927..e5e7519 100644 --- a/Unvirt/CmdHelper.hpp +++ b/Unvirt/CmdHelper.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace Unvirt { namespace CmdHelper { @@ -15,7 +16,7 @@ namespace Unvirt { CmdSplitter& operator=(const CmdSplitter&) = delete; ~CmdSplitter(); - std::vector Convert(std::string& u8cmd); + std::vector Convert(const std::string& u8cmd); private: char mCmdChar; std::string* mBuffer; @@ -120,13 +121,68 @@ namespace Unvirt { } }; - class SubCmd { + enum class CmdArgType { + NONE, + STRING, + INT + }; + + struct OptionDescription { + std::string mLongName; + char mShortName; + CmdArgType mType; + std::string mDescription; + }; + + class OptionsDescription { public: - SubCmd(); - ~SubCmd(); + OptionsDescription(); + OptionsDescription(const OptionsDescription&) = delete; + OptionsDescription& operator=(const OptionsDescription&) = delete; + ~OptionsDescription(); + /// + /// Add an option + /// + /// The long name of this option. Should NOT be blank or NULL. + /// A single char for the short name of this option. Leave ZERO to omit this. + /// The value type of this option. Set to CmdArgType::NONE to indicate this is a switch (no value). + /// The description of this option. This can be NULL. + void AddOption(const char* fullname, char shortname, CmdArgType type, const char* sescription); + void AddPositionalOption(const char* corresponding_longname); + + void PrintHelp(FILE* f); private: + std::unordered_map mLongNameDict; + std::unordered_map mShortNameMapping; + std::vector mPositionalArgMapping; + }; + struct AnyVariable { + CmdArgType mType; + void* mData; + }; + + class VariablesMap { + private: + std::unordered_map mDataPair; + + public: + VariablesMap(); + ~VariablesMap(); + + void Clear(void); + bool AddPair(std::string& name, CmdArgType t, std::string& val); + bool Contain(const char* probe); + template + T* GetData(const char* opt) { + ; + } + }; + + struct CmdRegisteryEntry { + OptionsDescription mOptDesc; + std::function mBindProc; }; class InteractiveCmd { @@ -137,7 +193,9 @@ namespace Unvirt { void Run(void); private: - //std::unordered_map mCmdDispatcher; + bool AnalyzeCmd(std::vector& args); + void PrintHelp(FILE* f); + std::unordered_map mCmdDispatcher; };