C++命令行系统(二)

文章详细描述了一个C++编写的嵌入式开发中的命令行交互系统,包括CommandManager类的定义和实现,以及Command、CommandHelper和CmdIO类的功能,展示了如何注册、执行和管理命令,支持命令分组和显示帮助。
摘要由CSDN通过智能技术生成

1 概述

  在嵌入式开发中,经常会利用命令行交互系统测试功能,本文描述使用C++语言开发的一个命令行交互系统,支持命令注册(C或C++格式),命令分组,执行命令,显示命令提示。

3 实现

3.1 CommandManager定义

typedef std::vector<std::string> Args;
typedef std::function<int(int argc, char *argv[])> handler;
typedef std::function<int(Args const& args)> Handler;

#define PTR(Obj) &(Obj)
#define HANDLER(MemberFun, Ptr) \
    std::bind(&MemberFun, Ptr, std::placeholders::_1)

#define NL  "\n"
#define S    NL" "
#define SS   NL"  "
#define SSS  NL"   "
#define SSSS NL"    "

class CommandHelper;
class CommandManager
{
    CommandHelper* helpr_;
    CommandManager(CommandManager const&);
    void operator==(CommandManager const&);
public:
    CommandManager();
    ~CommandManager();

    size_t commandSize() const;

    bool registerCommand(const char* cmd, Handler handler, const char* help);
    bool registerCommand(const char* cmd, handler handler, const char* help);
    bool registerCommand(const char* cmd, 
                         const char* group, Handler handler, const char* help);
    bool registerCommand(const char* cmd,
                         const char* group, handler handler, const char* help);
    
    bool unregisterCommand(const char* cmd);

    bool showCommand(const char* cmd) const;
    int  showCommands() const;
    int  showCommands(const char* group) const;

    bool execCommand(const char* cmdString) const;
    
    int  retrunValue() const;

    int run(const char* prompt);
};

接口说明:

  • commandSize 注册的命令数
  • registerCommand 注册命令
  • unregisterCommand 注销命令
  • showCommand 显示单条命令信息
  • showCommands 按组显示命令
  • execCommand 执行命令
  • returnValue 获取命令返回值
  • run 运行命令行系统,通过默认命令exit退出

3.2 CommandManager实现

CommandManager::CommandManager()
: helpr_(new CommandHelper())
{
}

CommandManager::~CommandManager() { delete helpr_; }

size_t CommandManager::commandSize() const { return helpr_->size(); }

bool CommandManager::registerCommand(const char* cmd, 
    Handler handler, const char* help)
{
    return helpr_->add(std::make_shared<Command>(handler, cmd, help));
}

bool CommandManager::registerCommand(const char* cmd, 
    handler handler, const char* help)
{
    return helpr_->add(std::make_shared<Command>(handler, cmd, help));
}

bool CommandManager::registerCommand(const char* cmd, const char* group, 
    Handler handler, const char* help)
{
    return helpr_->add(std::make_shared<Command>(handler, cmd, help, group));
}

bool CommandManager::registerCommand(const char* cmd, const char* group, 
    handler handler, const char* help)
{
    return helpr_->add(std::make_shared<Command>(handler, cmd, help, group));
}

bool CommandManager::unregisterCommand(const char* cmd)
{
    return helpr_->remove(cmd ? cmd : std::string());
}

bool CommandManager::showCommand(const char* cmd) const
{
    return helpr_->show(cmd ? cmd : std::string());
}

int CommandManager::showCommands() const
{
    return helpr_->showGroup(std::string());
}

int CommandManager::showCommands(const char* group) const
{
    return helpr_->showGroup(group ? group : std::string());
}

bool CommandManager::execCommand(const char* line) const
{
    return helpr_->parse(line ? line : std::string());
}

int CommandManager::retrunValue() const
{
    return helpr_->returnValue();
}

int CommandManager::run(const char* prompt)
{
    CmdIO io;
    helpr_->addDefault();
    while(!helpr_->signal())
    {
        std::string line = io.readLine(prompt);
        if(line.empty())
            continue;
        
        helpr_->parse(line);
    }
    return 0;
}

