/home/vlg/develop/libASSA/libassa/assa/CmdLineOpts.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 // $Id: CmdLineOpts.cpp,v 1.6 2006/07/20 02:30:53 vlg Exp $
00004 //------------------------------------------------------------------------------
00005 //                        CmdLineOpts.cpp
00006 //------------------------------------------------------------------------------
00007 //  Copyright (C) 2000,2005  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 
00486 int
00487 CmdLineOpts::
00488 parse_config_file (IniFile& inifile_)
00489 {
00490     trace_with_mask ("CmdLineOpts::parse_config_file", CMDLINEOPTS);
00491 
00492     unsigned int count = 0;
00493     string v;
00494     string s;
00495     OptionSet::iterator pos = m_opts_set.begin ();
00496 
00497     if (inifile_.find_section ("options") == inifile_.sect_end ()) {
00498         m_error = "Missing [options] section in INI file!";
00499         return -1;
00500     }
00501 
00502     while (pos != m_opts_set.end ()) {
00503         if (pos->m_long_name.size ()) {
00504             s = pos->m_long_name;
00505             ASSA::Utils::find_and_replace_char (s, '-', '_');
00506             DL ((CMDLINEOPTS, "trying option \"%s\"\n", s.c_str ()));
00507             v = inifile_.get_value ("options", s);
00508             if (v.size ()) {
00509                 if (assign (&(*pos), v.c_str ())) {
00510                     count++;
00511                 }
00512             }
00513         }
00514         pos++;
00515     }
00516 
00517     return (count);
00518 }
00519 
00520 bool 
00521 CmdLineOpts::
00522 assign (Option* node_, const char* op_)
00523 {
00524     trace_with_mask ("CmdLineOpts::assign", CMDLINEOPTS);
00525 
00526     long l;
00527     double d;
00528 
00529     if (node_ && op_) {
00530         DL ((CMDLINEOPTS, "Assign '%s' to {-%c, --%s, t=%s}\n", 
00531              op_, node_->m_short_name, node_->m_long_name.c_str (),
00532              node_->type_c_str ()));
00533     }
00534 
00535     /*---
00536       From strtol(3C) man page:
00537 
00538       "Because 0 is returned on error and is also a valid return on
00539       success, an application wishing to check for error situations 
00540       should set 'errno' to 0, then call strtol(3C), then check 'errno'
00541       and if it is non-zero, assume an error has occured."
00542       ---*/
00543       
00544     switch (node_->m_type) {
00545     case Option::string_t:
00546         *(string*) node_->m_val = op_;
00547         break;
00548 
00549     case Option::int_t:
00550     case Option::long_t:
00551         errno = 0;
00552         l = strtol (op_, NULL, 0);
00553 
00554         if (errno != 0) {
00555             m_error = "Error: '" + string (strerror (errno)) + "',";
00556             m_error += " in converting to integer from '";
00557             m_error += string (op_) + "'.";
00558             return (false);
00559         }
00560 
00561         if (node_->m_type == Option::int_t) {
00562             *(int*) node_->m_val = int (l);
00563         }
00564         else {
00565             *(long*) node_->m_val = l;
00566         }
00567         break;
00568 
00569     case Option::uint_t:
00570     case Option::ulong_t:
00571         errno = 0;
00572         l = strtol (op_, NULL, 0);
00573 
00574         if (errno != 0) {
00575             m_error = "Error: '" + string (strerror (errno)) + "',";
00576             m_error += " in converting to unsinged integer from '";
00577             m_error += string (op_) + "'.";
00578             return (false);
00579         }
00580 
00581         if (node_->m_type == Option::uint_t) {
00582             *(unsigned int*) node_->m_val = int (l);
00583         }
00584         else {
00585             *(unsigned long*) node_->m_val = l;
00586         }
00587         break;
00588 
00589     case Option::double_t:
00590     case Option::float_t:
00591         errno = 0;
00592         d = strtod (op_, NULL);
00593 
00594         if (errno != 0) {
00595             m_error = "Error: '" + string (strerror (errno)) + "',";
00596             m_error += " in converting to double/float from '";
00597             m_error += string (op_) + "'.";
00598             return (false);
00599         }
00600 
00601         if (node_->m_type == Option::double_t) {
00602             *(double*) node_->m_val = d;
00603         }
00604         else {
00605             *(float*) node_->m_val = float (d);
00606         }
00607         break;
00608 
00609     case Option::flag_t:
00610         *(bool*) node_->m_val = true; // no more flipping!
00611         break;
00612         
00613     case Option::func_t:
00614         (*(OPTS_FUNC)(node_->m_val)) ();
00615         break;
00616 
00617     case Option::func_one_t:
00618         (*(OPTS_FUNC_ONE)(node_->m_val)) (op_);
00619         break;
00620 
00621     case Option::none_t:
00622     default:
00623         m_error = "Undefined type for option '"+string (op_)+"'.";
00624         return (false);
00625     } /*-- switch () --*/
00626 
00627     return (true);
00628 }
00629 
00630 void
00631 CmdLineOpts::
00632 dump () const
00633 {
00634     OptionSet::const_iterator i;
00635 
00636     for (i = m_opts_set.begin (); i != m_opts_set.end (); i++) {
00637         i->dump ();
00638     }
00639 
00640     if (!m_error.empty ()) {
00641         DL((CMDLINEOPTS, "Last error: '%s'\n", m_error.c_str ()));
00642     }
00643 }
00644 
00645 void
00646 CmdLineOpts::
00647 str_to_argv (const string& src_, int& argc_, char**& argv_)
00648 {
00649     trace_with_mask ("CmdLineOpts::str_to_argv", CMDLINEOPTS);
00650 
00651     std::vector<string> vs;
00652     std::istringstream input (src_);
00653     std::string token;
00654 
00655     while (input >> token) {
00656         vs.push_back (token);
00657         token = "";
00658     }
00659     int i = 0;
00660     char* p;
00661 
00662     if (vs.size ()) {
00663         argv_ = new char* [vs.size() + 1];
00664         std::vector<string>::iterator it;
00665 
00666         for (it = vs.begin (); it != vs.end (); it++, i++) {
00667             p = new char [it->size() + 1];
00668             strcpy (p, it->c_str ());
00669             p[it->size()] = '\0';
00670             argv_[i] = p;
00671         }
00672         argv_[i] = NULL;
00673     }
00674     argc_ = i;
00675 }
00676 
00677 void
00678 CmdLineOpts::
00679 free_argv (char**& argv_)
00680 {
00681     trace_with_mask ("CmdLineOpts::free_argv", CMDLINEOPTS);
00682 
00683     /* If argument is empty (which should never be the case),
00684      * then freeing the memory would core dump application.
00685      */
00686     if (argv_ == NULL) {
00687         return;
00688     }
00689 
00690     for (int i = 0; argv_[i]; i++) {
00691         delete [] argv_[i];
00692     }
00693     delete [] argv_;
00694     argv_ = NULL;
00695 }
00696 

Generated on Sun Aug 13 15:08:00 2006 for libassa by  doxygen 1.4.6