pdf2htmlEX/src/ArgParser.cc

177 lines
4.5 KiB
C++
Raw Normal View History

2012-09-10 09:01:15 +00:00
/*
* A wrapper of getopt
*
* by WangLu
* 2012.09.10
*/
#include <iostream>
#include <unordered_map>
2012-09-10 14:22:01 +00:00
#include <cassert>
2012-09-10 09:01:15 +00:00
2013-04-07 06:12:43 +00:00
#include <getopt.h>
2012-09-10 09:01:15 +00:00
#include "ArgParser.h"
namespace pdf2htmlEX {
2012-09-10 09:01:15 +00:00
using std::ostream;
using std::cerr;
using std::endl;
using std::string;
using std::vector;
using std::unordered_map;
using std::make_pair;
using std::ostringstream;
2012-09-11 14:30:12 +00:00
bool read_value(const char * arg, char * location)
{
*location = arg[0];
return (arg[1] == 0);
}
bool read_value(const char * arg, std::string * location)
{
*location = std::string(arg);
2012-09-11 14:30:12 +00:00
return true;
}
void dump_value(std::ostream & out, const std::string & v)
{
out << '"' << v << '"';
}
ArgParser & ArgParser::add(const char * optname, const char * description, ArgParserCallBack callback, bool need_arg)
2012-09-10 09:01:15 +00:00
{
// ArgEntry does not accept nullptr as optname nor description
if((!optname) || (!optname[0]))
{
// when optname is nullptr or "", it's optional, and description is dropped
optional_arg_entries.emplace_back(new ArgEntry<string, string>("", "", callback, need_arg));
}
else
{
arg_entries.emplace_back(new ArgEntry<string, string>(optname, (description ? description : ""), callback, need_arg));
}
return *this;
2012-09-10 09:01:15 +00:00
}
void ArgParser::parse(int argc, char ** argv) const
{
//prepare optstring and longopts
vector<char> optstring;
2012-09-13 03:38:56 +00:00
optstring.reserve(2*arg_entries.size() + 1);
2012-09-10 09:01:15 +00:00
vector<struct option> longopts;
longopts.reserve(arg_entries.size() + 1);
unordered_map<int, const ArgEntryBase*> opt_map;
for(auto iter = arg_entries.begin(); iter != arg_entries.end(); ++iter)
{
2013-04-05 16:00:03 +00:00
const auto * p = iter->get();
2012-09-10 09:01:15 +00:00
if(p->shortname != 0)
{
optstring.push_back(p->shortname);
if(p->need_arg)
optstring.push_back(':');
int v = p->shortname;
if(!(opt_map.insert(make_pair(v, p)).second))
{
cerr << "Warning: duplicated shortname: " << v << endl;
2012-09-10 09:01:15 +00:00
}
}
if(p->name != "")
{
int v = (256 + (iter - arg_entries.begin()));
2012-09-10 17:53:33 +00:00
longopts.resize(longopts.size() + 1);
{
auto & cur = longopts.back();
cur.name = p->name.c_str();
cur.has_arg = ((p->need_arg) ? required_argument : no_argument);
cur.flag = nullptr;
cur.val = v;
}
2012-09-10 09:01:15 +00:00
if(!(opt_map.insert(make_pair(v, p)).second))
{
cerr << "Warning: duplicated long name: " << (p->name) << endl;
2012-09-10 09:01:15 +00:00
}
}
}
optstring.push_back(0);
2012-09-10 17:53:33 +00:00
longopts.resize(longopts.size() + 1);
{
2013-01-08 12:37:08 +00:00
auto & cur = longopts.back();
cur.name = 0;
cur.has_arg = 0;
cur.flag = 0;
cur.val = 0;
2012-09-10 17:53:33 +00:00
}
2012-09-10 09:01:15 +00:00
{
2012-09-10 14:44:19 +00:00
opterr = 1;
2012-09-10 09:01:15 +00:00
int r;
int idx;
while(true)
{
r = getopt_long(argc, argv, &optstring.front(), &longopts.front(), &idx);
if(r == -1)
2012-09-10 14:22:01 +00:00
break;
assert(r != ':');
if(r == '?')
2012-09-10 09:01:15 +00:00
{
2012-09-10 14:44:19 +00:00
throw "";
2012-09-10 09:01:15 +00:00
}
2012-09-10 14:22:01 +00:00
auto iter = opt_map.find(r);
assert(iter != opt_map.end());
iter->second->parse(optarg);
}
}
{
auto iter = optional_arg_entries.begin();
while((optind < argc) && (iter != optional_arg_entries.end()))
2012-09-10 14:22:01 +00:00
{
(*(iter++))->parse(argv[optind++]);
2012-09-10 09:01:15 +00:00
}
}
}
void ArgParser::show_usage(ostream & out) const
{
2014-11-16 14:04:02 +00:00
for(auto & entry : arg_entries)
2012-09-10 09:01:15 +00:00
{
2014-11-16 14:04:02 +00:00
entry->show_usage(out);
2012-09-10 09:01:15 +00:00
}
}
2013-01-29 18:48:05 +00:00
template<> const char * ArgParser::get_type_name<int> (void) { return "int"; }
template<> const char * ArgParser::get_type_name<double> (void) { return "fp"; }
template<> const char * ArgParser::get_type_name<string> (void) { return "string"; }
2012-09-10 09:01:15 +00:00
ArgParser::ArgEntryBase::ArgEntryBase(const char * name, const char * description, bool need_arg)
: shortname(0), name(name), description(description), need_arg(need_arg)
{
size_t idx = this->name.rfind(',');
if(idx != string::npos)
{
if(idx+2 == this->name.size())
{
shortname = this->name[this->name.size()-1];
this->name = this->name.substr(0, idx);
}
else
{
2014-07-13 23:59:30 +00:00
cerr << "Warning: argument '" << this->name << "' cannot be parsed as a short option" << endl;
2012-09-10 09:01:15 +00:00
}
}
}
const int ArgParser::arg_col_width = 31;
} // namespace pdf2htmlEX