4.9 C++ Boost 命令行解析庫(kù)
命令行解析庫(kù)是一種用于簡(jiǎn)化處理命令行參數(shù)的工具,它可以幫助開(kāi)發(fā)者更方便地解析命令行參數(shù)并提供適當(dāng)?shù)膸椭畔?。C++語(yǔ)言中,常用的命令行解析庫(kù)有許多,通過(guò)本文的學(xué)習(xí),讀者可以了解不同的命令行解析庫(kù)和它們?cè)贑++項(xiàng)目中的應(yīng)用,從而更加靈活和高效地處理命令行參數(shù)。
一般比較常見(jiàn)的解析庫(kù):
??getopt:一個(gè)C語(yǔ)言的命令行解析庫(kù),也被廣泛用于C++程序。它提供了一組函數(shù)來(lái)解析命令行參數(shù),并支持短選項(xiàng)(如 -a)和長(zhǎng)選項(xiàng)(如 --help)。
??Boost.Program_options:這是Boost庫(kù)中的一個(gè)模塊,提供了一個(gè)強(qiáng)大的命令行解析庫(kù)。它支持短選項(xiàng)、長(zhǎng)選項(xiàng)、位置參數(shù)等,并且具有很好的錯(cuò)誤處理和幫助信息生成功能。
??TCLAP:TCLAP(Templatized C++ Command Line Parser Library)是一個(gè)C++的命令行解析庫(kù),它提供了簡(jiǎn)單易用的API來(lái)解析命令行參數(shù),并支持短選項(xiàng)和長(zhǎng)選項(xiàng)。
??CLI11:CLI11是一個(gè)現(xiàn)代化的C++命令行解析庫(kù),它使用C++11標(biāo)準(zhǔn),并提供了一組簡(jiǎn)單易用的API。
這些庫(kù)各有特點(diǎn),開(kāi)發(fā)者可以根據(jù)項(xiàng)目的需求和個(gè)人喜好選擇合適的命令行解析庫(kù)。通過(guò)使用這些庫(kù),開(kāi)發(fā)者可以更輕松地處理命令行參數(shù),提高程序的易用性和用戶(hù)體驗(yàn)。在命令行程序中,argc和argv是C++程序中用于接收命令行參數(shù)的主要機(jī)制。其中:
??
argc
(Argument Count)表示命令行參數(shù)的個(gè)數(shù),包括程序本身。至少為1,即程序名。??
argv
(Argument Vector)是一個(gè)指向字符指針數(shù)組的指針,每個(gè)指針指向一個(gè)以空字符結(jié)尾的C字符串,表示一個(gè)命令行參數(shù)。
通常,argv[0]
?存儲(chǔ)的是程序的名稱(chēng),argv[1]
?開(kāi)始存儲(chǔ)的是傳遞給程序的實(shí)際命令行參數(shù)。開(kāi)發(fā)者可以通過(guò)對(duì)?argc
?和?argv
?的處理,來(lái)獲取和解析命令行參數(shù),從而完成特定功能的配置和操作。例如,使用?getopt
、Boost.Program_options
?或者其他命令行解析庫(kù)來(lái)解析和處理命令行參數(shù),更方便地獲取用戶(hù)的輸入。
9.1 在字符串上解析
該段代碼通過(guò)簡(jiǎn)單的字符串切割實(shí)現(xiàn)了對(duì)命令行參數(shù)的解析。它將命令行字符串切割為選項(xiàng)和參數(shù),并輸出它們的內(nèi)容。同時(shí),根據(jù)特定的選項(xiàng)和參數(shù)組合條件,輸出用戶(hù)登錄的相關(guān)信息。
代碼的主要流程如下:
1.?定義了一個(gè)函數(shù)?
GetOpt
,該函數(shù)接收一個(gè)字符指針?command
(命令行字符串)和一個(gè)二維字符數(shù)組?command_ptr
(用于存儲(chǔ)解析后的選項(xiàng)和參數(shù))。2.?在?
GetOpt
?函數(shù)中,使用?strtok
?函數(shù)對(duì)?command
?字符串進(jìn)行切割和解析,將選項(xiàng)和參數(shù)存儲(chǔ)在?command_ptr
?數(shù)組中,并返回選項(xiàng)和參數(shù)的總數(shù)。3.?在?
main()
?函數(shù)中,構(gòu)造一個(gè)命令行字符串?cmd
,然后調(diào)用?GetOpt
?函數(shù),將解析后的選項(xiàng)和參數(shù)存儲(chǔ)在?Opts
?數(shù)組中,并獲取選項(xiàng)和參數(shù)的總數(shù)?count
。4.?使用?
for
?循環(huán)遍歷?Opts
?數(shù)組,根據(jù)數(shù)組索引的奇偶性分別輸出命令行選項(xiàng)和參數(shù)。
讀者需要注意,此代碼使用簡(jiǎn)單的字符串切割來(lái)實(shí)現(xiàn)命令行參數(shù)的解析,并假設(shè)輸入的命令行格式是固定的,即選項(xiàng)和參數(shù)的順序和格式是固定的(如 "--address 127.0.0.1 --password 123456 --port 22")。如果輸入的命令行格式有變化或者更復(fù)雜的需求,可能需要使用更強(qiáng)大的命令行解析庫(kù)來(lái)完成更靈活的解析工作。
using?namespace?std;
//?傳入命令行,切割解析
int?GetOpt(IN?char?*command,?OUT?char?command_ptr[][1024])
{
????char*?ptr;
????ptr?=?strtok(command,?"?");
????int?count?=?0;
????while?(ptr?!=?NULL)
????{
????????strcpy(command_ptr[count++],?ptr);
????????ptr?=?strtok(NULL,?"?");
????}
????return?count;
}
int?main(int?argc,?char*?argv[])
{
????char?cmd[4096]?=?"--address?127.0.0.1?--password?123456?--port?22";
????char?Opts[30][1024];
????int?count?=?GetOpt(cmd,?Opts);
????for?(int?x?=?0;?x?<?count;?x++)
????{
????????if?(x?%?2?==?0)
????????{
????????????std::cout?<<?"命令行:?"?<<?Opts[x]?<<?std::endl;
????????}
????????else
????????{
????????????std::cout?<<?"參數(shù):?"?<<?Opts[x]?<<?std::endl;
????????}
????}
????//?參數(shù)解析使用
????if?((strcmp(Opts[0],?"--address")?==?0)?&&?(strcmp(Opts[2],?"--password")?==?0)?&&?(strcmp(Opts[4],?"--port")?==?0))
????{
????????std::cout?<<?"用戶(hù)登錄:?"?<<?Opts[1]?<<?"?密碼:?"?<<?Opts[3]?<<?"?端口:?"?<<?Opts[5]?<<?std::endl;
????}
????return?0;
}
9.2 自實(shí)現(xiàn)參數(shù)解析
這段代碼是筆者突發(fā)奇想之后寫(xiě)出來(lái)的一個(gè)簡(jiǎn)易版參數(shù)解析器,通過(guò)檢查參數(shù)個(gè)數(shù)和特定的選項(xiàng)和參數(shù)組合,輸出對(duì)應(yīng)的類(lèi)型、地址和端口信息。如果參數(shù)個(gè)數(shù)小于等于2,則輸出使用說(shuō)明;如果參數(shù)個(gè)數(shù)等于7且滿(mǎn)足特定格式 "--type tcp/udp --address 127.0.0.1 --port 8888",則輸出用戶(hù)指定的類(lèi)型、地址和端口信息。
代碼的主要流程如下:
1.?通過(guò)檢查?
argc
?的值,如果小于等于2,則輸出使用說(shuō)明提示用戶(hù)正確輸入命令行參數(shù)。2.?如果參數(shù)個(gè)數(shù)等于7,按照特定的格式 "--type tcp/udp --address 127.0.0.1 --port 8888" 進(jìn)行解析和判斷。
3.?使用?
strcmp
?函數(shù)判斷命令行選項(xiàng)是否為 "--type"、"--address" 和 "--port",并檢查其后的參數(shù)是否符合預(yù)期格式。
根據(jù)特定的選項(xiàng)和參數(shù)組合條件,輸出對(duì)應(yīng)的類(lèi)型、地址和端口信息。
int?main(int?argc,?char*?argv[])
{
????//?如果小于兩個(gè)參數(shù)則輸出提示
????if?(argc?<=?2)
????{
????????fprintf(stderr,?"\nUsage:\n\n"
????????????"?\t?--type??????????????指定類(lèi)型(string)?\n"
????????????"?\t?--address???????????指定地址(string)?\n"
????????????"?\t?--port??????????????指定端口(int)????\n\n"
????????);
????????exit(0);
????}
????//?如果參數(shù)個(gè)數(shù)是7那么總共需要有6個(gè)參數(shù)傳遞
????//?其中?1,3,5?代表的是參數(shù)開(kāi)關(guān)
????//?剩余?2,4,6?則代表每個(gè)開(kāi)關(guān)傳入?yún)?shù)
????if?(argc?==?7)
????{
????????//?--type?tcp/udp?--address?127.0.0.1?--port?8888
????????if?(strcmp((char*)argv[1],?"--type")?==?0?&&?strcmp((char*)argv[3],?"--address")?==?0?&&?strcmp((char*)argv[5],?"--port")?==?0?)
????????{
????????????//?開(kāi)關(guān)內(nèi)部,也可以嵌套繼續(xù)判斷類(lèi)型
????????????if?(strcmp((char*)argv[2],?"tcp")?==?0)
????????????{
????????????????printf("[+]?類(lèi)型:?%s?地址:?%s?端口:?%d?\n",?argv[2],?argv[4],?atoi(argv[6]));
????????????}
????????????else?if?(strcmp((char*)argv[2],?"udp")?==?0)
????????????{
????????????????printf("[+]?類(lèi)型:?%s?地址:?%s?端口:?%d?\n",?argv[2],?argv[4],?atoi(argv[6]));
????????????}
????????}
????}
????return?0;
}
如上代碼所示,是筆者最常用的命令行解析方式,這種方式比較死板無(wú)法更智能的判斷參數(shù)類(lèi)型,如果需要判斷的更全面則需要將其改進(jìn)為以下格式,改進(jìn)后雖然解析更靈活了,但管理起來(lái)也會(huì)變得更復(fù)雜。
如下所示,代碼實(shí)現(xiàn)了一個(gè)32位端口快速掃描器的簡(jiǎn)單功能。通過(guò)解析命令行參數(shù),用戶(hù)可以指定待掃描的IP地址、開(kāi)始端口和結(jié)束端口,并根據(jù)參數(shù)選擇相應(yīng)的掃描方式。如果沒(méi)有指定合法的參數(shù)或缺少必要參數(shù),則輸出工具的菜單選項(xiàng)供用戶(hù)參考。
代碼的主要流程如下:
1.?定義了一個(gè)結(jié)構(gòu)體?
GetOpt
?用于保存參數(shù)信息,并定義了全局變量?opt
?作為全局參數(shù)存儲(chǔ)對(duì)象。2.?編寫(xiě)函數(shù)?
getOpts
?對(duì)命令行參數(shù)進(jìn)行解析,并將解析結(jié)果存儲(chǔ)到結(jié)構(gòu)體?opt
?中。3.?編寫(xiě)函數(shù)?
ShowOptions
?輸出工具的菜單選項(xiàng),包含待掃描的IP地址、開(kāi)始端口和結(jié)束端口的參數(shù)說(shuō)明。
在?main()
?函數(shù)中,根據(jù)命令行參數(shù)的解析結(jié)果,輸出對(duì)應(yīng)的信息:如果同時(shí)指定了IP地址、開(kāi)始端口和結(jié)束端口,則輸出對(duì)應(yīng)的掃描信息;如果只指定了開(kāi)始端口和結(jié)束端口,則輸出端口范圍信息;否則,顯示工具的菜單選項(xiàng)。
typedef?struct?GetOpt????//?全局保存每個(gè)參數(shù)
{
??char?Address[128];???//?IP地址
??int?Start;???????????//?開(kāi)始端口
??int?End;?????????????//?結(jié)束端口
}GetOpt;
static?struct?GetOpt?opt;?//?定義全局結(jié)構(gòu)體
//?getOpts?針對(duì)參數(shù)的解析與賦值
int?getOpts(int?argc,?char?**argv)
{
??strcpy(opt.Address,?"null");???//?初始化參數(shù)解析
??opt.Start?=?0;?opt.End?=?0;????//?初始化參數(shù)解析
??for?(int?each?=?1;?each?<?argc;?each++)
??{
????if?(!strcmp(argv[each],?"--addr")?&&?each?+?1?<?argc)
????{
??????strcpy(opt.Address,?argv[++each]);
????}
????else?if?(!strcmp(argv[each],?"--start")?&&?each?+?1?<?argc)
????{
??????opt.Start?=?atoi(argv[++each]);
????}
????else?if?(!strcmp(argv[each],?"--end")?&&?each?+?1?<?argc)
????{
??????opt.End?=?atoi(argv[++each]);
????}
????else?{?return?0;?}
??}
??return?1;
}
//?輸出工具菜單選項(xiàng)
void?ShowOptions()
{
??fprintf(stderr,?"\n"
????"Usage:?32位端口快速掃描器?Ver:1.0??By:Lyshark?\n\n"
????"options:?\n"
????"\t?--addr?[addr]??????指定待掃描的Ip地址?\n"
????"\t?--start?[count]????指定待掃描的開(kāi)始端口?\n"
????"\t?--end?[count]??????指定待掃描的結(jié)束端口?\n"
????);
}
//?主函數(shù)還是用來(lái)判斷參數(shù),并執(zhí)行相應(yīng)的命令
int?main(int?argc,?char*?argv[])
{
??if?(getOpts(argc,?argv)?!=?1)
??{
????ShowOptions();
??}
??else?if?(strcmp(opt.Address,?"null")?!=?0?&&?opt.Start?!=?0?&&?opt.End?!=?0)
??{
????for?(int?x?=?0;?x?<?100;?x++)
??????printf("掃描:?%s?開(kāi)始地址:?%d?結(jié)束地址:?%d?\n",?opt.Address,?x,?opt.End);
??}
??else?if?(opt.Start?!=?0?&&?opt.End?!=?0)
??{
????for?(int?y?=?0;?y?<?10;?y++)
??????printf("端口范圍:?%d?->?%d?\n",?y,?opt.End);
??}
??else?{?ShowOptions();?}
??return?0;
}
9.3 交互式參數(shù)解析
交互式參數(shù)解析器,其實(shí)就是類(lèi)似于Linux系統(tǒng)終端那樣的頁(yè)面,運(yùn)行代碼后進(jìn)入一個(gè)可交互環(huán)境,讀者可以執(zhí)行需要的命令。該功能的實(shí)現(xiàn)依賴(lài)于tokenizer.hpp
模塊,該模塊提供了靈活、高效的字符串分割工具,可以幫助簡(jiǎn)化字符串處理的任務(wù),特別是在文本處理、配置文件解析、數(shù)據(jù)解析等方面有著廣泛的應(yīng)用。
boost/tokenizer.hpp
?主要功能是將一個(gè)字符串拆分成多個(gè)子串(tokens),通過(guò)指定分隔符或者符合某種條件的位置來(lái)實(shí)現(xiàn)字符串的分割。這在處理文本文件、解析命令行參數(shù)、數(shù)據(jù)處理等方面非常有用。
使用?boost::tokenizer
?需要包含?<boost/tokenizer.hpp>
?頭文件,并在代碼中使用?boost::tokenizer
?類(lèi)的實(shí)例對(duì)象來(lái)進(jìn)行字符串的分割。該類(lèi)提供了靈活的選項(xiàng),允許用戶(hù)指定分隔符、忽略空白字符、指定分隔符類(lèi)型等。
例如,下面是一個(gè)使用?boost::tokenizer
?進(jìn)行字符串分割的簡(jiǎn)單示例:
int?main()
{
????std::string?input?=?"Boost?C++?Libraries";
????boost::tokenizer<>?tokens(input);?//?默認(rèn)使用空格作為分隔符
????for?(const?auto&?token?:?tokens)?{
????????std::cout?<<?token?<<?std::endl;
????}
????return?0;
}
上述示例會(huì)將字符串?"Boost C++ Libraries"
?按照空格進(jìn)行分割,并輸出拆分得到的子串。運(yùn)用此功能并配合一個(gè)死循環(huán)結(jié)構(gòu)我們就可以構(gòu)建出一個(gè)交互式命令行環(huán)境,并可以根據(jù)用戶(hù)輸入的命令執(zhí)行相應(yīng)的操作。
根據(jù)上述所示的庫(kù)函數(shù),我們可以靈活的實(shí)現(xiàn)參數(shù)的解析功能,并實(shí)現(xiàn)一個(gè)簡(jiǎn)單的交互式參數(shù)解析功能,如下所示將提供三個(gè)交互命令,讀者可自行編譯并運(yùn)行測(cè)試。
代碼的主要流程如下:
1.?使用?
std::getline(std::cin, command)
?從標(biāo)準(zhǔn)輸入讀取用戶(hù)輸入的命令,并將命令存儲(chǔ)在字符串?command
?中。2.?通過(guò)字符串的比較判斷用戶(hù)輸入的命令,如果是 "help" 則輸出功能菜單,展示可用的命令選項(xiàng)。
3.?使用?
boost::tokenizer
?將用戶(hù)輸入的命令進(jìn)行分割,提取出命令關(guān)鍵詞和參數(shù)。4.?根據(jù)分割后的命令關(guān)鍵詞和參數(shù),執(zhí)行相應(yīng)的功能:
??如果是 "AddRule" 命令,則解析地址和DNS參數(shù),并輸出解析結(jié)果。
??如果是 "DeleteRule" 命令,則解析地址參數(shù),并輸出刪除地址信息。
??如果是 "ShowList" 命令,則輸出一個(gè)簡(jiǎn)單的數(shù)字列表。
using?namespace?std;
using?namespace?boost;
int?main(int?argc,?char?const?*argv[])
{
??std::string?command;
??while?(1)
??{
????std::cout?<<?"[LyShark]?#?";
????std::getline(std::cin,command);
????if?(command.length()?==?0)
????{
??????continue;
????}
????else?if?(command?==?"help")
????{
??????std::cout?<<?"[功能菜單]?\n"?<<?std::endl;
??????std::cout?<<?"增加規(guī)則:?AddRule?--address?192.168.1.1?--dns?8.8.8.8"?<<?std::endl;
??????std::cout?<<?"刪除規(guī)則:?DeleteRule?--address?192.168.1.1"?<<?std::endl;
??????std::cout?<<?"輸出列表:?ShowList"?<<?std::endl;
????}
????else
????{
??????//?定義分詞器:?定義分割符號(hào)為[逗號(hào),空格]
??????boost::char_separator<char>?sep(",?--");
??????typedef?boost::tokenizer<boost::char_separator<char>>?CustonTokenizer;
??????CustonTokenizer?tok(command,?sep);
??????//?將分詞結(jié)果放入vector鏈表
??????std::vector<std::string>?vecSegTag;
??????for?(CustonTokenizer::iterator?beg?=?tok.begin();?beg?!=?tok.end();?++beg)
??????{
????????vecSegTag.push_back(*beg);
??????}
??????//?解析?[shell]?#?AddRule?--address?192.168.1.1?--dns?8.8.8.8
??????if?(vecSegTag.size()?==?5?&&?vecSegTag[0]?==?"AddRule")
??????{
????????if?(vecSegTag[1]?==?"address"?&&?vecSegTag[3]?==?"dns")
????????{
??????????std::string?set_address?=?vecSegTag[2];
??????????std::string?set_dns?=?vecSegTag[4];
??????????std::cout?<<?"解析地址:?"?<<?vecSegTag[2]?<<?"解析DNS:?"?<<?vecSegTag[4]?<<?std::endl;
????????}
??????}
??????//?解析?[shell]?#?DeleteRule?--address?192.168.1.1
??????else?if?(vecSegTag.size()?==?3?&&?vecSegTag[0]?==?"DeleteRule")
??????{
????????if?(vecSegTag[1]?==?"address")
????????{
??????????std::string?del_address?=?vecSegTag[2];
??????????std::cout?<<?"刪除地址:?"?<<?del_address?<<?std::endl;
????????}
??????}
??????//?解析?[shell]?#?ShowList
??????else?if?(vecSegTag.size()?==?1?&&?vecSegTag[0]?==?"ShowList")
??????{
????????for?(int?x?=?0;?x?<?10;?x++)
????????{
??????????std::cout?<<?x?<<?std::endl;
????????}
??????}
????}
??}
??return?0;
}
9.4 非交互參數(shù)解析
雖然分詞器可以用于參數(shù)解析,但是其本身并不是用于做參數(shù)解析用的,在Boost中提供了Boost.Program_options
庫(kù),該框架提供了強(qiáng)大而靈活的命令行選項(xiàng)解析功能,可以幫助簡(jiǎn)化處理命令行參數(shù)的過(guò)程,并提供良好的幫助信息和錯(cuò)誤處理機(jī)制,是處理命令行參數(shù)的優(yōu)秀工具庫(kù)之一。
使用?Boost.Program_options
?需要包含?<boost/program_options.hpp>
?頭文件,并通過(guò)創(chuàng)建?boost::program_options::options_description
?對(duì)象來(lái)定義選項(xiàng)描述,然后使用?boost::program_options::parse_command_line
?函數(shù)解析命令行參數(shù),最后通過(guò)?boost::program_options::variables_map
?對(duì)象獲取解析后的選項(xiàng)和參數(shù)的值。
例如,下面是一個(gè)使用?Boost.Program_options
?解析命令行參數(shù)的簡(jiǎn)單示例:
代碼的主要流程如下:
1.?使用?
boost::program_options::options_description
?定義命令行選項(xiàng)描述,包含三個(gè)選項(xiàng):address
、start_port
?和?end_port
,以及一個(gè)?help
?選項(xiàng)用于輸出幫助菜單。2.?使用?
boost::program_options::parse_command_line
?函數(shù)解析命令行參數(shù),并將解析結(jié)果存儲(chǔ)在?boost::program_options::variables_map
?對(duì)象?virtual_map
?中。3.?使用?
boost::program_options::notify
?函數(shù)檢查命令行參數(shù)是否符合預(yù)期,并存儲(chǔ)解析后的值到?virtual_map
。4.?根據(jù)?
virtual_map
中存儲(chǔ)的命令行參數(shù)值,判斷用戶(hù)輸入的選項(xiàng)并執(zhí)行相應(yīng)的操作:??如果用戶(hù)輸入了?
--help
?或?-h
?選項(xiàng),則輸出幫助菜單。??如果用戶(hù)輸入了?
--address
、--start_port
?和?--end_port
?選項(xiàng),則輸出掃描地址、開(kāi)始端口和結(jié)束端口的信息。??如果用戶(hù)輸入了未定義的選項(xiàng)或缺少必需的選項(xiàng),則輸出參數(shù)錯(cuò)誤信息。
通過(guò)使用?Boost.Program_options
?庫(kù),可以更方便地定義和解析命令行選項(xiàng),從而使程序的命令行使用更加友好和靈活。
namespace?opt?=?boost::program_options;
int?main(int?argc,?char?const?*argv[])
{
??opt::options_description?des_cmd("\n?Usage:?32位端口快速掃描器?Ver:1.0?\n\n?Options");
??des_cmd.add_options()
????("address,a",?opt::value<std::string>()->default_value("127.0.0.1"),?"指定掃描地址")
????("start_port,s",?opt::value<int>()->default_value(0),?"掃描開(kāi)始端口")
????("end_port,e",?opt::value<int>()->default_value(65535),?"掃描結(jié)束端口")
????("help,h",?"幫助菜單");
??opt::variables_map?virtual_map;
??try
??{
????opt::store(opt::parse_command_line(argc,?argv,?des_cmd),?virtual_map);
??}
??catch?(...){?return?0;?}
??//?定義消息
??opt::notify(virtual_map);
??//?無(wú)參數(shù)直接返回
??if?(virtual_map.empty())
??{
????return?0;
??}
??else?if?(virtual_map.count("help")?||?virtual_map.count("h"))
??{
????std::cout?<<?des_cmd?<<?std::endl;
????return?0;
??}
??else?if?(virtual_map.count("address")?&&?virtual_map.count("start_port")?&&?virtual_map.count("end_port"))
??{
????std::string?address?=?virtual_map["address"].as<std::string>();
????int?start_port?=?virtual_map["start_port"].as<int>();
????int?end_port?=?virtual_map["end_port"].as<int>();
????//?判斷是不是默認(rèn)參數(shù)
????if?(?address?==?"127.0.0.1"?||?start_port?==?0?||?end_port?==?65535)
????{
??????std::cout?<<?des_cmd?<<?std::endl;
????}
????else
????{
??????std::cout?<<?"開(kāi)始掃描:?"?<<?address?<<?"?開(kāi)始地址:?"?<<?start_port?<<?"??結(jié)束地址:?"?<<?end_port?<<?std::endl;
????}
??}
??else
??{
????std::cout?<<?"參數(shù)錯(cuò)誤"?<<?std::endl;
??}
??return?0;
}
當(dāng)然了,上述代碼中我們也可以單獨(dú)增加一個(gè)Banner()
函數(shù),并將其放入到virtual_map.empty()
無(wú)參數(shù)模式,這樣一來(lái)當(dāng)參數(shù)輸入不當(dāng)或無(wú)參數(shù)是則會(huì)打印輸出我們自己的點(diǎn)陣標(biāo)志,能使程序變得更友好。
namespace?opt?=?boost::program_options;
void?Banner()
{
????printf("?_???????????_????????????????_?????\n");
????printf("|?|_???_?___|?|__???__?_?_?__|?|?__?\n");
????printf("|?|?|?|?/?__|?'_?\\?/?_`?|?'__|?|/?/?\n");
????printf("|?|?|_|?\\__?\\?|?|?|?(_|?|?|??|???<??\n");
????printf("|_|\\__,?|___/_|?|_|\\__,_|_|??|_|\\_\\?\n");
????printf("???|___/????????????????????????????\n\n");
}
int?main(int?argc,?char?const?*argv[])
{
??opt::options_description?des_cmd("\n?Usage:?輸出Logo?Ver:1.0?\n\n?Options");
??des_cmd.add_options()
????("address,a",?opt::value<std::string>(),?"指定掃描地址")
????("start_port,s",?opt::value<int>(),?"掃描開(kāi)始端口")
????("end_port,e",?opt::value<int>(),?"掃描結(jié)束端口")
????("help,h",?"幫助菜單");
??opt::variables_map?virtual_map;
??try
??{
????opt::store(opt::parse_command_line(argc,?argv,?des_cmd),?virtual_map);
??}
??catch?(...){?return?0;?}
??//?定義消息
??opt::notify(virtual_map);
??//?無(wú)參數(shù)直接返回
??if?(virtual_map.empty())
??{
????Banner();
????std::cout?<<?des_cmd?<<?std::endl;
????return?0;
??}
??//?幫助菜單
??else?if?(virtual_map.count("help")?||?virtual_map.count("h"))
??{
????Banner();
????std::cout?<<?des_cmd?<<?std::endl;
????return?0;
??}
??//?分支結(jié)構(gòu)1
??else?if?(virtual_map.count("address")?&&?virtual_map.count("start_port")?&&?virtual_map.count("end_port"))
??{
????std::string?address?=?virtual_map["address"].as<std::string>();
????int?start_port?=?virtual_map["start_port"].as<int>();
????int?end_port?=?virtual_map["end_port"].as<int>();
????std::cout?<<?"開(kāi)始掃描:?"?<<?address?<<?"?開(kāi)始地址:?"?<<?start_port?<<?"??結(jié)束地址:?"?<<?end_port?<<?std::endl;
??}
??//?分支結(jié)構(gòu)2
??else?if?(virtual_map.count("address"))
??{
????std::string?address?=?virtual_map["address"].as<std::string>();
????std::cout?<<?"地址:?"?<<?address?<<?std::endl;
??}
??else
??{
????std::cout?<<?"參數(shù)錯(cuò)誤"?<<?std::endl;
??}
??return?0;
}
本文作者: 王瑞 本文鏈接: https://www.lyshark.com/post/8b095ec4.html 版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請(qǐng)注明出處!