Loading...
Searching...
No Matches
CmdLineOpts.cpp
Go to the documentation of this file.
// -*- c++ -*-
//------------------------------------------------------------------------------
// $Id: CmdLineOpts.cpp,v 1.7 2007/05/14 19:19:50 vlg Exp $
//------------------------------------------------------------------------------
// CmdLineOpts.cpp
//------------------------------------------------------------------------------
// Copyright (C) 2000,2005,2007 Vladislav Grinchenko
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//------------------------------------------------------------------------------
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sstream>
#include <iomanip>
#include "assa/Logger.h"
#include "assa/CmdLineOpts.h"
#include "assa/CommonUtils.h"
#include "assa/IniFile.h"
using namespace ASSA;
void
Option::
dump () const
{
std::ostringstream msg;
if (m_short_name != 0) {
msg << "-" << m_short_name << ", ";
}
else {
msg << " ";
}
if (m_long_name.size ()) {
msg << "--" << std::setiosflags (std::ios::left)
<< std::setw(14) << m_long_name.c_str () << ' ';
}
else {
msg << std::setiosflags (std::ios::left) << std::setw (14) << " ";
}
msg << '[';
switch (m_type)
{
case Option::string_t:
msg << std::setiosflags (std::ios::left) << std::setw(7) << "string";
msg << "] = '" << *(string*) m_val << "'";
break;
case Option::int_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "int";
msg << "] = " << *(int*) m_val;
break;
case Option::uint_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_int";
msg << "] = " << *(int*) m_val;
break;
case Option::long_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "long";
msg << "] = " << *(long*) m_val;
break;
case Option::ulong_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_long";
msg << "] = " << *(long*) m_val;
break;
case Option::double_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "double";
msg << "] = " << *(double*) m_val;
break;
case Option::float_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "float";
msg << "] = " << *(float*) m_val;
break;
case Option::flag_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "bool";
msg << "] = " << *(bool*) m_val ? "true" : "false";
break;
case Option::func_t:
msg << std::setiosflags(std::ios::left)
<< std::setw(7) << "function ()";
msg << ']';
break;
case Option::func_one_t:
msg << std::setiosflags(std::ios::left)
<< std::setw(7) << "function (opt)";
msg << ']';
break;
case Option::none_t:
msg << std::setiosflags(std::ios::left) << std::setw(7) << "none";
msg << ']';
break;
default:
msg << std::setiosflags(std::ios::left)
<< std::setw(7) << "--undef--";
msg << ']';
}
msg << std::ends;
DL((CMDLINEOPTS,"%s\n", msg.str ().c_str ()));
}
const char*
Option::
type_c_str ()
{
const char* ret;
switch (m_type)
{
case Option::string_t: ret = "string"; break;
case Option::int_t: ret = "int"; break;
case Option::uint_t: ret = "u_int"; break;
case Option::long_t: ret = "long"; break;
case Option::ulong_t: ret = "u_long"; break;
case Option::double_t: ret = "double"; break;
case Option::float_t: ret = "float"; break;
case Option::flag_t: ret = "bool"; break;
case Option::func_t: ret = "func()"; break;
case Option::func_one_t: ret = "func(opt)"; break;
case Option::none_t: ret = "none"; break;
default: ret = "--undef--";
}
return (ret);
}
/*----------------------------------------------------------------------------*/
bool
CmdLineOpts::
is_valid (const char sopt_, const string& lopt_)
{
trace_with_mask ("CmdLineOpts::is_valid", CMDLINEOPTS);
set_error_none ();
OptionSet::const_iterator i;
for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
if (sopt_ == '\0' && lopt_.empty ()) {
m_error = "Ignore empty option";
return (false);
}
else if (sopt_ != '\0' && i->m_short_name == sopt_) {
m_error = "Ignored multiple option '-";
m_error += sopt_ + string ("'");
return (false);
}
else if (!lopt_.empty () && i->m_long_name == lopt_) {
m_error = "Ignore multiple option '--";
m_error += lopt_ + string ("'");
return (false);
}
}
return (true);
}
Option*
CmdLineOpts::
find_option (const char* str_)
{
trace_with_mask ("CmdLineOpts::find_option(char*)", CMDLINEOPTS);
OptionSet::iterator i;
for ( i = m_opts_set.begin (); i != m_opts_set.end (); i++)
{
if (i->m_long_name == str_) {
return &(*i);
}
}
return (NULL);
}
Option*
CmdLineOpts::
find_option (const char letter_)
{
trace_with_mask ("CmdLineOpts::find_option(char)", CMDLINEOPTS);
OptionSet::iterator i;
for (i = m_opts_set.begin (); i != m_opts_set.end (); i++)
{
if (i->m_short_name == letter_)
return &(*i);
}
return (NULL);
}
bool
CmdLineOpts::
add_flag_opt (const char sopt_, const string& lopt_, bool* v_)
{
trace_with_mask ("CmdLineOpts::add_flag_opt", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_))
return (false);
Option o (sopt_, lopt_, Option::flag_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, string* v_)
{
trace_with_mask ("CmdLineOpts::add_opt(string*)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_))
return (false);
Option o (sopt_, lopt_, Option::string_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, int* v_)
{
trace_with_mask ("CmdLineOpts::add_opt(int*)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::int_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, unsigned int* v_)
{
trace_with_mask ("CmdLineOpts::add_opt(u_int*)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::uint_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, long* v_)
{
trace_with_mask ("CmdLineOpts::add_opt(long*)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::long_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, unsigned long* v_)
{
trace_with_mask ("CmdLineOpts::add_opt(u_long*)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::long_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, double* v_)
{
trace_with_mask ("CmdLineOpts::add_opt(double*)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::double_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, float* v_)
{
trace_with_mask ("CmdLineOpts::add_opt(float*)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::float_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, OPTS_FUNC v_)
{
trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::func_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
add_opt (const char sopt_, const string& lopt_, OPTS_FUNC_ONE v_)
{
trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC_ONE)", CMDLINEOPTS);
if (!is_valid (sopt_, lopt_)) {
return (false);
}
Option o (sopt_, lopt_, Option::func_one_t, (void*) v_);
m_opts_set.push_back (o);
return (true);
}
bool
CmdLineOpts::
rm_opt (const char sopt_, const string& lopt_)
{
trace_with_mask ("CmdLineOpts::rm_opt(string&)", CMDLINEOPTS);
OptionSet::iterator i;
for (i = m_opts_set.begin (); i != m_opts_set.end (); i++)
{
if (i->m_short_name == sopt_ || i->m_long_name == lopt_)
{
m_opts_set.erase (i);
return (true);
}
}
return (false);
}
bool
CmdLineOpts::
parse_args (const char* argv_[])
{
trace_with_mask ("CmdLineOpts::parse_args", CMDLINEOPTS);
register int skip = 1;
bool pos_args_started = false;
string param ("");
string token ("");
set_error_none ();
Option* node = (Option*) NULL;
for (argv_++; argv_[0]; argv_ += skip) {
if (skip != 0) {
token = argv_[0];
}
DL((CMDLINEOPTS, "token: \"%s\"\n", token.c_str()));
if (pos_args_started) {
DL((CMDLINEOPTS,"pos_args_started = true\n"));
if (token[0] == '-' && token.size () != 1) {
m_error = "Invalid order of arguments: '";
m_error += token + "'.";
goto done;
}
pos_arg (token.c_str ());
continue;
}
skip = 1;
if (token[0] == '-' && token.size () > 1 && token[1] != '-') {
if (token.size () == 1 && !pos_args_started) {
pos_arg (token.c_str ());
pos_args_started = true;
continue;
}
if ((node = find_option (token[1])) != NULL) {
if (token.size () > 2) {
if (node->m_type == Option::flag_t ||
node->m_type == Option::func_t)
{
token.erase (1, 1);
skip = 0;
}
else {
param = token.substr (2);
}
} // if (token.size()>2)
} // if ((node = find_option ())
}
else {
if (token.size () > 1 && token[1] == '-') {
string op = token.substr (2);
size_t pos;
if ((pos = op.find ("=")) != (size_t)-1) {
param = op.substr (pos+1, op.length ());
op.replace (pos, op.length() - pos, "");
}
node = find_option (op.c_str ());
}
else {
pos_arg (token.c_str ());
pos_args_started = true;
continue;
}
} // if (token[0] == '-' && token[1] != '-')
if (!node) {
m_error = "Invalid option '" + token + "'.";
goto done;
}
if (node->m_type != Option::flag_t &&
node->m_type != Option::func_t)
{
if (param.empty ()) {
if (!argv_[1]) {
m_error = "Expecting parameter after '"
+ string (argv_[0]) + "'.";
goto done;
}
param = argv_[1];
skip = 2;
}
}
/*---
* if positional arguments only
---*/
if (!node) {
goto done;
}
if (param.empty ()) {
if (!assign (node, argv_[1])) {
return (false);
}
}
else {
const char* str = param.c_str ();
if (!assign (node, str)) {
return (false);
}
param = "";
}
} // for (argv_++; argv_[0]; argv_ += skip)
done:
return !m_error.empty () ? false : true;
}
int
CmdLineOpts::
parse_config_file (IniFile& inifile_)
{
trace_with_mask ("CmdLineOpts::parse_config_file", CMDLINEOPTS);
unsigned int count = 0;
string v;
string s;
string optsect_name ("options");
OptionSet::iterator pos = m_opts_set.begin ();
if (inifile_.find_section (optsect_name) == inifile_.sect_end ())
{
optsect_name = "Options";
if (inifile_.find_section (optsect_name) == inifile_.sect_end ())
{
optsect_name = "OPTIONS";
if (inifile_.find_section (optsect_name) == inifile_.sect_end ())
{
m_error = "Missing [options] section in INI file!";
return -1;
}
}
}
while (pos != m_opts_set.end ()) {
if (pos->m_long_name.size ()) {
s = pos->m_long_name;
ASSA::Utils::find_and_replace_char (s, '-', '_');
DL ((CMDLINEOPTS, "trying option \"%s\"\n", s.c_str ()));
v = inifile_.get_value (optsect_name, s);
if (v.size ()) {
if (assign (&(*pos), v.c_str ())) {
count++;
}
}
}
pos++;
}
return (count);
}
bool
CmdLineOpts::
assign (Option* node_, const char* op_)
{
trace_with_mask ("CmdLineOpts::assign", CMDLINEOPTS);
long l;
double d;
if (node_ && op_) {
DL ((CMDLINEOPTS, "Assign '%s' to {-%c, --%s, t=%s}\n",
op_, node_->m_short_name, node_->m_long_name.c_str (),
node_->type_c_str ()));
}
/*---
From strtol(3C) man page:
"Because 0 is returned on error and is also a valid return on
success, an application wishing to check for error situations
should set 'errno' to 0, then call strtol(3C), then check 'errno'
and if it is non-zero, assume an error has occured."
---*/
switch (node_->m_type) {
case Option::string_t:
*(string*) node_->m_val = op_;
break;
case Option::int_t:
case Option::long_t:
errno = 0;
l = strtol (op_, NULL, 0);
if (errno != 0) {
m_error = "Error: '" + string (strerror (errno)) + "',";
m_error += " in converting to integer from '";
m_error += string (op_) + "'.";
return (false);
}
if (node_->m_type == Option::int_t) {
*(int*) node_->m_val = int (l);
}
else {
*(long*) node_->m_val = l;
}
break;
case Option::uint_t:
case Option::ulong_t:
errno = 0;
l = strtol (op_, NULL, 0);
if (errno != 0) {
m_error = "Error: '" + string (strerror (errno)) + "',";
m_error += " in converting to unsigned integer from '";
m_error += string (op_) + "'.";
return (false);
}
if (node_->m_type == Option::uint_t) {
*(unsigned int*) node_->m_val = int (l);
}
else {
*(unsigned long*) node_->m_val = l;
}
break;
case Option::double_t:
case Option::float_t:
errno = 0;
d = strtod (op_, NULL);
if (errno != 0) {
m_error = "Error: '" + string (strerror (errno)) + "',";
m_error += " in converting to double/float from '";
m_error += string (op_) + "'.";
return (false);
}
if (node_->m_type == Option::double_t) {
*(double*) node_->m_val = d;
}
else {
*(float*) node_->m_val = float (d);
}
break;
case Option::flag_t:
*(bool*) node_->m_val = true; // no more flipping!
break;
case Option::func_t:
(*(OPTS_FUNC)(node_->m_val)) ();
break;
case Option::func_one_t:
(*(OPTS_FUNC_ONE)(node_->m_val)) (op_);
break;
case Option::none_t:
default:
m_error = "Undefined type for option '"+string (op_)+"'.";
return (false);
} /*-- switch () --*/
return (true);
}
void
CmdLineOpts::
dump () const
{
OptionSet::const_iterator i;
for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
i->dump ();
}
if (!m_error.empty ()) {
DL((CMDLINEOPTS, "Last error: '%s'\n", m_error.c_str ()));
}
}
void
CmdLineOpts::
str_to_argv (const string& src_, int& argc_, char**& argv_)
{
trace_with_mask ("CmdLineOpts::str_to_argv", CMDLINEOPTS);
std::vector<string> vs;
std::istringstream input (src_);
std::string token;
while (input >> token) {
vs.push_back (token);
token = "";
}
int i = 0;
char* p;
if (vs.size ()) {
argv_ = new char* [vs.size() + 1];
std::vector<string>::iterator it;
for (it = vs.begin (); it != vs.end (); it++, i++) {
p = new char [it->size() + 1];
strcpy (p, it->c_str ());
p[it->size()] = '\0';
argv_[i] = p;
}
argv_[i] = NULL;
}
argc_ = i;
}
void
CmdLineOpts::
free_argv (char**& argv_)
{
trace_with_mask ("CmdLineOpts::free_argv", CMDLINEOPTS);
/* If argument is empty (which should never be the case),
* then freeing the memory would core dump application.
*/
if (argv_ == NULL) {
return;
}
for (int i = 0; argv_[i]; i++) {
delete [] argv_[i];
}
delete [] argv_;
argv_ = NULL;
}
CmdLineOpts.h
Class to handle processing command-line options.
CommonUtils.h
IniFile.h
A Windows-style INI configuration file management class.
Logger.h
An abstraction to message logging facility.
DL
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
trace_with_mask
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
ASSA::CmdLineOpts::find_option
Option * find_option(const char *str_)
Locate option in the options set.
Definition CmdLineOpts.cpp:173
ASSA::CmdLineOpts::m_error
string m_error
Last reported error.
Definition CmdLineOpts.h:287
ASSA::CmdLineOpts::parse_args
bool parse_args(const char *argv[])
Parse command line arguments based on installed options set.
Definition CmdLineOpts.cpp:365
ASSA::CmdLineOpts::OPTS_FUNC
void(* OPTS_FUNC)(void)
Definition CmdLineOpts.h:116
ASSA::CmdLineOpts::OPTS_FUNC_ONE
void(* OPTS_FUNC_ONE)(const string &)
Definition CmdLineOpts.h:117
ASSA::CmdLineOpts::set_error_none
void set_error_none()
Reset error message to an empty string.
Definition CmdLineOpts.h:302
ASSA::CmdLineOpts::add_opt
bool add_opt(const char c, const string &s, string *str)
Add an option with STL string argument.
Definition CmdLineOpts.cpp:220
ASSA::CmdLineOpts::rm_opt
bool rm_opt(const char c_, const string &s_)
Remove option for the option list.
Definition CmdLineOpts.cpp:346
ASSA::CmdLineOpts::m_opts_set
OptionSet m_opts_set
Options set.
Definition CmdLineOpts.h:284
ASSA::CmdLineOpts::add_flag_opt
bool add_flag_opt(const char c, const string &s, bool *f)
Add binary flag option.
Definition CmdLineOpts.cpp:206
ASSA::CmdLineOpts::assign
bool assign(Option *node_, const char *op_)
Perform value assignment to the node.
Definition CmdLineOpts.cpp:536
ASSA::CmdLineOpts::parse_config_file
int parse_config_file(IniFile &inifile_)
Parse configuration parameters found in [options] section of the INI file.
Definition CmdLineOpts.cpp:492
ASSA::CmdLineOpts::pos_arg
virtual void pos_arg(const char *arg_)
Process positional argument arg_.
Definition CmdLineOpts.h:292
ASSA::CmdLineOpts::str_to_argv
static void str_to_argv(const string &src_, int &argc_, char **&argv_)
Static function.
Definition CmdLineOpts.cpp:661
ASSA::CmdLineOpts::dump
void dump() const
Write options set to the log file.
Definition CmdLineOpts.cpp:646
ASSA::CmdLineOpts::free_argv
static void free_argv(char **&argv_)
Free up memory allocated by str_to_argv() function.
Definition CmdLineOpts.cpp:693
ASSA::CmdLineOpts::is_valid
bool is_valid(const char sopt_, const string &lopt_)
Detect if supplied option is valid.
Definition CmdLineOpts.cpp:145
ASSA::IniFile
Definition IniFile.h:40
ASSA::IniFile::find_section
config_iterator find_section(const string &section_)
Find section by its name.
Definition IniFile.cpp:199
ASSA::IniFile::get_value
string get_value(const string &section_, const string &name_) const
Find and return a value of the name/value pair in the section section_.
Definition IniFile.cpp:165
ASSA::IniFile::sect_end
config_iterator sect_end()
Return iterator past the last section.
Definition IniFile.h:174
ASSA::Option
Option class.
Definition CmdLineOpts.h:39
ASSA::Option::func_one_t
@ func_one_t
Convert argument to function with one argument.
Definition CmdLineOpts.h:57
ASSA::Option::func_t
@ func_t
Convert argument to function.
Definition CmdLineOpts.h:56
ASSA::Option::string_t
@ string_t
Convert argument to STL string.
Definition CmdLineOpts.h:48
ASSA::Option::ulong_t
@ ulong_t
Convert argument to unsigned long.
Definition CmdLineOpts.h:52
ASSA::Option::float_t
@ float_t
Convert argument to float.
Definition CmdLineOpts.h:54
ASSA::Option::long_t
@ long_t
Convert argument to long.
Definition CmdLineOpts.h:51
ASSA::Option::double_t
@ double_t
Convert argument to double.
Definition CmdLineOpts.h:53
ASSA::Option::flag_t
@ flag_t
No argument; bool value is flipped.
Definition CmdLineOpts.h:55
ASSA::Option::int_t
@ int_t
Convert argument to int.
Definition CmdLineOpts.h:49
ASSA::Option::uint_t
@ uint_t
Convert argument to unsigned int.
Definition CmdLineOpts.h:50
ASSA::Option::none_t
@ none_t
Definition CmdLineOpts.h:58
ASSA::Option::m_type
type_t m_type
Option type.
Definition CmdLineOpts.h:82
ASSA::Option::m_long_name
string m_long_name
Long option name.
Definition CmdLineOpts.h:79
ASSA::Option::m_val
void * m_val
Pointer to the option value.
Definition CmdLineOpts.h:85
ASSA::Option::dump
void dump() const
Write object state to the log file.
Definition CmdLineOpts.cpp:30
ASSA::Option::type_c_str
const char * type_c_str()
Return the type of the Option object.
Definition CmdLineOpts.cpp:120
ASSA::Option::m_short_name
char m_short_name
One-letter option name.
Definition CmdLineOpts.h:76
ASSA::Utils::find_and_replace_char
void find_and_replace_char(std::string &text_, char src_, char dest_)
Find and relpace all instances of src_ character with dest_ character in a string text_.
Definition CommonUtils.cpp:110
ASSA
Definition Acceptor.h:40
ASSA::CMDLINEOPTS
@ CMDLINEOPTS
Class CmdLineOpts messages.
Definition LogMask.h:36