799 lines
20 KiB
C++
799 lines
20 KiB
C++
|
/********************************************************
|
|||
|
* ██████╗ ██████╗████████╗██╗
|
|||
|
* ██╔════╝ ██╔════╝╚══██╔══╝██║
|
|||
|
* ██║ ███╗██║ ██║ ██║
|
|||
|
* ██║ ██║██║ ██║ ██║
|
|||
|
* ╚██████╔╝╚██████╗ ██║ ███████╗
|
|||
|
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
|||
|
* Geophysical Computational Tools & Library (GCTL)
|
|||
|
*
|
|||
|
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
|
|||
|
*
|
|||
|
* GCTL is distributed under a dual licensing scheme. You can redistribute
|
|||
|
* it and/or modify it under the terms of the GNU Lesser General Public
|
|||
|
* License as published by the Free Software Foundation, either version 2
|
|||
|
* of the License, or (at your option) any later version. You should have
|
|||
|
* received a copy of the GNU Lesser General Public License along with this
|
|||
|
* program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
*
|
|||
|
* If the terms and conditions of the LGPL v.2. would prevent you from using
|
|||
|
* the GCTL, please consider the option to obtain a commercial license for a
|
|||
|
* fee. These licenses are offered by the GCTL's original author. As a rule,
|
|||
|
* licenses are provided "as-is", unlimited in time for a one time fee. Please
|
|||
|
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
|
|||
|
* to include some description of your company and the realm of its activities.
|
|||
|
* Also add information on how to contact you by electronic and paper mail.
|
|||
|
******************************************************/
|
|||
|
|
|||
|
#include "getopt_help.h"
|
|||
|
|
|||
|
|
|||
|
/**
|
|||
|
* @brief Display a string massage using the standard outputs.
|
|||
|
*
|
|||
|
* @param[in] f_space The front space before the printing.
|
|||
|
* @param[in] b_space The end space before the printing.
|
|||
|
* @param[in] hang_space The hang space starting from the second line.
|
|||
|
* @param[in] wth window size of the terminal
|
|||
|
* @param[in] msg The message
|
|||
|
* @param[in] stdout Output stream. The default is the standard error output
|
|||
|
*/
|
|||
|
void display_line(int f_space, int b_space, int hang_space, int wth, std::string msg, std::ostream& sout=std::clog)
|
|||
|
{
|
|||
|
int line_length = f_space + b_space;
|
|||
|
std::string segment;
|
|||
|
std::stringstream ss_message;
|
|||
|
|
|||
|
ss_message.clear();
|
|||
|
ss_message.str(msg);
|
|||
|
while (ss_message >> segment)
|
|||
|
{
|
|||
|
if ((line_length+segment.length()) <= wth)
|
|||
|
{
|
|||
|
if (line_length == f_space+b_space)
|
|||
|
{
|
|||
|
for (int i = 0; i < f_space; i++)
|
|||
|
sout << " ";
|
|||
|
sout << segment << " ";
|
|||
|
line_length += segment.length()+1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sout << segment << " ";
|
|||
|
line_length += segment.length()+1;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sout << std::endl;
|
|||
|
for (int i = 0; i < f_space+hang_space; i++)
|
|||
|
sout << " ";
|
|||
|
sout << segment << " ";
|
|||
|
line_length = (segment.length()+1+hang_space+f_space+b_space);
|
|||
|
}
|
|||
|
}
|
|||
|
sout << std::endl;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief display formatted help information in terminal
|
|||
|
*
|
|||
|
* This function will display formated help information in the terminal using
|
|||
|
* the standard error output. We choose the error output to avoid unexpected
|
|||
|
* redirection and make sure the information will appear in the terminal.
|
|||
|
*
|
|||
|
* @param[in] proname The program's name.
|
|||
|
* @param[in] brief The brief information show right after the program's name.
|
|||
|
* @param[in] exp_longopts The pointer of expanded longopts
|
|||
|
*/
|
|||
|
void gctl::getopt_long_help(const option *longopts, const option_info *expd_longopts, const char* proname,
|
|||
|
const char* brief, std::ostream& sout, std::string extra_usage)
|
|||
|
{
|
|||
|
// Default layout. One can only change this by recompile the library.
|
|||
|
int front_space = 0, back_space = 10;
|
|||
|
|
|||
|
int line_length;
|
|||
|
std::string m1, m2, m3;
|
|||
|
std::string segment;
|
|||
|
std::stringstream ss_message;
|
|||
|
|
|||
|
int width;
|
|||
|
//获取终端窗口的行列数
|
|||
|
#ifdef _WINDOWS
|
|||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|||
|
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
|
|||
|
width = csbi.srWindow.Right - csbi.srWindow.Left;
|
|||
|
#else
|
|||
|
struct winsize w;
|
|||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
|||
|
width = w.ws_col;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
// We firstly display the program's name which is assumed to be the first argument.
|
|||
|
m1 = proname;
|
|||
|
m1 += " - ";
|
|||
|
m2 = brief;
|
|||
|
m1 += m2;
|
|||
|
display_line(front_space, back_space, 4, width, m1, sout);
|
|||
|
sout << std::endl;
|
|||
|
|
|||
|
// display usage
|
|||
|
int loop_index = 0;
|
|||
|
m2 = proname;
|
|||
|
m1 = "Usage: " + m2;
|
|||
|
while(1)
|
|||
|
{
|
|||
|
if (longopts[loop_index].name != 0 && expd_longopts[loop_index].format != 0)
|
|||
|
{
|
|||
|
if (longopts[loop_index].val >= 65 && longopts[loop_index].val <= 122)
|
|||
|
m2 = (char)longopts[loop_index].val;
|
|||
|
else
|
|||
|
{
|
|||
|
m2 = "-";
|
|||
|
m2 += longopts[loop_index].name;
|
|||
|
}
|
|||
|
|
|||
|
m3 = expd_longopts[loop_index].format;
|
|||
|
if (!expd_longopts[loop_index].manda)
|
|||
|
m1 += " [-" + m2 + m3 +"]";
|
|||
|
else
|
|||
|
{
|
|||
|
#ifdef _WINDOWS
|
|||
|
m1 += " -" + m2 + m3;
|
|||
|
#else
|
|||
|
m1 += GCTL_BOLD;
|
|||
|
m1 += " -" + m2 + m3;
|
|||
|
m1 += GCTL_RESET;
|
|||
|
#endif
|
|||
|
}
|
|||
|
loop_index++;
|
|||
|
}
|
|||
|
else if (longopts[loop_index].name != 0)
|
|||
|
{
|
|||
|
if (longopts[loop_index].val >= 65 && longopts[loop_index].val <= 122)
|
|||
|
m2 = (char)longopts[loop_index].val;
|
|||
|
else
|
|||
|
{
|
|||
|
m2 = "-";
|
|||
|
m2 += longopts[loop_index].name;
|
|||
|
}
|
|||
|
|
|||
|
if (!expd_longopts[loop_index].manda)
|
|||
|
m1 += " [-" + m2 + "]";
|
|||
|
else
|
|||
|
{
|
|||
|
#ifdef _WINDOWS
|
|||
|
m1 += " -" + m2;
|
|||
|
#else
|
|||
|
m1 += GCTL_BOLD;
|
|||
|
m1 += " -" + m2;
|
|||
|
m1 += GCTL_RESET;
|
|||
|
#endif
|
|||
|
}
|
|||
|
loop_index++;
|
|||
|
}
|
|||
|
else break;
|
|||
|
}
|
|||
|
m1 += extra_usage;
|
|||
|
|
|||
|
display_line(front_space, back_space, 7, width, m1, sout);
|
|||
|
sout << std::endl;
|
|||
|
|
|||
|
//找到最长的选项作为排版的依据
|
|||
|
int temp_len, remain_len, max_opt_length = -1;
|
|||
|
loop_index = 0;
|
|||
|
while(1)
|
|||
|
{
|
|||
|
if (longopts[loop_index].name != 0)
|
|||
|
{
|
|||
|
temp_len = strlen(longopts[loop_index].name);
|
|||
|
max_opt_length = std::max(max_opt_length, temp_len + 1);
|
|||
|
loop_index++;
|
|||
|
}
|
|||
|
else break;
|
|||
|
}
|
|||
|
|
|||
|
m1 = "Options:";
|
|||
|
display_line(front_space, back_space, 0, width, m1, sout);
|
|||
|
|
|||
|
// display usage
|
|||
|
loop_index = 0;
|
|||
|
while(1)
|
|||
|
{
|
|||
|
if (longopts[loop_index].name != 0)
|
|||
|
{
|
|||
|
for (int j = 0; j < front_space+2; j++)
|
|||
|
sout << " ";
|
|||
|
|
|||
|
temp_len = strlen(longopts[loop_index].name) + 1;
|
|||
|
remain_len = max_opt_length - temp_len;
|
|||
|
|
|||
|
if (longopts[loop_index].val >= 65 && longopts[loop_index].val <= 122)
|
|||
|
{
|
|||
|
if (expd_longopts[loop_index].manda)
|
|||
|
{
|
|||
|
#ifdef _WINDOWS
|
|||
|
sout << "-" << (char)longopts[loop_index].val
|
|||
|
<< " --" << longopts[loop_index].name << " ";
|
|||
|
#else
|
|||
|
sout << GCTL_BOLD << "-" << (char)longopts[loop_index].val
|
|||
|
<< " --" << longopts[loop_index].name << GCTL_RESET << " ";
|
|||
|
#endif
|
|||
|
}
|
|||
|
else sout << "-" << (char)longopts[loop_index].val
|
|||
|
<< " --" << longopts[loop_index].name << " ";
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (expd_longopts[loop_index].manda)
|
|||
|
{
|
|||
|
#ifdef _WINDOWS
|
|||
|
sout << " --" << longopts[loop_index].name << " ";
|
|||
|
#else
|
|||
|
sout << GCTL_BOLD << " --" << longopts[loop_index].name << GCTL_RESET << " ";
|
|||
|
#endif
|
|||
|
}
|
|||
|
else sout << " --" << longopts[loop_index].name << " ";
|
|||
|
}
|
|||
|
|
|||
|
for (int j = 0; j < remain_len; j++)
|
|||
|
sout << " ";
|
|||
|
|
|||
|
ss_message.clear();
|
|||
|
ss_message.str(expd_longopts[loop_index].info);
|
|||
|
line_length = front_space + back_space + max_opt_length + 14;
|
|||
|
while(ss_message >> segment)
|
|||
|
{
|
|||
|
if ((line_length+segment.length()+1) <= width)
|
|||
|
{
|
|||
|
sout << segment << " ";
|
|||
|
line_length += (segment.length()+1);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sout << std::endl;
|
|||
|
for (int j = 0; j < front_space+max_opt_length+13; j++)
|
|||
|
sout << " ";
|
|||
|
sout << segment << " ";
|
|||
|
line_length = (segment.length()+13+max_opt_length+front_space+back_space);
|
|||
|
}
|
|||
|
}
|
|||
|
sout << std::endl;
|
|||
|
|
|||
|
loop_index++;
|
|||
|
}
|
|||
|
else break;
|
|||
|
}
|
|||
|
sout << std::endl;
|
|||
|
|
|||
|
m1 = "This page is generated by the GCTL library automatically.";
|
|||
|
display_line(front_space, back_space, 4, width, m1, sout);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @brief Display the help information of one option indicated by its id.
|
|||
|
*
|
|||
|
* @param[in] val The option's value
|
|||
|
* @param exp_longopts The expanded longopts
|
|||
|
*/
|
|||
|
void gctl::getopt_long_option_info(int val, const option *longopts, const option_info *expd_longopts,
|
|||
|
std::ostream& sout)
|
|||
|
{
|
|||
|
int width;
|
|||
|
//获取终端窗口的行列数
|
|||
|
#ifdef _WINDOWS
|
|||
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|||
|
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
|
|||
|
width = csbi.srWindow.Right - csbi.srWindow.Left;
|
|||
|
#else
|
|||
|
struct winsize w;
|
|||
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
|||
|
width = w.ws_col;
|
|||
|
#endif
|
|||
|
|
|||
|
std::string m1, m2;
|
|||
|
int loop_index = 0;
|
|||
|
while (1)
|
|||
|
{
|
|||
|
if (longopts[loop_index].name != 0)
|
|||
|
{
|
|||
|
if (longopts[loop_index].val == val)
|
|||
|
{
|
|||
|
m1 = "Option: -";
|
|||
|
m2 = (char)longopts[loop_index].val;
|
|||
|
m1 += m2;
|
|||
|
|
|||
|
if (expd_longopts[loop_index].format != 0)
|
|||
|
{
|
|||
|
m2 = expd_longopts[loop_index].format;
|
|||
|
m1 += m2 + " ";
|
|||
|
}
|
|||
|
else m1 += " ";
|
|||
|
|
|||
|
m2 = expd_longopts[loop_index].info;
|
|||
|
m1 += m2;
|
|||
|
display_line(0, 10, 4, width, m1, sout);
|
|||
|
}
|
|||
|
loop_index++;
|
|||
|
}
|
|||
|
else break;
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 以下为类的方法定义
|
|||
|
*/
|
|||
|
|
|||
|
gctl::flags_parser::flags_parser()
|
|||
|
{
|
|||
|
configured_ = false;
|
|||
|
failed_mandatory_ = false;
|
|||
|
pro_name_ = pro_info_ = "";
|
|||
|
nofound_return_ = "NULL";
|
|||
|
noarg_return_ = "NO_ARG";
|
|||
|
}
|
|||
|
|
|||
|
gctl::flags_parser::~flags_parser(){}
|
|||
|
|
|||
|
void gctl::flags_parser::add_opt(int s_name, const char* f_name, int has_arg,
|
|||
|
int *flag, const char* info, const char* format, bool manda)
|
|||
|
{
|
|||
|
option p = {f_name, has_arg, flag, s_name};
|
|||
|
option_info f = {info, format, manda};
|
|||
|
rec_opts_.push_back(p);
|
|||
|
rec_info_.push_back(f);
|
|||
|
configured_ = false;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::configure(int argc, char **argv)
|
|||
|
{
|
|||
|
if (rec_opts_.empty())
|
|||
|
throw length_error("No option registered yet. From flags_parser::configure(...)");
|
|||
|
|
|||
|
if (pro_name_ == "" || pro_info_ == "")
|
|||
|
throw invalid_argument("The program's name or description is not set. From flags_parser::configure(...)");
|
|||
|
|
|||
|
// 拷贝命令行参数个数与地址
|
|||
|
argc_ = argc;
|
|||
|
argv_ = &argv[0];
|
|||
|
|
|||
|
// 先在记录的option与option_info后添加一个全为0的对象
|
|||
|
option p = {0, 0, 0, 0};
|
|||
|
option_info f = {0, 0, 0};
|
|||
|
rec_opts_.push_back(p);
|
|||
|
rec_info_.push_back(f);
|
|||
|
|
|||
|
// 解析参数符号串
|
|||
|
arg_format_ = "";
|
|||
|
// 最后一个参数是空的 不要
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
arg_format_ += (char) rec_opts_[i].val;
|
|||
|
if (rec_opts_[i].has_arg == 1) arg_format_ += ":";
|
|||
|
else if (rec_opts_[i].has_arg == 2) arg_format_ += "::";
|
|||
|
}
|
|||
|
|
|||
|
configured_ = true;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
bool gctl::flags_parser::pass_mandatory()
|
|||
|
{
|
|||
|
return !failed_mandatory_;
|
|||
|
}
|
|||
|
|
|||
|
int gctl::flags_parser::set_opt(const int s_name)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
throw runtime_error("flags_parser is not configured. From flags_parser::set_opt(...)");
|
|||
|
|
|||
|
int is_set = 0;
|
|||
|
|
|||
|
// 下面这段检查是针对程序编写中的可能出现的错误调用
|
|||
|
bool is_manda = false;
|
|||
|
bool registered = false;
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
if (s_name == rec_opts_[i].val)
|
|||
|
{
|
|||
|
registered = true;
|
|||
|
if (rec_info_[i].manda) is_manda = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!registered)
|
|||
|
{
|
|||
|
err_str = "Option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " is not registered. Use flags_parser::add_opt() to register before use. From flags_parser::set_opt(...)";
|
|||
|
throw domain_error(err_str);;
|
|||
|
}
|
|||
|
|
|||
|
optind = 0; // 重置已分析参数个数 再从头分析一遍
|
|||
|
while (1)
|
|||
|
{
|
|||
|
int optIndex = 0;
|
|||
|
int curr = getopt_long(argc_, argv_, arg_format_.c_str(), rec_opts_.data(), &optIndex);
|
|||
|
if (curr == -1 && is_manda)
|
|||
|
{
|
|||
|
err_str = "Mandatory option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " is not found and returned -1. From flags_parser::set_opt().";
|
|||
|
GCTL_ShowWhatError(err_str, GCTL_ERROR_ERROR, 0, 0, 0);
|
|||
|
show_option_info(s_name);
|
|||
|
is_set = -1;
|
|||
|
failed_mandatory_ = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (curr == -1) break;
|
|||
|
|
|||
|
if (curr == s_name)
|
|||
|
{
|
|||
|
is_set = 1; break;
|
|||
|
}
|
|||
|
else if (curr == '?')
|
|||
|
{
|
|||
|
err_str = "Invalid option found and returned 0. From flags_parser::set_opt().";
|
|||
|
GCTL_ShowWhatError(err_str, GCTL_ERROR_ERROR, 0, 0, 0);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return is_set;
|
|||
|
}
|
|||
|
|
|||
|
int gctl::flags_parser::set_opt(const char* f_name)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
{
|
|||
|
err_str = "flags_parser is not configured. From flags_parser::set_opt(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
// 下面这段检查是针对程序编写中的可能出现的错误调用
|
|||
|
int s_name = '?';
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
if (!strcmp(f_name, rec_opts_[i].name))
|
|||
|
{
|
|||
|
s_name = rec_opts_[i].val;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (s_name == '?')
|
|||
|
{
|
|||
|
err_str = "Option --";
|
|||
|
err_str += f_name;
|
|||
|
err_str += " is not registered. Use flags_parser::add_opt() to register before use. From flags_parser::set_opt(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
return set_opt(s_name);
|
|||
|
}
|
|||
|
|
|||
|
std::string gctl::flags_parser::get_arg(const int s_name)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
{
|
|||
|
err_str = "flags_parser is not configured. From flags_parser::get_arg(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
std::string out_opt = nofound_return_;
|
|||
|
|
|||
|
// 下面这段检查是针对程序编写中的可能出现的错误调用
|
|||
|
bool registered = false;
|
|||
|
bool no_arg = true;
|
|||
|
bool is_manda = false;
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
if (s_name == rec_opts_[i].val)
|
|||
|
{
|
|||
|
registered = true;
|
|||
|
if (rec_opts_[i].has_arg != 0) no_arg = false;
|
|||
|
if (rec_info_[i].manda) is_manda = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!registered)
|
|||
|
{
|
|||
|
err_str = "Option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " is not registered. Use flags_parser::add_opt() to register before use. From flags_parser::get_arg(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
if (no_arg)
|
|||
|
{
|
|||
|
err_str = "Option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " has no argument. From flags_parser::get_arg(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
// 下面是检查命令行参数拾取中的可能出现的错误输入
|
|||
|
optind = 0; // 重置已分析参数个数 再从头分析一遍
|
|||
|
while (1)
|
|||
|
{
|
|||
|
int optIndex = 0;
|
|||
|
int curr = getopt_long(argc_, argv_, arg_format_.c_str(), rec_opts_.data(), &optIndex);
|
|||
|
if (curr == -1 && is_manda)
|
|||
|
{
|
|||
|
err_str = "Mandatory option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " is not found and returned NULL. From flags_parser::get_arg(...)";
|
|||
|
GCTL_ShowWhatError(err_str, GCTL_ERROR_ERROR, 0, 0, 0);
|
|||
|
show_option_info(s_name);
|
|||
|
failed_mandatory_ = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (curr == -1) break;
|
|||
|
|
|||
|
if (curr == s_name)
|
|||
|
{
|
|||
|
/**
|
|||
|
* 注意 如果s_name对应的选项的参数是可选的(optional_argument) 则其在调用get_arg()时可能没有参数
|
|||
|
* 此时optarg2将指向一个空指针 不能进行赋值操作 最终的函数返回值为NULL 即没有拾取到参数
|
|||
|
*/
|
|||
|
if (optarg != NULL) out_opt = optarg;
|
|||
|
else out_opt = noarg_return_;
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (curr == '?')
|
|||
|
{
|
|||
|
err_str = "Invalid option found and returned NULL. From flags_parser::get_arg(...)";
|
|||
|
GCTL_ShowWhatError(err_str, GCTL_ERROR_ERROR, 0, 0, 0);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return out_opt;
|
|||
|
}
|
|||
|
|
|||
|
std::string gctl::flags_parser::get_arg(const char* f_name)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
{
|
|||
|
err_str = "flags_parser is not configured. From flags_parser::get_arg(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
int s_name = '?';
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
if (!strcmp(f_name, rec_opts_[i].name))
|
|||
|
{
|
|||
|
s_name = rec_opts_[i].val;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (s_name == '?')
|
|||
|
{
|
|||
|
err_str = "Option --";
|
|||
|
err_str += f_name;
|
|||
|
err_str += " is not registered. From flags_parser::get_arg(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
return get_arg(s_name);
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::get_argv(std::initializer_list<char> tar_val, std::initializer_list<std::string*> ret_str)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
{
|
|||
|
err_str = "flags_parser is not configured. From flags_parser::get_argv(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
if (tar_val.size() != ret_str.size())
|
|||
|
{
|
|||
|
err_str = "target and result sizes don't match. From flags_parser::get_argv(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
// 下面这段检查是针对程序编写中的可能出现的错误调用
|
|||
|
bool registered, no_arg;
|
|||
|
std::initializer_list<char>::iterator icl;
|
|||
|
std::initializer_list<std::string*>::iterator isl;
|
|||
|
|
|||
|
char s_name;
|
|||
|
for (icl = tar_val.begin(); icl != tar_val.end(); ++icl)
|
|||
|
{
|
|||
|
s_name = *icl;
|
|||
|
registered = false;
|
|||
|
no_arg = true;
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
if (s_name == rec_opts_[i].val)
|
|||
|
{
|
|||
|
registered = true;
|
|||
|
if (rec_opts_[i].has_arg != 0) no_arg = false;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!registered)
|
|||
|
{
|
|||
|
err_str = "Option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " is not registered. From flags_parser::get_argv(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
if (no_arg)
|
|||
|
{
|
|||
|
err_str = "Option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " has no argument. From flags_parser::get_argv(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (isl = ret_str.begin(); isl != ret_str.end(); ++isl)
|
|||
|
{
|
|||
|
(*isl)->assign(nofound_return_);
|
|||
|
}
|
|||
|
|
|||
|
// 下面是检查命令行参数拾取中的可能出现的错误输入
|
|||
|
bool is_manda, end_analysis = false;
|
|||
|
|
|||
|
isl = ret_str.begin();
|
|||
|
for (icl = tar_val.begin(); icl != tar_val.end(); ++icl)
|
|||
|
{
|
|||
|
s_name = *icl;
|
|||
|
is_manda = false;
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
if (s_name == rec_opts_[i].val)
|
|||
|
{
|
|||
|
if (rec_info_[i].manda) is_manda = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
optind = 0; // 重置已分析参数个数 再从头分析一遍
|
|||
|
while (1)
|
|||
|
{
|
|||
|
int optIndex = 0;
|
|||
|
int curr = getopt_long(argc_, argv_, arg_format_.c_str(), rec_opts_.data(), &optIndex);
|
|||
|
if (curr == -1 && is_manda)
|
|||
|
{
|
|||
|
err_str = "Mandatory option -";
|
|||
|
err_str += (char) s_name;
|
|||
|
err_str += " is not found and returned NULL. From flags_parser::get_argv(...)";
|
|||
|
GCTL_ShowWhatError(err_str, GCTL_ERROR_ERROR, 0, 0, 0);
|
|||
|
show_option_info(s_name);
|
|||
|
failed_mandatory_ = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (curr == -1) break;
|
|||
|
|
|||
|
if (curr == s_name)
|
|||
|
{
|
|||
|
/**
|
|||
|
* 注意 如果s_name对应的选项的参数是可选的(optional_argument) 则其在调用get_arg()时可能没有参数
|
|||
|
* 此时optarg2将指向一个空指针 不能进行赋值操作 最终的函数返回值为NULL 即没有拾取到参数
|
|||
|
*/
|
|||
|
if (optarg != NULL) (*isl)->assign(optarg);
|
|||
|
else (*isl)->assign(noarg_return_);
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (curr == '?')
|
|||
|
{
|
|||
|
err_str = "Invalid option found and returned NULL. From flags_parser::get_argv(...)";
|
|||
|
GCTL_ShowWhatError(err_str, GCTL_ERROR_ERROR, 0, 0, 0);
|
|||
|
end_analysis = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
isl++;
|
|||
|
if (end_analysis) break;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::show_help_page(std::ostream& sout, std::string extra_usage)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
{
|
|||
|
err_str = "flags_parser is not configured. From flags_parser::show_help_page(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
gctl::display_logo(sout);
|
|||
|
gctl::getopt_long_help(rec_opts_.data(), rec_info_.data(), pro_name_.c_str(), pro_info_.c_str(), sout, extra_usage);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::show_option_info(int s_name, std::ostream& sout)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
{
|
|||
|
err_str = "flags_parser is not configured. From flags_parser::show_option_info(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
gctl::getopt_long_option_info(s_name, rec_opts_.data(), rec_info_.data(), sout);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::show_option_info(const char* f_name, std::ostream& sout)
|
|||
|
{
|
|||
|
std::string err_str;
|
|||
|
if (!configured_)
|
|||
|
{
|
|||
|
err_str = "flags_parser is not configured. From flags_parser::show_option_info(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
int s_name = '?';
|
|||
|
for (int i = 0; i < rec_opts_.size()-1; i++)
|
|||
|
{
|
|||
|
if (!strcmp(f_name, rec_opts_[i].name))
|
|||
|
{
|
|||
|
s_name = rec_opts_[i].val;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (s_name == '?')
|
|||
|
{
|
|||
|
err_str = "Option --";
|
|||
|
err_str += f_name;
|
|||
|
err_str += " is not registered. From flags_parser::show_option_info(...)";
|
|||
|
throw err_str;
|
|||
|
}
|
|||
|
|
|||
|
gctl::getopt_long_option_info(s_name, rec_opts_.data(), rec_info_.data(), sout);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::set_proname(const char* proname)
|
|||
|
{
|
|||
|
pro_name_ = proname;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::set_proinfo(const char* proinfo)
|
|||
|
{
|
|||
|
pro_info_ = proinfo;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::set_nofound_return(std::string in_str)
|
|||
|
{
|
|||
|
nofound_return_ = in_str;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::set_noarg_return(std::string in_str)
|
|||
|
{
|
|||
|
noarg_return_ = in_str;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
void gctl::flags_parser::show_arg_format(std::ostream& sout)
|
|||
|
{
|
|||
|
sout << arg_format_ << std::endl;
|
|||
|
return;
|
|||
|
}
|