libassa 3.5.0

/builddir/build/BUILD/libassa-3.5.0/assa/CmdLineOpts.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 // $Id: CmdLineOpts.cpp,v 1.7 2007/05/14 19:19:50 vlg Exp $
00004 //------------------------------------------------------------------------------
00005 //                        CmdLineOpts.cpp
00006 //------------------------------------------------------------------------------
00007 //  Copyright (C) 2000,2005,2007  Vladislav Grinchenko
00008 //
00009 //  This library is free software; you can redistribute it and/or
00010 //  modify it under the terms of the GNU Library General Public
00011 //  License as published by the Free Software Foundation; either
00012 //  version 2 of the License, or (at your option) any later version.    
00013 //------------------------------------------------------------------------------
00014 #include <errno.h>
00015 #include <string.h>
00016 #include <stdlib.h>
00017 
00018 #include <sstream>
00019 #include <iomanip>
00020 
00021 #include "assa/Logger.h"
00022 #include "assa/CmdLineOpts.h"
00023 #include "assa/CommonUtils.h"
00024 #include "assa/IniFile.h"
00025 
00026 using namespace ASSA;
00027 
00028 void
00029 Option::
00030 dump () const 
00031 {
00032     std::ostringstream msg;
00033 
00034     if (m_short_name != 0) {
00035         msg << "-" << m_short_name << ", ";
00036     }
00037     else {
00038         msg << "    ";
00039     }
00040 
00041     if (m_long_name.size ()) { 
00042         msg << "--" << std::setiosflags (std::ios::left)
00043             << std::setw(14) << m_long_name.c_str () << ' ';
00044     }
00045     else {
00046         msg << std::setiosflags (std::ios::left) << std::setw (14) << "    ";
00047     }
00048     msg << '[';
00049 
00050     switch (m_type) 
00051     {
00052     case Option::string_t: 
00053         msg << std::setiosflags (std::ios::left) << std::setw(7) << "string";
00054         msg << "] = '" << *(string*) m_val << "'";
00055         break;
00056 
00057     case Option::int_t: 
00058         msg << std::setiosflags(std::ios::left) << std::setw(7) << "int";
00059         msg << "] = " << *(int*) m_val; 
00060         break;
00061 
00062     case Option::uint_t: 
00063         msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_int";
00064         msg << "] = " << *(int*) m_val; 
00065         break;
00066 
00067     case Option::long_t: 
00068         msg << std::setiosflags(std::ios::left) << std::setw(7) << "long";
00069         msg << "] = " << *(long*) m_val; 
00070         break;
00071 
00072     case Option::ulong_t: 
00073         msg << std::setiosflags(std::ios::left) << std::setw(7) << "u_long";
00074         msg << "] = " << *(long*) m_val; 
00075         break;
00076 
00077     case Option::double_t: 
00078         msg << std::setiosflags(std::ios::left) << std::setw(7) << "double";
00079         msg << "] = " << *(double*) m_val;
00080         break;
00081 
00082     case Option::float_t: 
00083         msg << std::setiosflags(std::ios::left) << std::setw(7) << "float";
00084         msg << "] = " << *(float*) m_val;
00085         break;
00086 
00087     case Option::flag_t: 
00088         msg << std::setiosflags(std::ios::left) << std::setw(7) << "bool";
00089         msg << "] = " << *(bool*) m_val ? "true" : "false"; 
00090         break;
00091 
00092     case Option::func_t: 
00093         msg << std::setiosflags(std::ios::left) 
00094             << std::setw(7) << "function ()"; 
00095         msg << ']';
00096         break;
00097 
00098     case Option::func_one_t: 
00099         msg << std::setiosflags(std::ios::left) 
00100             << std::setw(7) << "function (opt)";
00101         msg << ']';
00102         break;
00103 
00104     case Option::none_t: 
00105         msg << std::setiosflags(std::ios::left) << std::setw(7) << "none"; 
00106         msg << ']';
00107         break;
00108 
00109     default: 
00110         msg << std::setiosflags(std::ios::left) 
00111         << std::setw(7) << "--undef--";
00112         msg << ']';
00113     }
00114     msg << std::ends;
00115     DL((CMDLINEOPTS,"%s\n", msg.str ().c_str ()));
00116 }
00117 
00118 const char*
00119 Option::
00120 type_c_str ()
00121 {
00122     const char* ret;
00123 
00124     switch (m_type) 
00125     {
00126     case Option::string_t:   ret = "string";    break;
00127     case Option::int_t:      ret = "int";       break;
00128     case Option::uint_t:     ret = "u_int";     break;
00129     case Option::long_t:     ret = "long";      break;
00130     case Option::ulong_t:    ret = "u_long";    break;
00131     case Option::double_t:   ret = "double";    break;
00132     case Option::float_t:    ret = "float";     break;
00133     case Option::flag_t:     ret = "bool";      break;
00134     case Option::func_t:     ret = "func()";    break;
00135     case Option::func_one_t: ret = "func(opt)"; break;
00136     case Option::none_t:     ret = "none";      break;
00137     default:                 ret = "--undef--"; 
00138     }
00139     return (ret);
00140 }
00141 
00142 /*----------------------------------------------------------------------------*/
00143 bool 
00144 CmdLineOpts::
00145 is_valid (const char sopt_, const string& lopt_)
00146 {
00147     trace_with_mask ("CmdLineOpts::is_valid", CMDLINEOPTS);
00148 
00149     set_error_none ();
00150     OptionSet::const_iterator i;
00151 
00152     for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
00153         if (sopt_ == '\0' && lopt_.empty ()) {
00154             m_error = "Ignore empty option";
00155             return (false);
00156         }
00157         else if (sopt_ != '\0' && i->m_short_name == sopt_) {
00158             m_error = "Ignored multiple option '-";
00159             m_error += sopt_ + string ("'");
00160             return (false);
00161         }
00162         else if (!lopt_.empty () && i->m_long_name == lopt_) {
00163             m_error = "Ignore multiple option '--";
00164             m_error += lopt_ + string ("'");
00165             return (false);
00166         }
00167     }
00168     return (true);
00169 }
00170 
00171 Option*
00172 CmdLineOpts::
00173 find_option (const char* str_)
00174 {
00175     trace_with_mask ("CmdLineOpts::find_option(char*)", CMDLINEOPTS);
00176 
00177     OptionSet::iterator i;
00178 
00179     for ( i = m_opts_set.begin (); i != m_opts_set.end (); i++) 
00180     {
00181         if (i->m_long_name == str_) {
00182             return &(*i);
00183         }
00184     }
00185     return (NULL);
00186 }
00187 
00188 Option*
00189 CmdLineOpts::
00190 find_option (const char letter_)
00191 {
00192     trace_with_mask ("CmdLineOpts::find_option(char)", CMDLINEOPTS);
00193 
00194     OptionSet::iterator i;
00195 
00196     for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) 
00197     {
00198         if (i->m_short_name == letter_) 
00199             return &(*i);
00200     }
00201     return (NULL);
00202 }
00203 
00204 bool 
00205 CmdLineOpts::
00206 add_flag_opt (const char sopt_, const string& lopt_, bool* v_)
00207 {
00208     trace_with_mask ("CmdLineOpts::add_flag_opt", CMDLINEOPTS);
00209 
00210     if (!is_valid (sopt_, lopt_)) 
00211         return (false);
00212 
00213     Option o (sopt_, lopt_, Option::flag_t, (void*) v_);
00214     m_opts_set.push_back (o);
00215     return (true);
00216 }
00217 
00218 bool 
00219 CmdLineOpts::
00220 add_opt (const char sopt_, const string& lopt_, string* v_)
00221 {
00222     trace_with_mask ("CmdLineOpts::add_opt(string*)", CMDLINEOPTS);
00223 
00224     if (!is_valid (sopt_, lopt_)) 
00225         return (false);
00226 
00227     Option o (sopt_, lopt_, Option::string_t, (void*) v_);
00228     m_opts_set.push_back (o);
00229     return (true);
00230 }
00231     
00232 bool 
00233 CmdLineOpts::
00234 add_opt (const char sopt_, const string& lopt_, int* v_)
00235 {
00236     trace_with_mask ("CmdLineOpts::add_opt(int*)", CMDLINEOPTS);
00237 
00238     if (!is_valid (sopt_, lopt_)) {
00239         return (false);
00240     }
00241     Option o (sopt_, lopt_, Option::int_t, (void*) v_);
00242     m_opts_set.push_back (o);
00243     return (true);
00244 }
00245 
00246 bool 
00247 CmdLineOpts::
00248 add_opt (const char sopt_, const string& lopt_, unsigned int* v_)
00249 {
00250     trace_with_mask ("CmdLineOpts::add_opt(u_int*)", CMDLINEOPTS);
00251 
00252     if (!is_valid (sopt_, lopt_)) {
00253         return (false);
00254     }
00255     Option o (sopt_, lopt_, Option::uint_t, (void*) v_);
00256     m_opts_set.push_back (o);
00257     return (true);
00258 }
00259 
00260 bool 
00261 CmdLineOpts::
00262 add_opt (const char sopt_, const string& lopt_, long* v_)
00263 {
00264     trace_with_mask ("CmdLineOpts::add_opt(long*)", CMDLINEOPTS);
00265 
00266     if (!is_valid (sopt_, lopt_)) {
00267         return (false);
00268     }
00269     Option o (sopt_, lopt_, Option::long_t, (void*) v_);
00270     m_opts_set.push_back (o);
00271     return (true);
00272 }
00273 
00274 bool 
00275 CmdLineOpts::
00276 add_opt (const char sopt_, const string& lopt_, unsigned long* v_)
00277 {
00278     trace_with_mask ("CmdLineOpts::add_opt(u_long*)", CMDLINEOPTS);
00279 
00280     if (!is_valid (sopt_, lopt_)) {
00281         return (false);
00282     }
00283     Option o (sopt_, lopt_, Option::long_t, (void*) v_);
00284     m_opts_set.push_back (o);
00285     return (true);
00286 }
00287 
00288 bool 
00289 CmdLineOpts::
00290 add_opt (const char sopt_, const string& lopt_, double* v_)
00291 {
00292     trace_with_mask ("CmdLineOpts::add_opt(double*)", CMDLINEOPTS);
00293 
00294     if (!is_valid (sopt_, lopt_)) {
00295         return (false);
00296     }
00297     Option o (sopt_, lopt_, Option::double_t, (void*) v_);
00298     m_opts_set.push_back (o);
00299     return (true);
00300 }
00301 
00302 bool 
00303 CmdLineOpts::
00304 add_opt (const char sopt_, const string& lopt_, float* v_)
00305 {
00306     trace_with_mask ("CmdLineOpts::add_opt(float*)", CMDLINEOPTS);
00307 
00308     if (!is_valid (sopt_, lopt_)) {
00309         return (false);
00310     }
00311     Option o (sopt_, lopt_, Option::float_t, (void*) v_);
00312     m_opts_set.push_back (o);
00313     return (true);
00314 }
00315 
00316 bool 
00317 CmdLineOpts::
00318 add_opt (const char sopt_, const string& lopt_, OPTS_FUNC v_)
00319 {
00320     trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC)", CMDLINEOPTS);
00321 
00322     if (!is_valid (sopt_, lopt_)) {
00323         return (false);
00324     }
00325     Option o (sopt_, lopt_, Option::func_t, (void*) v_);
00326     m_opts_set.push_back (o);
00327     return (true);
00328 }
00329 
00330 bool 
00331 CmdLineOpts::
00332 add_opt (const char sopt_, const string& lopt_, OPTS_FUNC_ONE v_)
00333 {
00334     trace_with_mask ("CmdLineOpts::add_opt(OPTS_FUNC_ONE)", CMDLINEOPTS);
00335 
00336     if (!is_valid (sopt_, lopt_)) {
00337         return (false);
00338     }
00339     Option o (sopt_, lopt_, Option::func_one_t, (void*) v_);
00340     m_opts_set.push_back (o);
00341     return (true);
00342 }
00343 
00344 bool
00345 CmdLineOpts::
00346 rm_opt (const char sopt_, const string& lopt_)
00347 {
00348     trace_with_mask ("CmdLineOpts::rm_opt(string&)", CMDLINEOPTS);
00349 
00350     OptionSet::iterator i;
00351 
00352     for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) 
00353     {
00354         if (i->m_short_name == sopt_ || i->m_long_name == lopt_) 
00355         {
00356             m_opts_set.erase (i);
00357             return (true);
00358         }
00359     }
00360     return (false);
00361 }
00362     
00363 bool 
00364 CmdLineOpts::
00365 parse_args (const char* argv_[])
00366 {
00367     trace_with_mask ("CmdLineOpts::parse_args", CMDLINEOPTS);
00368 
00369     register int skip = 1;
00370     bool pos_args_started = false;
00371     string param ("");
00372     string token ("");
00373     set_error_none ();
00374     Option* node = (Option*) NULL;
00375 
00376     for (argv_++; argv_[0]; argv_ += skip) {
00377         if (skip != 0) {
00378             token = argv_[0];
00379         }
00380 
00381         DL((CMDLINEOPTS, "token: \"%s\"\n", token.c_str()));
00382 
00383         if (pos_args_started) {
00384             DL((CMDLINEOPTS,"pos_args_started = true\n"));
00385 
00386             if (token[0] == '-' && token.size () != 1) {
00387                 m_error = "Invalid order of arguments: '";
00388                 m_error += token + "'.";
00389                 goto done;
00390             }
00391             pos_arg (token.c_str ());
00392             continue;
00393         }
00394         skip = 1;
00395 
00396         if (token[0] == '-' && token.size () > 1 && token[1] != '-') {
00397             if (token.size () == 1 && !pos_args_started) {
00398                 pos_arg (token.c_str ());
00399                 pos_args_started = true;
00400                 continue;
00401             }
00402                 
00403             if ((node = find_option (token[1])) != NULL) {
00404                 if (token.size () > 2) {
00405                     if (node->m_type == Option::flag_t ||
00406                         node->m_type == Option::func_t) 
00407                     {
00408                         token.erase (1, 1);
00409                         skip = 0;
00410                     }
00411                     else {
00412                         param = token.substr (2);
00413                     } 
00414                 } // if (token.size()>2)
00415             } // if ((node = find_option ())
00416         } 
00417         else {  
00418             if (token.size () > 1 && token[1] == '-') {
00419                 string op = token.substr (2);
00420                 size_t pos;
00421 
00422                 if ((pos = op.find ("=")) != (size_t)-1) {
00423                     param = op.substr (pos+1, op.length ());
00424                     op.replace (pos, op.length() - pos, "");
00425                 }
00426                 node = find_option (op.c_str ());
00427             }
00428             else {  
00429                 pos_arg (token.c_str ());
00430                 pos_args_started = true;
00431                 continue;
00432             } 
00433         } // if (token[0] == '-' && token[1] != '-') 
00434 
00435         if (!node) {
00436             m_error = "Invalid option '" + token + "'.";
00437             goto done;
00438         }
00439 
00440         if (node->m_type != Option::flag_t &&
00441             node->m_type != Option::func_t) 
00442         {
00443             if (param.empty ()) {
00444                 if (!argv_[1]) {
00445                     m_error = "Expecting parameter after '"
00446                         + string (argv_[0]) + "'.";
00447                     goto done;
00448                 }
00449                 param = argv_[1];
00450                 skip = 2;
00451             }
00452         }
00453         /*--- 
00454          * if positional arguments only 
00455          ---*/
00456         if (!node) {
00457             goto done;
00458         }
00459 
00460         if (param.empty ()) {
00461             if (!assign (node, argv_[1])) {
00462                 return (false);
00463             }
00464         }
00465         else {
00466             const char* str = param.c_str ();
00467             if (!assign (node, str)) {
00468                 return (false);
00469             }
00470             param = "";
00471         }
00472     } // for (argv_++; argv_[0]; argv_ += skip) 
00473 
00474  done:
00475     return !m_error.empty () ? false : true;
00476 }
00477 
00490 int
00491 CmdLineOpts::
00492 parse_config_file (IniFile& inifile_)
00493 {
00494     trace_with_mask ("CmdLineOpts::parse_config_file", CMDLINEOPTS);
00495 
00496     unsigned int count = 0;
00497     string v;
00498     string s;
00499     string optsect_name ("options");
00500     OptionSet::iterator pos = m_opts_set.begin ();
00501 
00502     if (inifile_.find_section (optsect_name) == inifile_.sect_end ()) 
00503     {
00504         optsect_name = "Options";
00505         if (inifile_.find_section (optsect_name) == inifile_.sect_end ()) 
00506         {
00507             optsect_name = "OPTIONS";
00508             if (inifile_.find_section (optsect_name) == inifile_.sect_end ()) 
00509             {
00510                 m_error = "Missing [options] section in INI file!";
00511                 return -1;
00512             }
00513         }
00514     }
00515 
00516     while (pos != m_opts_set.end ()) {
00517         if (pos->m_long_name.size ()) {
00518             s = pos->m_long_name;
00519             ASSA::Utils::find_and_replace_char (s, '-', '_');
00520             DL ((CMDLINEOPTS, "trying option \"%s\"\n", s.c_str ()));
00521             v = inifile_.get_value (optsect_name, s);
00522             if (v.size ()) {
00523                 if (assign (&(*pos), v.c_str ())) {
00524                     count++;
00525                 }
00526             }
00527         }
00528         pos++;
00529     }
00530 
00531     return (count);
00532 }
00533 
00534 bool 
00535 CmdLineOpts::
00536 assign (Option* node_, const char* op_)
00537 {
00538     trace_with_mask ("CmdLineOpts::assign", CMDLINEOPTS);
00539 
00540     long l;
00541     double d;
00542 
00543     if (node_ && op_) {
00544         DL ((CMDLINEOPTS, "Assign '%s' to {-%c, --%s, t=%s}\n", 
00545              op_, node_->m_short_name, node_->m_long_name.c_str (),
00546              node_->type_c_str ()));
00547     }
00548 
00549     /*---
00550       From strtol(3C) man page:
00551 
00552       "Because 0 is returned on error and is also a valid return on
00553       success, an application wishing to check for error situations 
00554       should set 'errno' to 0, then call strtol(3C), then check 'errno'
00555       and if it is non-zero, assume an error has occured."
00556       ---*/
00557       
00558     switch (node_->m_type) {
00559     case Option::string_t:
00560         *(string*) node_->m_val = op_;
00561         break;
00562 
00563     case Option::int_t:
00564     case Option::long_t:
00565         errno = 0;
00566         l = strtol (op_, NULL, 0);
00567 
00568         if (errno != 0) {
00569             m_error = "Error: '" + string (strerror (errno)) + "',";
00570             m_error += " in converting to integer from '";
00571             m_error += string (op_) + "'.";
00572             return (false);
00573         }
00574 
00575         if (node_->m_type == Option::int_t) {
00576             *(int*) node_->m_val = int (l);
00577         }
00578         else {
00579             *(long*) node_->m_val = l;
00580         }
00581         break;
00582 
00583     case Option::uint_t:
00584     case Option::ulong_t:
00585         errno = 0;
00586         l = strtol (op_, NULL, 0);
00587 
00588         if (errno != 0) {
00589             m_error = "Error: '" + string (strerror (errno)) + "',";
00590             m_error += " in converting to unsinged integer from '";
00591             m_error += string (op_) + "'.";
00592             return (false);
00593         }
00594 
00595         if (node_->m_type == Option::uint_t) {
00596             *(unsigned int*) node_->m_val = int (l);
00597         }
00598         else {
00599             *(unsigned long*) node_->m_val = l;
00600         }
00601         break;
00602 
00603     case Option::double_t:
00604     case Option::float_t:
00605         errno = 0;
00606         d = strtod (op_, NULL);
00607 
00608         if (errno != 0) {
00609             m_error = "Error: '" + string (strerror (errno)) + "',";
00610             m_error += " in converting to double/float from '";
00611             m_error += string (op_) + "'.";
00612             return (false);
00613         }
00614 
00615         if (node_->m_type == Option::double_t) {
00616             *(double*) node_->m_val = d;
00617         }
00618         else {
00619             *(float*) node_->m_val = float (d);
00620         }
00621         break;
00622 
00623     case Option::flag_t:
00624         *(bool*) node_->m_val = true; // no more flipping!
00625         break;
00626         
00627     case Option::func_t:
00628         (*(OPTS_FUNC)(node_->m_val)) ();
00629         break;
00630 
00631     case Option::func_one_t:
00632         (*(OPTS_FUNC_ONE)(node_->m_val)) (op_);
00633         break;
00634 
00635     case Option::none_t:
00636     default:
00637         m_error = "Undefined type for option '"+string (op_)+"'.";
00638         return (false);
00639     } /*-- switch () --*/
00640 
00641     return (true);
00642 }
00643 
00644 void
00645 CmdLineOpts::
00646 dump () const
00647 {
00648     OptionSet::const_iterator i;
00649 
00650     for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
00651         i->dump ();
00652     }
00653 
00654     if (!m_error.empty ()) {
00655         DL((CMDLINEOPTS, "Last error: '%s'\n", m_error.c_str ()));
00656     }
00657 }
00658 
00659 void
00660 CmdLineOpts::
00661 str_to_argv (const string& src_, int& argc_, char**& argv_)
00662 {
00663     trace_with_mask ("CmdLineOpts::str_to_argv", CMDLINEOPTS);
00664 
00665     std::vector<string> vs;
00666     std::istringstream input (src_);
00667     std::string token;
00668 
00669     while (input >> token) {
00670         vs.push_back (token);
00671         token = "";
00672     }
00673     int i = 0;
00674     char* p;
00675 
00676     if (vs.size ()) {
00677         argv_ = new char* [vs.size() + 1];
00678         std::vector<string>::iterator it;
00679 
00680         for (it = vs.begin (); it != vs.end (); it++, i++) {
00681             p = new char [it->size() + 1];
00682             strcpy (p, it->c_str ());
00683             p[it->size()] = '\0';
00684             argv_[i] = p;
00685         }
00686         argv_[i] = NULL;
00687     }
00688     argc_ = i;
00689 }
00690 
00691 void
00692 CmdLineOpts::
00693 free_argv (char**& argv_)
00694 {
00695     trace_with_mask ("CmdLineOpts::free_argv", CMDLINEOPTS);
00696 
00697     /* If argument is empty (which should never be the case),
00698      * then freeing the memory would core dump application.
00699      */
00700     if (argv_ == NULL) {
00701         return;
00702     }
00703 
00704     for (int i = 0; argv_[i]; i++) {
00705         delete [] argv_[i];
00706     }
00707     delete [] argv_;
00708     argv_ = NULL;
00709 }
00710 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines