mirror of
https://github.com/pdf2htmlEX/pdf2htmlEX.git
synced 2024-12-22 04:50:09 +00:00
177 lines
4.5 KiB
C++
177 lines
4.5 KiB
C++
/*
|
|
* A wrapper of getopt
|
|
*
|
|
* by WangLu
|
|
* 2012.09.10
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <unordered_map>
|
|
#include <cassert>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include "ArgParser.h"
|
|
|
|
namespace pdf2htmlEX {
|
|
|
|
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;
|
|
|
|
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);
|
|
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)
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
void ArgParser::parse(int argc, char ** argv) const
|
|
{
|
|
//prepare optstring and longopts
|
|
vector<char> optstring;
|
|
optstring.reserve(2*arg_entries.size() + 1);
|
|
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)
|
|
{
|
|
const auto * p = iter->get();
|
|
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;
|
|
}
|
|
}
|
|
|
|
if(p->name != "")
|
|
{
|
|
int v = (256 + (iter - arg_entries.begin()));
|
|
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;
|
|
}
|
|
if(!(opt_map.insert(make_pair(v, p)).second))
|
|
{
|
|
cerr << "Warning: duplicated long name: " << (p->name) << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
optstring.push_back(0);
|
|
longopts.resize(longopts.size() + 1);
|
|
{
|
|
auto & cur = longopts.back();
|
|
cur.name = 0;
|
|
cur.has_arg = 0;
|
|
cur.flag = 0;
|
|
cur.val = 0;
|
|
}
|
|
|
|
{
|
|
opterr = 1;
|
|
int r;
|
|
int idx;
|
|
while(true)
|
|
{
|
|
r = getopt_long(argc, argv, &optstring.front(), &longopts.front(), &idx);
|
|
if(r == -1)
|
|
break;
|
|
assert(r != ':');
|
|
if(r == '?')
|
|
{
|
|
throw "";
|
|
}
|
|
|
|
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()))
|
|
{
|
|
(*(iter++))->parse(argv[optind++]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ArgParser::show_usage(ostream & out) const
|
|
{
|
|
for(auto iter = arg_entries.begin(); iter != arg_entries.end(); ++iter)
|
|
{
|
|
(*iter)->show_usage(out);
|
|
}
|
|
}
|
|
|
|
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"; }
|
|
|
|
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
|
|
{
|
|
cerr << "Warning: argument '" << this->name << "' cannnot be parsed as a short option" << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
const int ArgParser::arg_col_width = 31;
|
|
|
|
} // namespace pdf2htmlEX
|