函数说明:

  • run 运行命令行系统
    • 调用helpr_的addDefault函数注册默认命令
    • 调用io函数的readLine读取命令行
    • 调用helpr_的parse解析并执行命令
    • 重复上面两步,直到调用exit命令退出
  • 其它函数直接调用CommandHelper对应函数。

3.3 Command

struct Command
{
    Command(Handler _handler = Handler(),
        const char *_cmd = nullptr,
        const char *_help = nullptr,
        const char *_group = nullptr
        )
    : cpp_handler(_handler)
    , cmd(_cmd ? _cmd : std::string())
    , help(_help ? _help : std::string())
    , group(_group ? _group : std::string())
    {}

    Command(handler _handler = handler(),
        const char *_cmd = nullptr,
        const char *_help = nullptr,
        const char *_group = nullptr
        )
    : c_hanlder(_handler)
    , cmd(_cmd ? _cmd : std::string())
    , help(_help ? _help : std::string())
    , group(_group ? _group : std::string())
    {}

    typedef std::shared_ptr<Command> Ptr;

    bool empty() const 
    {
        return cmd.empty() || 
            (cpp_handler == nullptr 
                && c_hanlder == nullptr); 
    }
    
    size_t cmd_len() const { return cmd.size(); }

    Handler cpp_handler;
    handler c_hanlder;
    std::string name;
	std::string help;
	std::string group;
};

成员列表:

  • cpp_handler C++命令处理器
  • c_hanlder C命令处理器
  • name 命令名称
  • help 命令帮助
  • group 命令组

接口列表:

  • empty 命令是否为空

3.4 CommandHelper

class CommandHelper
{
    std::list<Command::Ptr> commands_;
    volatile bool signal_ =  false;
    int retValue_ = 0xFFFFFFFF;
public:
    bool signal() const { return signal_; }
    void doSingal() { signal_ = true; }
    inline int returnValue() const { return retValue_; }

    inline bool add(Command::Ptr const& command)
    {
        if(command->empty() || find(command->cmd))
            return false;
        
        commands_.push_back(command);
        return true;
    }

    bool remove(std::string const& cmd)
    {
        if(!cmd.empty())
        {
            auto c = std::find_if(commands_.begin(), commands_.end(), 
                [&](Command::Ptr const& c) { return cmd == c->cmd; });
            if(c != commands_.end())
            {
                commands_.erase(c);
                return true;
            }
        }
        return false;
    }

    inline size_t size() const { return commands_.size(); }

    inline size_t cmd_maxlen() const
    {
        auto compare = [](Command::Ptr const& l, Command::Ptr const& r) {
             return l->cmd_len() < r->cmd_len(); };
        auto command = std::max_element(commands_.begin(), commands_.end(), compare);
        if(command == commands_.end())
            return 0;
        return (*command)->cmd_len();
    }

    Command::Ptr find(std::string const& cmd) const
    {
        if(!cmd.empty())
        {
            auto command = std::find_if(commands_.begin(), commands_.end(), 
                [&](Command::Ptr const& c) { return cmd == c->cmd; });
            if(command != commands_.end())
                return *command;
        }
        return Command::Ptr();
    }

    void showHelp(std::string const& help, size_t maxlen) const
    {
        auto pos = help.find(NL);
        if(pos == std::string::npos)
            std::cout << help;
        else
        {
            decltype(pos) start = 0;
            do
            {
                std::cout << help.substr(start, pos - start) << std::endl;
                std::cout << std::left << std::setw(maxlen) << "";

                start = pos + 1;
                pos = help.find(NL, start);
                if(pos == std::string::npos)
                {
                    std::cout << help.substr(start, help.size() - start);
                    break;
                }
            } while(true);
        }
        std::cout << std::endl;
    }

    bool show(std::string const& cmd, bool is_print_error = true) const
    {
        auto command = find(cmd);
        if(command)
        {
            std::cout << std::left << std::setw(command->cmd_len()) 
                << command->cmd << " : ";
            showHelp(command->help, command->cmd_len() + 3);
            return true;
        }
        if(is_print_error)
            std::cerr << "cannot find cmd: " << cmd << std::endl;
        return false;
    }

