blob: 53a8c80de8c9186315eb512c7542a90b3bb3ebb4 [file] [log] [blame]
/**
* @file popt_options.cpp
* option parsing
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Philippe Elie
* @author John Levon
*/
#include <iostream>
#include "op_popt.h"
#include "op_version.h"
#include "popt_options.h"
#include "string_manip.h"
using namespace std;
namespace popt {
/**
* option_base - base class for implementation of a command line option
*
* Every command line option added before calling parse_options()
* is of this type.
*/
class option_base {
public:
/**
* option_base - construct an option with the given options.
* @param option_name name part of long form e.g. --option
* @param short_name short form name e.g. -o
* @param help_str short description of the option
* @param arg_help_str short description of the argument (if any)
* @param data a pointer to the data to fill in
* @param popt_flags the popt library data type
*/
option_base(char const * option_name, char short_name,
char const * help_str, char const * arg_help_str,
void * data, int popt_flags);
virtual ~option_base() {}
/**
* post_process - perform any necessary post-processing
*/
virtual void post_process() {}
protected:
char const * option_name;
};
/** the popt array singleton options */
static vector<poptOption> & popt_options(void)
{
static vector<poptOption> *x = new(vector<poptOption>);
return *x;
}
static vector<option_base *> & options_list(void)
{
static vector<option_base *> *x = new(vector<option_base *>);
return *x;
}
static int showvers;
static struct poptOption appended_options[] = {
{ "version", 'v', POPT_ARG_NONE, &showvers, 0, "show version", NULL, },
POPT_AUTOHELP
POPT_TABLEEND
};
/* options parameter can't be a local variable because caller can use the
* returned poptContext which contains pointer inside the options array */
static poptContext do_parse_options(int argc, char const ** argv,
vector<poptOption> & options,
vector<string> & additional_params)
{
options = popt_options();
int const nr_appended_options =
sizeof(appended_options) / sizeof(appended_options[0]);
options.insert(options.end(), appended_options,
appended_options + nr_appended_options);
poptContext con = op_poptGetContext(NULL, argc, argv, &options[0], 0);
if (showvers)
show_version(argv[0]);
char const * file;
while ((file = poptGetArg(con)) != 0)
additional_params.push_back(file);
for (size_t i = 0 ; i < options_list().size() ; ++i)
options_list()[i]->post_process();
return con;
}
void parse_options(int argc, char const ** argv,
vector<string> & additional_params)
{
vector<poptOption> options;
poptContext con =
do_parse_options(argc, argv, options, additional_params);
poptFreeContext(con);
}
template <typename T> class option_imp;
/**
* option<void> - a binary option
*
* Use this option type for constructing specified / not-specified
* options e.g. --frob
*/
template <> class option_imp<void> : public option_base {
public:
option_imp(bool & value, char const * option_name, char short_name,
char const * help_str);
~option_imp() {}
void post_process();
private:
bool & value;
int popt_value;
};
/**
* option<int> - a integer option
*
* Use this for options taking an integer e.g. --frob 6
*/
template <> class option_imp<int> : public option_base {
public:
option_imp(int & value, char const * option_name, char short_name,
char const * help_str, char const * arg_help_str);
~option_imp() {}
};
/**
* option<string> - a string option
*
* Use this for options taking a string e.g. --frob parsley
*/
template <> class option_imp<string> : public option_base {
public:
option_imp(string & value, char const * option_name,
char short_name, char const * help_str,
char const * arg_help_str);
void post_process();
~option_imp() {}
private:
// we need an intermediate char array to pass to popt libs
char * popt_value;
string & value;
};
/**
* option< vector<string> > - a string vector option
*
* Use this for options taking a number of string arguments,
* separated by the given separator.
*/
template <> class option_imp< vector<string> > : public option_base {
public:
option_imp(vector<string> & value,
char const * option_name, char short_name,
char const * help_str, char const * arg_help_str,
char separator = ',');
void post_process();
~option_imp() {}
private:
vector<string> & value;
// we need an intermediate char array to pass to popt libs
char * popt_value;
char const separator;
};
option::~option()
{
delete the_option;
}
/// non templatized ctor for boolean option
option::option(bool & value, char const * name, char short_name, char const * help)
: the_option(new option_imp<void>(value, name, short_name, help))
{
}
/// specialization of option ctor for integer option
template <>
option::option(int & value, char const * name, char short_name,
char const * help, char const * arg_help)
: the_option(new option_imp<int>
(value, name, short_name, help, arg_help))
{
}
/// specialization of option ctor for string option
template <>
option::option(string & value, char const * name, char short_name,
char const * help, char const * arg_help)
: the_option(new option_imp<string>
(value, name, short_name, help, arg_help))
{
}
/// specialization of option ctor for vector<string> option
template <>
option::option(vector<string> & value, char const * name, char short_name,
char const * help, char const * arg_help)
: the_option(new option_imp< vector<string> >
(value, name, short_name, help, arg_help))
{
}
option_base::option_base(char const * name, char short_name,
char const * help, char const * arg_help,
void * data, int popt_flags)
: option_name(name)
{
poptOption const opt = { name, short_name, popt_flags,
data, 0, help, arg_help };
popt_options().push_back(opt);
options_list().push_back(this);
}
option_imp<void>::option_imp(bool & val, char const * name, char short_name,
char const * help)
: option_base(name, short_name, help, 0, &popt_value, POPT_ARG_NONE),
value(val), popt_value(0)
{
}
void option_imp<void>::post_process()
{
if (popt_value) {
if (is_prefix(option_name, "no-"))
value = !popt_value;
else
value = popt_value;
}
}
option_imp<int>::option_imp(int & value, char const * name, char short_name,
char const * help, char const * arg_help)
: option_base(name, short_name, help, arg_help, &value, POPT_ARG_INT)
{
}
option_imp<string>::option_imp(string & val, char const * name, char short_name,
char const * help, char const * arg_help)
: option_base(name, short_name, help, arg_help,
&popt_value, POPT_ARG_STRING),
popt_value(0), value(val)
{
}
void option_imp<string>::post_process()
{
if (popt_value) {
value = popt_value;
popt_value = 0;
}
}
option_imp< vector<string> >::option_imp(vector<string> & val,
char const * name, char short_name,
char const * help,
char const * arg_help, char sepchar)
: option_base(name, short_name, help, arg_help,
&popt_value, POPT_ARG_STRING),
value(val), popt_value(0), separator(sepchar)
{
}
void option_imp< vector<string> >::post_process()
{
if (popt_value) {
value = separate_token(popt_value, separator);
popt_value = 0;
}
}
} // namespace popt