📄 args.cc
字号:
//
// args.cc
//
// $Id: args.cc,v 1.1.1.1 2001/02/28 00:28:35 cstolte Exp $
//
#include <iostream>
#include <sgl/args.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
/////////////////////////////////////////////////////////////////////////////
// Inside the argument parser, we keep a list of the arguments that the
// user has told us about--each one is recorded in an APItem in
// item_list. The "floating argument"--the optional string argument that
// isn't prefixed by any switch--is recorded separately. floating_arg
// holds a pointer to it, floating_name holds a description of what
// it is (for error messages), floating_required is true if it must be
// specified.
ArgParser::ArgParser() {
floating_arg = 0;
floating_name = 0;
floating_required = false;
floating_set = false;
item_list = 0;
}
ArgParser::~ArgParser() {
delete floating_name;
APItem *i = item_list;
while (i) {
APItem *next = i->next;
delete i;
i = next;
}
}
/////////////////////////////////////////////////////////////////////////////
// Here's where the floating argument is added to the arg parser's internal
// state.
void
ArgParser::operator()(char **fl, const char *float_name,
ArgRequired required) {
floating_arg = fl;
delete [] floating_name;
floating_name = new char[1 + strlen(float_name)];
strcpy(floating_name, float_name);
floating_required = required == Required ? true : false;
}
////////////////////////////////////////////////////////////////////////////
// And here's where all other types of arguments are added to item_list.
// operator() is overloaded based on the type of the argument that we're
// adding. By default, arguments aren't required, and only one value
// after a switch is used to intialize its argument.
void
ArgParser::operator()(char c, const char *str, int *i,
ArgRequired req, u_int num) {
APItem *item = new APItem;
item->c_switch = c;
item->str_switch = new char[1 + strlen(str)];
strcpy(item->str_switch, str);
item->num = num;
item->required = req == Required ? true : false;
item->initialized = false;
item->type = APItem::I;
item->i = i;
add_item_to_list(item);
}
void
ArgParser::operator()(char c, const char *str, double *d,
ArgRequired req, u_int num) {
APItem*item = new APItem;
item->c_switch = c;
item->str_switch = new char[1 + strlen(str)];
strcpy(item->str_switch, str);
item->num = num;
item->required = req == Required ? true : false;
item->initialized = false;
item->type = APItem::D;
item->d = d;
add_item_to_list(item);
}
void
ArgParser::operator()(char c, const char *str, u_int *ui,
ArgRequired req, u_int num) {
APItem *item = new APItem;
item->c_switch = c;
item->str_switch = new char[1 + strlen(str)];
strcpy(item->str_switch, str);
item->num = num;
item->required = req == Required ? true : false;
item->initialized = false;
item->type = APItem::UI;
item->ui = ui;
add_item_to_list(item);
}
void
ArgParser::operator()(char c, const char *str, char **s,
ArgRequired req, u_int num) {
APItem *item = new APItem;
item->c_switch = c;
item->str_switch = new char[1 + strlen(str)];
strcpy(item->str_switch, str);
item->num = num;
item->required = req == Required ? true : false;
item->initialized = false;
item->type = APItem::S;
item->s = s;
add_item_to_list(item);
}
/////////////////////////////////////////////////////////////////////////////
// Switches for booleans are a bit special, since no argument after them
// is looked at--each time a boolean's switch is found, it's just toggled.
// Thus, we don't need to worry about stuff like whether it's a
// required switch, or how many arguments after it to process.
void
ArgParser::operator()(char c, const char *str, bool *b) {
u_int num = 0;
bool req = false;
APItem *item = new APItem;
item->c_switch = c;
item->str_switch = new char[1 + strlen(str)];
strcpy(item->str_switch, str);
item->num = num;
item->required = req;
item->initialized = false;
item->type = APItem::B;
item->b = b;
add_item_to_list(item);
}
void
ArgParser::add_item_to_list(APItem *item) {
assert(item);
if(item->c_switch == 'h' || !strcmp(item->str_switch,"help")) {
std::cerr << "ArgParser: '-h' and '--help' are reserved for help!"
<< std::endl;
exit(1);
}
APItem *i = item_list;
while (i) {
if(i->c_switch == item->c_switch ||
!strcmp(i->str_switch, item->str_switch)) {
std::cerr << "ArgParser: switch '-" << i->c_switch << "' or '--"
<< i->str_switch << "' is already taken." << std::endl;
exit(1);
}
i = i->next;
}
item->next = item_list;
item_list = item;
}
void
ArgParser::process(const char *prog_name, int, char **argv) {
++argv;
while(*argv) {
if(*argv[0]!='-') {
if(!floating_arg || floating_set == true) {
std::cerr << prog_name << ": unknown argument " << argv[0]
<< std::endl;
}
else {
*floating_arg = new char[1 + strlen(*argv)];
strcpy(*floating_arg, *argv);
floating_set = true;
}
}
else {
if(argv[0][1] == '-') {
const char *long_switch = &argv[0][2];
if (!strcmp(long_switch, "help"))
print_help(prog_name);
else {
APItem *i = item_list;
while(i) {
if (!strcmp(i->str_switch, long_switch)) {
if(i->type == APItem::B) {
if(*i->b == false)
*i->b = true;
else
*i->b = false;
break;
}
else {
i->initialized = true;
for(u_int k = 0; k < i->num; ++k) {
++argv;
if(!*argv) {
std::cerr << prog_name <<
": not enough arguments for "
<< i->str_switch << " switch."
<< std::endl;
exit(1);
}
switch(i->type) {
case APItem::I:
i->i[k] = atoi(*argv);
break;
case APItem::UI:
i->ui[k] = atoi(*argv);
break;
case APItem::D:
i->d[k] = atof(*argv);
break;
case APItem::S:
if (i->s[k])
delete[] i->s[k];
i->s[k] = new char[1 + strlen(*argv)];
strcpy(i->s[k], *argv);
break;
default:
break;
}
}
}
break;
}
i = i->next;
}
if(!i) {
std::cerr << prog_name << ": unknown switch '--" <<
long_switch << "'" << std::endl;
}
}
}
else {
char short_switch = argv[0][1];
if(short_switch =='h')
print_help(prog_name);
else {
APItem *i = item_list;
while(i) {
if(i->c_switch == short_switch) {
if(i->type == APItem::B) {
if(*i->b == false)
*i->b = true;
else
*i->b = false;
break;
}
else {
i->initialized = true;
for(u_int k = 0; k< i->num; ++k) {
++argv;
if(!*argv) {
std::cerr << prog_name <<
": not enough arguments for "
<< i->str_switch << " switch."
<< std::endl;
exit(1);
}
switch(i->type) {
case APItem::I:
i->i[k] = atoi(*argv);
break;
case APItem::UI:
i->ui[k] = atoi(*argv);
break;
case APItem::D:
i->d[k] = atof(*argv);
break;
case APItem::S:
if (i->s[k])
delete[] i->s[k];
i->s[k] = new char[1 + strlen(*argv)];
strcpy(i->s[k], *argv);
break;
default:
break;
}
}
}
break;
}
i = i->next;
}
if(!i) {
std::cerr << prog_name << ": unknown switch '-" <<
short_switch << "'" << std::endl;
}
}
}
}
++argv;
}
bool missing_some = false;
if(floating_required == true) {
assert(floating_arg);
if(!*floating_arg) {
std::cerr << prog_name << ": " << floating_name <<
" must be specified." <<std::endl;
missing_some = true;
}
}
APItem *i = item_list;
while(i) {
if(i->required == true && i->initialized == false) {
missing_some = true;
std::cerr << prog_name << ": " << i->str_switch <<
" argument must be specified." << std::endl;
}
i = i->next;
}
if(missing_some == true) {
print_help(prog_name);
exit(1);
}
#ifdef DEBUG
print_values_of_all_switches();
#endif /* DEBUG */
}
void
ArgParser::print_help(const char *prog_name) const {
std::cerr << "usage: " << prog_name << " [-h] [--help] ";
if (floating_arg)
std::cerr << "[" << floating_name << "] ";
APItem *i = item_list;
while(i) {
std::cerr << "[-" << i->c_switch;
print_args_for_item(std::cerr, i);
std::cerr << "] [--" << i->str_switch;
print_args_for_item(std::cerr, i);
std::cerr << "] ";
i = i->next;
}
std::cerr << std::endl;
exit(0);
}
void ArgParser::print_args_for_item(std::ostream &os,APItem *item) const {
if (item->type == APItem::B)
return;
for(u_int i = 0; i < item->num; ++i) {
switch(item->type) {
case APItem::I:
os<<" int";
break;
case APItem::UI:
os<<" u_int";
break;
case APItem::D:
os<<" double";
break;
case APItem::S:
os<<" str";
break;
default:
break;
}
}
}
void
ArgParser::print_values_of_all_switches() const {
if (floating_arg)
std::cerr << floating_name << " = " << *floating_arg << std::endl;
APItem *i = item_list;
while(i) {
std::cerr << i->str_switch << " = ";
for(u_int u = 0; u < i->num; ++u) {
switch(i->type) {
case APItem::B:
if(*i->b)
std::cerr << "true";
else
std::cerr << "false";
break;
case APItem::I:
std::cerr << i->i[u];
break;
case APItem::UI:
std::cerr << i->ui[u];
break;
case APItem::D:
std::cerr << i->d[u];
break;
case APItem::S:
std::cerr << i->s[u];
break;
}
std::cerr << ' ';
}
std::cerr << std::endl;
i = i->next;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -