update shit
This commit is contained in:
parent
a519b2d8d5
commit
6fc223b208
|
@ -1,11 +1,10 @@
|
||||||
#include "CmdHelper.hpp"
|
#include "CmdHelper.hpp"
|
||||||
#include "TerminalHelper.hpp"
|
#include "TerminalHelper.hpp"
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace Unvirt {
|
namespace Unvirt {
|
||||||
namespace CmdHelper {
|
namespace CmdHelper {
|
||||||
|
|
||||||
#pragma region cmd splitter
|
#pragma region CmdSplitter
|
||||||
|
|
||||||
CmdSplitter::CmdSplitter() :
|
CmdSplitter::CmdSplitter() :
|
||||||
mCmdChar(0), mBuffer(nullptr), mResult(nullptr),
|
mCmdChar(0), mBuffer(nullptr), mResult(nullptr),
|
||||||
|
@ -69,8 +68,7 @@ namespace Unvirt {
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region interactive cmd helper classes
|
#pragma region OptionsDescription
|
||||||
|
|
||||||
|
|
||||||
OptionsDescription::OptionsDescription() :
|
OptionsDescription::OptionsDescription() :
|
||||||
mLongNameDict(), mShortNameMapping(), mPositionalArgMapping() {
|
mLongNameDict(), mShortNameMapping(), mPositionalArgMapping() {
|
||||||
|
@ -121,6 +119,21 @@ namespace Unvirt {
|
||||||
mPositionalArgMapping.push_back(std::move(fullname));
|
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(int pos) {
|
||||||
|
if (pos >= mPositionalArgMapping.size()) return nullptr;
|
||||||
|
return GetDescByLongName(mPositionalArgMapping[pos]);
|
||||||
|
}
|
||||||
|
|
||||||
void OptionsDescription::PrintHelp(FILE* f) {
|
void OptionsDescription::PrintHelp(FILE* f) {
|
||||||
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Options: \n")), f);
|
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Options: \n")), f);
|
||||||
for (const auto& [key, value] : mLongNameDict) {
|
for (const auto& [key, value] : mLongNameDict) {
|
||||||
|
@ -136,19 +149,124 @@ namespace Unvirt {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VariablesMap::VariablesMap() {
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region VariablesMap
|
||||||
|
|
||||||
|
VariablesMap::VariablesMap() : mDataPair() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
VariablesMap::~VariablesMap() {
|
||||||
|
this->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
VariablesMap::~VariablesMap() {
|
void VariablesMap::Clear(void) {
|
||||||
|
for (const auto& [key, value] : mDataPair) {
|
||||||
|
if (value.mData != nullptr) free(value.mData);
|
||||||
|
}
|
||||||
|
mDataPair.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VariablesMap::AddPair(std::string& name, CmdArgType t, 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region ExecEnvironment
|
||||||
|
|
||||||
|
ExecEnvironment::ExecEnvironment() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecEnvironment::~ExecEnvironment() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecEnvironment::ProcLoad(OptionsDescription& od, VariablesMap& vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecEnvironment::ProcInfo(OptionsDescription& od, VariablesMap& vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecEnvironment::ProcClear(OptionsDescription& od, VariablesMap& vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecEnvironment::ProcExportSql(OptionsDescription& od, VariablesMap& vm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|
||||||
#pragma region interactive cmd
|
#pragma region InteractiveCmd
|
||||||
|
|
||||||
InteractiveCmd::InteractiveCmd() {
|
InteractiveCmd::InteractiveCmd() :
|
||||||
|
mCmdDispatcher(), mExecEnv(), mVm(), mBlank()
|
||||||
|
{
|
||||||
|
// add load subcommand
|
||||||
|
CmdRegisteryEntry entryLoad;
|
||||||
|
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));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,9 +278,94 @@ namespace Unvirt {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (arg == args.end()) break;
|
||||||
|
|
||||||
|
const std::string& opt = *arg;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
optsDesc.GetDescByShortName(opt[1]);
|
||||||
|
} else {
|
||||||
|
// position
|
||||||
|
optDesc = optsDesc.GetDescByPosition(position_counter++);
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalid option
|
||||||
|
if (optDesc == nullptr) {
|
||||||
|
fprintf(f, UNVIRT_TERMCOL_LIGHT_RED(("Error! Invalid option \"%s\"! \n")), opt.c_str());
|
||||||
|
optsDesc.PrintHelp(f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get value
|
||||||
|
switch (optDesc->mType) {
|
||||||
|
case CmdArgType::NONE:
|
||||||
|
// just a switch
|
||||||
|
mVm.AddPair(optDesc->mLongName, optDesc->mType, this->mBlank);
|
||||||
|
++arg;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
mVm.AddPair(optDesc->mLongName, optDesc->mType, *arg);
|
||||||
|
++arg;
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace Unvirt {
|
namespace Unvirt {
|
||||||
namespace CmdHelper {
|
namespace CmdHelper {
|
||||||
|
@ -151,6 +152,10 @@ namespace Unvirt {
|
||||||
void AddOption(const char* fullname, char shortname, CmdArgType type, const char* sescription);
|
void AddOption(const char* fullname, char shortname, CmdArgType type, const char* sescription);
|
||||||
void AddPositionalOption(const char* corresponding_longname);
|
void AddPositionalOption(const char* corresponding_longname);
|
||||||
|
|
||||||
|
OptionDescription* GetDescByLongName(const std::string& longname);
|
||||||
|
OptionDescription* GetDescByShortName(char shortname);
|
||||||
|
OptionDescription* GetDescByPosition(int pos);
|
||||||
|
|
||||||
void PrintHelp(FILE* f);
|
void PrintHelp(FILE* f);
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, OptionDescription> mLongNameDict;
|
std::unordered_map<std::string, OptionDescription> mLongNameDict;
|
||||||
|
@ -159,7 +164,7 @@ namespace Unvirt {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AnyVariable {
|
struct AnyVariable {
|
||||||
CmdArgType mType;
|
size_t mDataBasicSize;
|
||||||
void* mData;
|
void* mData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -169,35 +174,72 @@ namespace Unvirt {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VariablesMap();
|
VariablesMap();
|
||||||
|
VariablesMap(const VariablesMap&) = delete;
|
||||||
|
VariablesMap& operator=(const VariablesMap&) = delete;
|
||||||
~VariablesMap();
|
~VariablesMap();
|
||||||
|
|
||||||
void Clear(void);
|
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(std::string& name, CmdArgType t, std::string& val);
|
bool AddPair(std::string& name, CmdArgType t, std::string& val);
|
||||||
bool Contain(const char* probe);
|
bool Contain(const char* opt) {
|
||||||
|
if (opt == nullptr) throw std::invalid_argument("Invalid Option Name.");
|
||||||
|
return mDataPair.contains(opt);
|
||||||
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* GetData(const char* opt) {
|
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 {
|
struct CmdRegisteryEntry {
|
||||||
|
std::string mSubCmdDesc;
|
||||||
OptionsDescription mOptDesc;
|
OptionsDescription mOptDesc;
|
||||||
std::function<void(OptionsDescription&, VariablesMap&)> mBindProc;
|
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:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class InteractiveCmd {
|
class InteractiveCmd {
|
||||||
public:
|
public:
|
||||||
InteractiveCmd();
|
InteractiveCmd();
|
||||||
|
InteractiveCmd(const InteractiveCmd&) = delete;
|
||||||
|
InteractiveCmd& operator=(const InteractiveCmd&) = delete;
|
||||||
~InteractiveCmd();
|
~InteractiveCmd();
|
||||||
|
|
||||||
void Run(void);
|
void Run(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool AnalyzeCmd(std::vector<std::string>& args);
|
void CmdParser(const std::vector<std::string>& args);
|
||||||
void PrintHelp(FILE* f);
|
void PrintHelp(FILE* f);
|
||||||
|
|
||||||
std::unordered_map<std::string, CmdRegisteryEntry> mCmdDispatcher;
|
std::unordered_map<std::string, CmdRegisteryEntry> mCmdDispatcher;
|
||||||
|
ExecEnvironment mExecEnv;
|
||||||
|
VariablesMap mVm;
|
||||||
|
std::string mBlank;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user