boost::program_options 命令行解析器应用实例

在linux里面的服务进程,需要提供两个接口:基于命令行的cli接口,基于api的应用接口。
其中cli命令接口,经过解析后,调用的也是api接口,实现业务功能。

cli的设计模式:命令解析器、dispatch器、callback handler
个人写的小项目来说,一般在启动的时候,用于Get一些参数,如ip port,thread_num,period,等。
对于中型大型项目,参数往外是在运行的过程中,按需传入。因此需要设计为c/s模式。即:使用Unix本机通讯、或Http服务器和主进程一起运行。 cli另外实现一个unix通讯或http客户端,找到daemon进程。这种模式是一种服务器代理模式,代理的对象就是命令行传入。

linux c 中的命令解析器是用getopt()和getopt_long来获取参数的

 #include <unistd.h>
       
int getopt(int argc, char * const argv[], const char *optstring);

int getopt_long(int argc, char * const argv[],
                  const char *optstring,
                  const struct option *longopts, int *longindex);

在c++ boost库提供了一个封装好的模板,弥补了getopt()的不足之处,提供更丰富,安全,易用的cli解析接口。

//cli.hpp
#include <iostream>
#include <iostream>
#include <string>
#include <boost/program_options.hpp>
using namespace std;
namespace  bpo = boost::program_options;

namespace ipfs
{
	namespace detail {
		enum SUB_CMD {

			INIT = 1, 
			DAEMON, 
			ADD, 
			OBJECT,  
			CAT, 
			GET, 
			LS,
			HELP,
			UNKNOW,
		};

		SUB_CMD cmd_parser(int argc, char **argv, vector<string> & item) {
			item.clear();
			// 定义命令描述、命令参数
			const string descs = "USAGE\
					      \n  ipfs - Global p2p merkle-dag filesystem.\
					      \n\
					      \n  ipfs [--config=<config> | -c] [--debug | -D] [--help] [-h] [--api=<api>] [--offline] [--cid-base=<base>] [--upgrade-cidv0-in-output]\
					      \n	 [--encoding=<encoding> | --enc] [--timeout=<timeout>] <command> ...\
					      ";
			bpo::options_description opts(descs);

			opts.add_options()
				("init", "Initialize ipfs local configuration")
				("daemon",  bpo::value<string>(), "Start a long-running daemon process")
				("add", bpo::value<std::vector<std::string>>()->multitoken(), "the file name which add to ipfs repository")
				("object", bpo::value<string>(), "Interact with raw dag nodes")
				("cat", bpo::value<string>(), "Show IPFS object data")
				("get", bpo::value<string>(), "Download IPFS objects")
				("ls", bpo::value<string>(), "List links from an object")
				("help", "this is a program to find a specified file");
				
			// 保存参数到解析器
			bpo::variables_map vm;
			try{
				bpo::store(bpo::parse_command_line(argc, argv, opts), vm);
			}
			catch(...){
				cout << "输入的参数中存在未定义的选项!\n";
				cout << opts << endl;
				return UNKNOW;
			}

			// 读取参数解析器
			if( vm.count("init") ) {
				cout << "init repository." << endl;
				return INIT;
			}
			else if( vm.count("daemon") ) {
				string mode = vm["daemon"].as<string>();
				item.push_back(mode);
				//cout << "start ipfs daemon." << endl;
				return DAEMON;
			}
			else if( vm.count("add") ) {
				//std::cout << "file which added is:";
				for(auto& str : vm["add"].as<std::vector<std::string> >() )  {
					//std::cout << str << " ";
					item.push_back(str);
				}
				//std::cout << std::endl;				

				//cout << "add file " << vm["add"].as<string>() << " to ipfs repository" << endl;
				return ADD;
			}
			else if( vm.count("object") ) {
				string str = vm["object"].as<string>();
				//cout << "object " << str << " to ipfs repository" << endl;
				item.push_back(str);
				return OBJECT;
			}			
			else if( vm.count("cat") ) {
				string id = vm["cat"].as<string>();
				//cout << "cat " << id << " from ipfs repository" << endl;
				item.push_back(id);
				return CAT;
			}
			else if( vm.count("get") ) {
				string id = vm["get"].as<string>();
				//cout << "get " << id << " get from ipfs repository" << endl;
				item.push_back(id);
				return GET;
			}
			else if( vm.count("ls") ) {
				string id = vm["ls"].as<string>();
				//cout << "ls " << id << " to ipfs repository" << endl;
				item.push_back(id);
				return LS;
			}
			else if( vm.count("help") ) {
				cout << opts << endl;
				return HELP;
			}
			else if( vm.empty() ) {
				cout << "no options found \n";
				cout << opts << endl;
			}

			return UNKNOW;
		}
	}
}
//main.cc
#include <iostream>
#include <boost/program_options.hpp>
#include "cli.hpp"

using namespace std;
namespace po = boost::program_options;


int main(int agrc, char **argv)
{
	vector<string> item;
	SUB_CMD cmd = cmd_parser(argc, argv, item);

	switch (cmd) {
		case INIT:
			break;
	
		case DAEMON:
	                {   
				bool bootstrap_mode = false;
				for (auto & it : item) {
					if (it == "bootstrap") {
						bootstrap_mode = true;
						break;
					}
				}
				if (bootstrap_mode) {
					cout << " mode is daemon." << endl;
					daemon(1, 1);
				}
			break;
		
		case ADD:
			// 只操作本地仓库
			for (auto& path : item) {
				cout << "ADD" << endl;
			}
			break;
			
		case OBJECT:
			break;
			
		case CAT:
			;
			break;
			
		case GET:
			;
			break;
			
		case LS:
			;
			break;
			
		case HELP:
			;
			break;
			
		case UNKNOW:
			;
			break;
		}
}
发布了61 篇原创文章 · 获赞 63 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/jacky128256/article/details/102548609