mirror of https://github.com/hmatuschek/libsdr
Added some comments.
parent
b18da61188
commit
e6a9aa6c02
@ -0,0 +1,208 @@
|
||||
#include "options.hh"
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace sdr;
|
||||
|
||||
|
||||
/* ********************************************************************************************* *
|
||||
* Implementation of Options
|
||||
* ********************************************************************************************* */
|
||||
Options::Options()
|
||||
: _options()
|
||||
{
|
||||
// pass...
|
||||
}
|
||||
|
||||
bool
|
||||
Options::has(const char *name) {
|
||||
return _options.end() != _options.find(name);
|
||||
}
|
||||
|
||||
const Options::Value &
|
||||
Options::get(const char *name) {
|
||||
return _options[name];
|
||||
}
|
||||
|
||||
bool
|
||||
Options::parse(const Definition defs[], int argc, char *argv[], Options &options)
|
||||
{
|
||||
// Get number of definitions
|
||||
const Definition *def = defs;
|
||||
int nopts = 0;
|
||||
while (def->name) { nopts++; def++; }
|
||||
|
||||
struct option *getopt_options = (struct option *)malloc((nopts+1)*sizeof(struct option));
|
||||
std::map<std::string, Definition> long_options;
|
||||
std::map<char, Definition> short_options;
|
||||
|
||||
def = defs; struct option *getopt_opt = getopt_options;
|
||||
std::string short_opt_str;
|
||||
for (int i=0; i<nopts; i++, def++, getopt_opt++) {
|
||||
getopt_opt->name = def->name;
|
||||
if (FLAG == def->type) { getopt_opt->has_arg = no_argument; }
|
||||
else { getopt_opt->has_arg = required_argument; }
|
||||
getopt_opt->flag = 0;
|
||||
getopt_opt->val = def->short_name;
|
||||
long_options[def->name] = *def;
|
||||
if (def->short_name) {
|
||||
short_options[def->short_name] = *def;
|
||||
short_opt_str += def->short_name;
|
||||
if (FLAG != def->type) { short_opt_str += ':'; }
|
||||
}
|
||||
}
|
||||
// add sentinel
|
||||
getopt_opt->name = 0; getopt_opt->has_arg = 0; getopt_opt->flag = 0; getopt_opt->val = 0;
|
||||
|
||||
// Parse options using getopt
|
||||
while (true) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, short_opt_str.c_str(), getopt_options, &option_index);
|
||||
if (-1 == c) { break; }
|
||||
|
||||
// Handle long option:
|
||||
if (0 == c) {
|
||||
const char *name = getopt_options[option_index].name;
|
||||
if (long_options.end() == long_options.find(name)) {
|
||||
free(getopt_options);
|
||||
return false;
|
||||
}
|
||||
const Definition &opt = long_options[name];
|
||||
if (FLAG == opt.type) { options._options[name] = Value(); }
|
||||
else if (INTEGER == opt.type) { options._options[name] = atol(optarg); }
|
||||
else if (FLOAT == opt.type) { options._options[name] = atof(optarg); }
|
||||
else if (ANY == opt.type) { options._options[name] = Value(optarg); }
|
||||
} else {
|
||||
if (short_options.end() == short_options.find(c)) {
|
||||
free(getopt_options);
|
||||
return false;
|
||||
}
|
||||
const Definition &opt = short_options[c];
|
||||
const char *name = opt.name;
|
||||
if (FLAG == opt.type) { options._options[name] = Value(); }
|
||||
else if (INTEGER == opt.type) { options._options[name] = atol(optarg); }
|
||||
else if (FLOAT == opt.type) { options._options[name] = atof(optarg); }
|
||||
else if (ANY == opt.type) { options._options[name] = Value(optarg); }
|
||||
}
|
||||
}
|
||||
|
||||
free(getopt_options);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Options::print_help(std::ostream &stream, const Definition defs[])
|
||||
{
|
||||
for (const Definition *def = defs; def->name; def++) {
|
||||
stream << "--" << def->name;
|
||||
if (def->short_name) { stream << ", -" << def->short_name; }
|
||||
if (INTEGER == def->type) { stream << " INTEGER"; }
|
||||
else if (FLOAT == def->type) { stream << " FLOAT"; }
|
||||
else if (ANY == def->type) { stream << " VALUE"; }
|
||||
stream << std::endl;
|
||||
if (def->help) {
|
||||
std::istringstream iss(def->help);
|
||||
std::string line(" ");
|
||||
do {
|
||||
std::string word; iss >> word;
|
||||
if ((line.length()+word.length()) > 78) {
|
||||
stream << line << std::endl;
|
||||
line = " ";
|
||||
}
|
||||
line += word + " ";
|
||||
} while (iss);
|
||||
if (! line.empty()) { stream << line << std::endl; }
|
||||
}
|
||||
stream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ********************************************************************************************* *
|
||||
* Implementation of Value
|
||||
* ********************************************************************************************* */
|
||||
Options::Value::Value()
|
||||
: _type(NONE)
|
||||
{
|
||||
// pass...
|
||||
}
|
||||
|
||||
Options::Value::Value(long value)
|
||||
: _type(INTEGER)
|
||||
{
|
||||
_value.as_int = value;
|
||||
}
|
||||
|
||||
Options::Value::Value(double value)
|
||||
: _type(FLOAT)
|
||||
{
|
||||
_value.as_float = value;
|
||||
}
|
||||
|
||||
Options::Value::Value(const std::string &value)
|
||||
: _type(STRING)
|
||||
{
|
||||
_value.as_string = strdup(value.c_str());
|
||||
}
|
||||
|
||||
Options::Value::~Value() {
|
||||
if (STRING == _type) { free(_value.as_string); }
|
||||
}
|
||||
|
||||
Options::Value::Value(const Value &other)
|
||||
: _type(other._type), _value(other._value)
|
||||
{
|
||||
if (STRING == _type) { _value.as_string = strdup(_value.as_string); }
|
||||
}
|
||||
|
||||
const Options::Value &
|
||||
Options::Value::operator =(const Value &other) {
|
||||
if (STRING == _type) { free(_value.as_string); }
|
||||
_type = other._type;
|
||||
if (NONE == _type) { /* pass...*/ }
|
||||
else if (INTEGER == _type) { _value.as_int = other._value.as_int; }
|
||||
else if (FLOAT == _type) { _value.as_float = other._value.as_float; }
|
||||
else if (STRING == _type) { _value.as_string = strdup(other._value.as_string); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
Options::Value::isNone() const {
|
||||
return NONE == _type;
|
||||
}
|
||||
|
||||
bool
|
||||
Options::Value::isInteger() const {
|
||||
return INTEGER == _type;
|
||||
}
|
||||
|
||||
bool
|
||||
Options::Value::isFloat() const {
|
||||
return FLOAT == _type;
|
||||
}
|
||||
|
||||
bool
|
||||
Options::Value::isString() const {
|
||||
return STRING == _type;
|
||||
}
|
||||
|
||||
long
|
||||
Options::Value::toInteger() const {
|
||||
return _value.as_int;
|
||||
}
|
||||
|
||||
double
|
||||
Options::Value::toFloat() const {
|
||||
return _value.as_float;
|
||||
}
|
||||
|
||||
std::string
|
||||
Options::Value::toString() const {
|
||||
return _value.as_string;
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
#ifndef __SDR_OPTIONS_HH__
|
||||
#define __SDR_OPTIONS_HH__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace sdr {
|
||||
|
||||
/** Convenience functions for command line arguments. */
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
/** The argument value. */
|
||||
class Value {
|
||||
protected:
|
||||
/** Value type. */
|
||||
typedef enum {
|
||||
NONE, ///< Empty or invalid value.
|
||||
INTEGER, ///< An integer (long int).
|
||||
FLOAT, ///< A floating point number (double).
|
||||
STRING ///< An ASCII string.
|
||||
} Type;
|
||||
|
||||
public:
|
||||
/** Empty constructor. */
|
||||
Value();
|
||||
/** Integer constructor. */
|
||||
Value(long value);
|
||||
/** Floating point constructor. */
|
||||
Value(double value);
|
||||
/** String constructor. */
|
||||
Value(const std::string &value);
|
||||
/** Copy constructor. */
|
||||
Value(const Value &other);
|
||||
/** Destructor. */
|
||||
~Value();
|
||||
/** Assignment. */
|
||||
const Value &operator=(const Value &other);
|
||||
/** Returns @c true if the value is empty. */
|
||||
bool isNone() const;
|
||||
/** Returns @c true if the value is an integer. */
|
||||
bool isInteger() const;
|
||||
/** Returns @c true if the value is a floating point number. */
|
||||
bool isFloat() const;
|
||||
/** Returns @c true if the value is a string. */
|
||||
bool isString() const;
|
||||
/** Turns the value into an integer. */
|
||||
long toInteger() const;
|
||||
/** Turns the value into a floating point number. */
|
||||
double toFloat() const;
|
||||
/** Turns the value into a string. */
|
||||
std::string toString() const;
|
||||
|
||||
protected:
|
||||
/** The type of the value. */
|
||||
Type _type;
|
||||
/** Values. */
|
||||
union {
|
||||
long as_int;
|
||||
double as_float;
|
||||
char *as_string;
|
||||
} _value;
|
||||
};
|
||||
|
||||
/** Possible argument types. */
|
||||
typedef enum {
|
||||
FLAG, ///< No argument (flag).
|
||||
INTEGER, ///< Integer argument.
|
||||
FLOAT, ///< Floating point argument.
|
||||
ANY ///< Any argument (string).
|
||||
} ArgType;
|
||||
|
||||
/** Argument definition. */
|
||||
typedef struct {
|
||||
const char *name; ///< Argument name (long).
|
||||
char short_name; ///< Argument name (short).
|
||||
ArgType type; ///< Argument type.
|
||||
const char *help; ///< Help string.
|
||||
} Definition;
|
||||
|
||||
/** Parse the given arguments (@c argc, @c argv) using the definitions @c defs and stores
|
||||
* the results into @c options. Returns @c false on error. */
|
||||
static bool parse(const Definition defs[], int argc, char *argv[], Options &options);
|
||||
/** Serializes a help text derived from given the definitions into @c stream. */
|
||||
static void print_help(std::ostream &stream, const Definition defs[]);
|
||||
|
||||
public:
|
||||
/** Empty constructor. */
|
||||
Options();
|
||||
/** Returns @c true if the specified option was found (long name). */
|
||||
bool has(const char *name);
|
||||
/** Returns the argument of the specified option (long name). */
|
||||
const Value &get(const char *name);
|
||||
|
||||
protected:
|
||||
/** The table of option names and argument values. */
|
||||
std::map<std::string, Value> _options;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __SDR_OPTIONS_HH__
|
||||
Loading…
Reference in New Issue