update shit

This commit is contained in:
yyc12345 2023-02-13 22:13:30 +08:00
parent a519b2d8d5
commit 6fc223b208
2 changed files with 260 additions and 15 deletions

View File

@ -1,11 +1,10 @@
#include "CmdHelper.hpp"
#include "TerminalHelper.hpp"
#include <stdexcept>
namespace Unvirt {
namespace CmdHelper {
#pragma region cmd splitter
#pragma region CmdSplitter
CmdSplitter::CmdSplitter() :
mCmdChar(0), mBuffer(nullptr), mResult(nullptr),
@ -69,8 +68,7 @@ namespace Unvirt {
#pragma endregion
#pragma region interactive cmd helper classes
#pragma region OptionsDescription
OptionsDescription::OptionsDescription() :
mLongNameDict(), mShortNameMapping(), mPositionalArgMapping() {
@ -121,6 +119,21 @@ namespace Unvirt {
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) {
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("Allowed Options: \n")), f);
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 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,8 +278,93 @@ namespace Unvirt {
}
#pragma endregion
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
}

View File

@ -5,6 +5,7 @@
#include <functional>
#include <vector>
#include <unordered_map>
#include <stdexcept>
namespace Unvirt {
namespace CmdHelper {
@ -151,6 +152,10 @@ namespace Unvirt {
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(int pos);
void PrintHelp(FILE* f);
private:
std::unordered_map<std::string, OptionDescription> mLongNameDict;
@ -159,7 +164,7 @@ namespace Unvirt {
};
struct AnyVariable {
CmdArgType mType;
size_t mDataBasicSize;
void* mData;
};
@ -169,35 +174,72 @@ namespace Unvirt {
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(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>
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:
};
class InteractiveCmd {
public:
InteractiveCmd();
InteractiveCmd(const InteractiveCmd&) = delete;
InteractiveCmd& operator=(const InteractiveCmd&) = delete;
~InteractiveCmd();
void Run(void);
private:
bool AnalyzeCmd(std::vector<std::string>& args);
void CmdParser(const std::vector<std::string>& args);
void PrintHelp(FILE* f);
std::unordered_map<std::string, CmdRegisteryEntry> mCmdDispatcher;
ExecEnvironment mExecEnv;
VariablesMap mVm;
std::string mBlank;
};
}