libcmo21/Unvirt/CmdHelper.hpp

279 lines
7.5 KiB
C++
Raw Permalink Normal View History

2023-02-13 10:57:10 +08:00
#pragma once
2023-08-27 12:30:12 +08:00
#include <VTAll.hpp>
2023-02-13 10:57:10 +08:00
#include <string>
#include <vector>
2023-08-27 12:30:12 +08:00
#include <functional>
2023-03-03 11:06:26 +08:00
#include <deque>
2023-08-27 12:30:12 +08:00
#include <unordered_map>
#include <stdexcept>
#include <cinttypes>
#include <initializer_list>
2023-03-03 11:06:26 +08:00
namespace Unvirt::CmdHelper {
class CmdSplitter {
public:
enum class StateType : int {
SPACE,
SINGLE,
DOUBLE,
ESCAPE,
NORMAL
};
2023-08-27 12:30:12 +08:00
public:
CmdSplitter() :
mCmdChar(0), mBuffer(nullptr), mResult(nullptr),
mState(StateType::NORMAL), mPreState(StateType::NORMAL) {}
~CmdSplitter() {}
LIBCMO_DISABLE_COPY_MOVE(CmdSplitter);
std::deque<std::string> Convert(const std::string& u8cmd);
protected:
char mCmdChar;
std::string* mBuffer;
std::deque<std::string>* mResult;
2023-03-03 11:06:26 +08:00
StateType mState, mPreState;
2023-08-27 12:30:12 +08:00
void ProcSpace(void);
void ProcSingle(void);
void ProcDouble(void);
void ProcEscape(void);
void ProcNormal(void);
};
class HelpDocument {
public:
2023-08-27 14:21:44 +08:00
HelpDocument();
~HelpDocument();
2023-08-27 12:30:12 +08:00
LIBCMO_DISABLE_COPY_MOVE(HelpDocument);
2023-08-27 14:21:44 +08:00
void Push(const std::string& arg_name, const std::string& arg_desc);
void Pop();
2023-08-27 12:30:12 +08:00
void Terminate(std::string& command_desc);
void Print();
protected:
struct StackItem {
StackItem() : m_Name(), m_Desc() {}
StackItem(const std::string& name, const std::string& desc) : m_Name(name), m_Desc(desc) {}
LIBCMO_DEFAULT_COPY_MOVE(StackItem);
std::string m_Name;
std::string m_Desc;
};
std::deque<StackItem> m_Stack;
struct ResultItem {
ResultItem() : m_CmdDesc(), m_ArgDesc() {}
ResultItem(const std::string& desc) : m_CmdDesc(desc), m_ArgDesc() {}
LIBCMO_DEFAULT_COPY_MOVE(ResultItem);
std::string m_CmdDesc;
std::vector<StackItem> m_ArgDesc;
};
std::vector<ResultItem> m_Results;
};
2023-08-27 14:21:44 +08:00
enum class NodeType {
Literal, Choice, Argument
2023-08-27 12:30:12 +08:00
};
2023-08-27 14:21:44 +08:00
class ArgumentsMap;
using ExecutionFct = std::function<void(const ArgumentsMap*)>;
2023-08-27 12:30:12 +08:00
class AbstractNode {
public:
2023-08-27 14:21:44 +08:00
AbstractNode();
virtual ~AbstractNode();
2023-08-27 12:30:12 +08:00
LIBCMO_DISABLE_COPY_MOVE(AbstractNode);
AbstractNode* Then(AbstractNode*);
2023-08-27 14:21:44 +08:00
AbstractNode* Executes(ExecutionFct, const char* = nullptr);
AbstractNode* Comment(const char*);
2023-08-27 12:30:12 +08:00
2023-08-27 14:21:44 +08:00
public:
void Help(HelpDocument*);
bool Consume(std::deque<std::string>&, ArgumentsMap*);
virtual NodeType GetNodeType() = 0;
2023-08-27 12:30:12 +08:00
virtual bool IsConflictWith(AbstractNode*) = 0;
2023-08-27 14:21:44 +08:00
protected:
virtual std::string GetHelpSymbol() = 0;
virtual bool BeginAccept(const std::string&, ArgumentsMap*) = 0;
virtual void EndAccept(ArgumentsMap*) = 0;
2023-08-27 12:30:12 +08:00
2023-08-27 14:21:44 +08:00
std::vector<AbstractNode*> m_Literals;
std::vector<AbstractNode*> m_Choices;
std::vector<AbstractNode*> m_Args;
2023-08-27 12:30:12 +08:00
ExecutionFct m_Execution;
2023-08-27 14:21:44 +08:00
std::string m_ExecutionDesc;
2023-08-27 12:30:12 +08:00
std::string m_Comment;
};
class CommandRoot : public AbstractNode {
public:
2023-08-27 14:21:44 +08:00
CommandRoot();
virtual ~CommandRoot();
2023-08-27 12:30:12 +08:00
LIBCMO_DISABLE_COPY_MOVE(CommandRoot);
// Root use special consume and help functions.
bool RootConsume(std::deque<std::string>&);
HelpDocument* RootHelp();
2023-08-27 14:21:44 +08:00
public:
virtual NodeType GetNodeType() override { throw std::logic_error("Root can not be called."); }
2023-08-27 12:30:12 +08:00
virtual bool IsConflictWith(AbstractNode*) override { throw std::logic_error("Root can not be called."); }
2023-08-27 14:21:44 +08:00
protected:
virtual std::string GetHelpSymbol() override { throw std::logic_error("Root can not be called."); }
virtual bool BeginAccept(const std::string&, ArgumentsMap*) override { throw std::logic_error("Root can not be called."); }
virtual void EndAccept(ArgumentsMap*) override { throw std::logic_error("Root can not be called."); }
2023-08-27 12:30:12 +08:00
};
class Literal : public AbstractNode {
friend class Choice;
2023-08-27 14:21:44 +08:00
friend class AbstractArgument;
2023-08-27 12:30:12 +08:00
public:
2023-08-27 14:21:44 +08:00
Literal(const char* words);
virtual ~Literal();
2023-08-27 12:30:12 +08:00
LIBCMO_DISABLE_COPY_MOVE(Literal);
2023-08-27 14:21:44 +08:00
public:
virtual NodeType GetNodeType() override;
virtual bool IsConflictWith(AbstractNode* node) override;
2023-08-27 12:30:12 +08:00
protected:
2023-08-27 14:21:44 +08:00
virtual std::string GetHelpSymbol() override;
virtual bool BeginAccept(const std::string&, ArgumentsMap*) override;
virtual void EndAccept(ArgumentsMap*) override;
2023-08-27 12:30:12 +08:00
std::string m_Literal;
};
class Choice : public AbstractNode {
2023-08-27 14:21:44 +08:00
friend class Literal;
friend class AbstractArgument;
2023-08-27 12:30:12 +08:00
public:
2023-08-27 16:45:07 +08:00
using vType = size_t;
2023-08-27 14:21:44 +08:00
Choice(const char* argname, const std::initializer_list<std::string>& vocabulary);
virtual ~Choice();
LIBCMO_DISABLE_COPY_MOVE(Choice);
2023-08-27 12:30:12 +08:00
2023-08-27 16:45:07 +08:00
vType* GetIndex();
2023-08-27 12:30:12 +08:00
2023-08-27 14:21:44 +08:00
public:
virtual NodeType GetNodeType() override;
virtual bool IsConflictWith(AbstractNode* node) override;
protected:
virtual std::string GetHelpSymbol() override;
virtual bool BeginAccept(const std::string&, ArgumentsMap*) override;
virtual void EndAccept(ArgumentsMap*) override;
2023-08-27 12:30:12 +08:00
std::string m_ChoiceName;
std::vector<std::string> m_Vocabulary;
2023-08-27 14:21:44 +08:00
bool m_Accepted;
size_t m_GottenIndex;
2023-08-27 12:30:12 +08:00
};
class AbstractArgument : public AbstractNode {
2023-08-27 14:21:44 +08:00
friend class Literal;
friend class Choice;
2023-08-27 12:30:12 +08:00
public:
2023-08-27 14:21:44 +08:00
AbstractArgument(const char* argname);
virtual ~AbstractArgument();
2023-08-27 12:30:12 +08:00
LIBCMO_DISABLE_COPY_MOVE(AbstractArgument);
template<class T>
2023-08-27 14:21:44 +08:00
T GetData() {
return reinterpret_cast<T>(m_ParsedData);
}
2023-08-27 12:30:12 +08:00
2023-08-27 14:21:44 +08:00
public:
virtual NodeType GetNodeType() override;
virtual bool IsConflictWith(AbstractNode* node) override;
2023-08-27 12:30:12 +08:00
protected:
2023-08-27 14:21:44 +08:00
virtual std::string GetHelpSymbol() override;
virtual bool BeginAccept(const std::string&, ArgumentsMap*) override;
virtual void EndAccept(ArgumentsMap*) override;
2023-08-27 12:30:12 +08:00
virtual bool BeginParse(const std::string&) = 0;
virtual void EndParse() = 0;
std::string m_ArgName;
bool m_Accepted;
void* m_ParsedData;
};
/**
* @brief Return true mean this value can accept.
*/
using IntLimit = std::function<bool(int32_t)>;
class IntArgument : public AbstractArgument {
public:
2023-08-27 14:21:44 +08:00
using vType = int32_t;
IntArgument(const char* argname, IntLimit limit = nullptr) :
AbstractArgument(argname), m_IntLimit(limit) {}
2023-08-27 12:30:12 +08:00
virtual ~IntArgument() {}
LIBCMO_DISABLE_COPY_MOVE(IntArgument);
protected:
virtual bool BeginParse(const std::string&) override;
virtual void EndParse() override;
IntLimit m_IntLimit;
2023-03-03 11:06:26 +08:00
};
2023-02-13 10:57:10 +08:00
2023-08-27 12:30:12 +08:00
class StringArgument : public AbstractArgument {
2023-03-03 11:06:26 +08:00
public:
2023-08-27 14:21:44 +08:00
using vType = std::string;
2023-08-27 22:14:02 +08:00
StringArgument(const char* argname) :
AbstractArgument(argname) {}
2023-08-27 12:30:12 +08:00
virtual ~StringArgument() {}
LIBCMO_DISABLE_COPY_MOVE(StringArgument);
protected:
virtual bool BeginParse(const std::string&) override;
virtual void EndParse() override;
2023-03-03 11:06:26 +08:00
};
2023-02-13 16:52:00 +08:00
2023-08-27 12:30:12 +08:00
class EncodingArgument : public AbstractArgument {
2023-03-03 11:06:26 +08:00
public:
2023-08-27 14:21:44 +08:00
using vType = std::vector<std::string>;
2023-08-27 22:14:02 +08:00
EncodingArgument(const char* argname) :
AbstractArgument(argname) {}
2023-08-27 12:30:12 +08:00
virtual ~EncodingArgument() {}
LIBCMO_DISABLE_COPY_MOVE(EncodingArgument);
protected:
virtual bool BeginParse(const std::string&) override;
virtual void EndParse() override;
2023-03-03 11:06:26 +08:00
};
2023-02-13 22:13:30 +08:00
2023-08-27 14:21:44 +08:00
class ArgumentsMap {
public:
ArgumentsMap() : m_Data() {}
~ArgumentsMap() {}
LIBCMO_DISABLE_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:
2023-08-27 16:45:07 +08:00
return reinterpret_cast<_Ty*>(dynamic_cast<AbstractArgument*>(node)->GetData<_Ty*>());
2023-08-27 14:21:44 +08:00
case NodeType::Choice:
2023-08-27 16:45:07 +08:00
return reinterpret_cast<_Ty*>(dynamic_cast<Choice*>(node)->GetIndex());
2023-08-27 14:21:44 +08:00
case NodeType::Literal:
default:
throw std::runtime_error("No such argument type.");
}
}
protected:
std::unordered_map<std::string, AbstractNode*> m_Data;
};
2023-08-27 12:30:12 +08:00
}