    int showGroup(std::string const& group) const
    {
        int count = 0;
        std::string g;
        size_t maxlen = cmd_maxlen();

        for(auto command = commands_.begin(); 
            command != commands_.end(); ++command)
        {
            if(g.empty())
                g =  (*command)->group;
            else if(g != (*command)->group)
            {
                g =  (*command)->group;
                std::cout << std::endl;
            }

            if(group.empty() || group == (*command)->group)
            {
                std::cout << std::left << std::setw(maxlen) << (*command)->cmd << " : ";
                showHelp((*command)->help, maxlen + 3);
                count++;
            }
        }
        std::cout << std::endl;
        if(group.empty())
            std::cout << "show " << count << " commands" << std::endl << std::endl;
        return count;
    }

    void addDefault()
    {
        add(std::make_shared<Command>([=](Args const& args) {
            std::cout << "ret = " << retValue_ << std::endl;
            return retValue_;
        }, "ret", "get return value of last command", "sys"));

        add(std::make_shared<Command>([=](Args const& args) {
            for(size_t i = 0; i < args.size(); i++) {
                std::cout << args[i];
                if(i != args.size() - 1)
                    std::cout << " ";
                else
                    std::cout << std::endl;   
	        }
            return retValue_;
        }, "print", "print text", "sys"));

        add(std::make_shared<Command>([=](Args const& args) {
            if(args.size() < 2)
                return retValue_;

            int value = std::stol(args[1]);
            if(value == retValue_)
                std::cout << "Test of " << args[0] << " is passed(ok)!" << std::endl;
            else
                std::cout << "Test of " << args[0] << " is not passed!" << std::endl;
            return retValue_;
        }, "test", "test return value of last command." S "eg. test funname retvalue", "sys"));

        add(std::make_shared<Command>([=](Args const& args) {
            std::cout << "Press enter key..." << std::endl;
            CmdIO().readAnyKey();
            return retValue_;
        }, 
        "pause", "pause util press enter key", "sys"));

        add(std::make_shared<Command>([=](Args const& args) {
            doSingal();
            return 0;
        }, 
        "exit", "exit the program", "sys"));

        add(std::make_shared<Command>([=](Args const& args) {
            std::string group;

            if(args.size() == 2 && args[1] == "group")
                group = args[0];
            else if(args.size() == 1) {
                if(show(args[0], false))
                    return 0;
		        group = args[0];
            }
            showGroup(group);
            return retValue_;
        }, 
        "help", "show this page." S "eg. help command/group", "sys"));
    }

    bool parse(std::string const& line)
    {
        std::string cmd;
        std::istringstream is(line);
        
        is >> cmd;

        Command::Ptr command = find(cmd);
        if(!command)
        {
            std::cerr << "cannot find command: " << cmd << std::endl;
            return false;
        }
        else
        {
            std::vector<std::string> args = get_args(is);
            if(command->cpp_handler)
                retValue_ = command->cpp_handler(args);
            else
            {
                std::vector<char*> argv(args.size(), 0);
                for(size_t i = 0; i < args.size(); i++)
                    argv[i] = (char *)args[i].c_str();
                
                retValue_ = command->c_hanlder(argv.size(), argv.size() ? &argv[0] : 0);
            }
        }
        return true;
    }

接口列表:

  • signal 是否是退出信号,默认是false
  • doSingal 设置退出信号
  • add 增加命令
  • remove 删除命令
  • show 显示单条命令信息
  • showGroup 按组显示命令
  • addDefault 增加默认命令
    • ret 返回信息最后命令返回值
    • print 打印信息
    • test 测试返回值是否正确
    • pause 暂停按任意键
    • exit 退出
    • help 获取帮助信息
  • parse 解析并执行命令

3.5 CmdIO定义

class CmdIO
{
public:
    std::string readLine(const char* prompt);
    void readAnyKey();
};

接口列表:

  • readLine 从命令上读取一行
  • readAnyKey 读取任意按键

3.6 CmdIO实现

std::string CmdIO::readLine(const char* prompt)
{
	std::string line;
	std::cout << prompt;
	std::getline(std::cin, line);
	return line;
}

void CmdIO::readAnyKey() { fgetc(stdin); }

说明:

  • readLine 调用getline获得命令行
  • readAnyKey 调用fgetc读取一个按键

C++命令行系统(一)C++命令行系统(三)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励就是我最大的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值