lemon/arg_parser.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 24 Mar 2009 00:18:25 +0100
changeset 596 8c3112a66878
parent 311 c887e703b566
permissions -rw-r--r--
Use XTI implementation instead of ATI in NetworkSimplex (#234)

XTI (eXtended Threaded Index) is an imporved version of the widely
known ATI (Augmented Threaded Index) method for storing and updating
the spanning tree structure in Network Simplex algorithms.

In the ATI data structure three indices are stored for each node:
predecessor, thread and depth. In the XTI data structure depth is
replaced by the number of successors and the last successor
(according to the thread index).
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2009
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include <lemon/arg_parser.h>
    20 
    21 namespace lemon {
    22 
    23   void ArgParser::_showHelp(void *p)
    24   {
    25     (static_cast<ArgParser*>(p))->showHelp();
    26     exit(1);
    27   }
    28 
    29   ArgParser::ArgParser(int argc, const char * const *argv)
    30     :_argc(argc), _argv(argv), _command_name(argv[0]) {
    31     funcOption("-help","Print a short help message",_showHelp,this);
    32     synonym("help","-help");
    33     synonym("h","-help");
    34   }
    35 
    36   ArgParser::~ArgParser()
    37   {
    38     for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
    39       if(i->second.self_delete)
    40         switch(i->second.type) {
    41         case BOOL:
    42           delete i->second.bool_p;
    43           break;
    44         case STRING:
    45           delete i->second.string_p;
    46           break;
    47         case DOUBLE:
    48           delete i->second.double_p;
    49           break;
    50         case INTEGER:
    51           delete i->second.int_p;
    52           break;
    53         case UNKNOWN:
    54           break;
    55         case FUNC:
    56           break;
    57         }
    58   }
    59 
    60 
    61   ArgParser &ArgParser::intOption(const std::string &name,
    62                                const std::string &help,
    63                                int value, bool obl)
    64   {
    65     ParData p;
    66     p.int_p=new int(value);
    67     p.self_delete=true;
    68     p.help=help;
    69     p.type=INTEGER;
    70     p.mandatory=obl;
    71     _opts[name]=p;
    72     return *this;
    73   }
    74 
    75   ArgParser &ArgParser::doubleOption(const std::string &name,
    76                                const std::string &help,
    77                                double value, bool obl)
    78   {
    79     ParData p;
    80     p.double_p=new double(value);
    81     p.self_delete=true;
    82     p.help=help;
    83     p.type=DOUBLE;
    84     p.mandatory=obl;
    85     _opts[name]=p;
    86     return *this;
    87   }
    88 
    89   ArgParser &ArgParser::boolOption(const std::string &name,
    90                                const std::string &help,
    91                                bool value, bool obl)
    92   {
    93     ParData p;
    94     p.bool_p=new bool(value);
    95     p.self_delete=true;
    96     p.help=help;
    97     p.type=BOOL;
    98     p.mandatory=obl;
    99     _opts[name]=p;
   100     return *this;
   101   }
   102 
   103   ArgParser &ArgParser::stringOption(const std::string &name,
   104                                const std::string &help,
   105                                std::string value, bool obl)
   106   {
   107     ParData p;
   108     p.string_p=new std::string(value);
   109     p.self_delete=true;
   110     p.help=help;
   111     p.type=STRING;
   112     p.mandatory=obl;
   113     _opts[name]=p;
   114     return *this;
   115   }
   116 
   117   ArgParser &ArgParser::refOption(const std::string &name,
   118                                const std::string &help,
   119                                int &ref, bool obl)
   120   {
   121     ParData p;
   122     p.int_p=&ref;
   123     p.self_delete=false;
   124     p.help=help;
   125     p.type=INTEGER;
   126     p.mandatory=obl;
   127     _opts[name]=p;
   128     return *this;
   129   }
   130 
   131   ArgParser &ArgParser::refOption(const std::string &name,
   132                                   const std::string &help,
   133                                   double &ref, bool obl)
   134   {
   135     ParData p;
   136     p.double_p=&ref;
   137     p.self_delete=false;
   138     p.help=help;
   139     p.type=DOUBLE;
   140     p.mandatory=obl;
   141     _opts[name]=p;
   142     return *this;
   143   }
   144 
   145   ArgParser &ArgParser::refOption(const std::string &name,
   146                                   const std::string &help,
   147                                   bool &ref, bool obl)
   148   {
   149     ParData p;
   150     p.bool_p=&ref;
   151     p.self_delete=false;
   152     p.help=help;
   153     p.type=BOOL;
   154     p.mandatory=obl;
   155     _opts[name]=p;
   156 
   157     ref = false;
   158 
   159     return *this;
   160   }
   161 
   162   ArgParser &ArgParser::refOption(const std::string &name,
   163                                const std::string &help,
   164                                std::string &ref, bool obl)
   165   {
   166     ParData p;
   167     p.string_p=&ref;
   168     p.self_delete=false;
   169     p.help=help;
   170     p.type=STRING;
   171     p.mandatory=obl;
   172     _opts[name]=p;
   173     return *this;
   174   }
   175 
   176   ArgParser &ArgParser::funcOption(const std::string &name,
   177                                const std::string &help,
   178                                void (*func)(void *),void *data)
   179   {
   180     ParData p;
   181     p.func_p.p=func;
   182     p.func_p.data=data;
   183     p.self_delete=false;
   184     p.help=help;
   185     p.type=FUNC;
   186     p.mandatory=false;
   187     _opts[name]=p;
   188     return *this;
   189   }
   190 
   191   ArgParser &ArgParser::optionGroup(const std::string &group,
   192                                     const std::string &opt)
   193   {
   194     Opts::iterator i = _opts.find(opt);
   195     LEMON_ASSERT(i!=_opts.end(), "Unknown option: '"+opt+"'");
   196     LEMON_ASSERT(!(i->second.ingroup),
   197                  "Option already in option group: '"+opt+"'");
   198     GroupData &g=_groups[group];
   199     g.opts.push_back(opt);
   200     i->second.ingroup=true;
   201     return *this;
   202   }
   203 
   204   ArgParser &ArgParser::onlyOneGroup(const std::string &group)
   205   {
   206     GroupData &g=_groups[group];
   207     g.only_one=true;
   208     return *this;
   209   }
   210 
   211   ArgParser &ArgParser::synonym(const std::string &syn,
   212                                 const std::string &opt)
   213   {
   214     Opts::iterator o = _opts.find(opt);
   215     Opts::iterator s = _opts.find(syn);
   216     LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
   217     LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'");
   218     ParData p;
   219     p.help=opt;
   220     p.mandatory=false;
   221     p.syn=true;
   222     _opts[syn]=p;
   223     o->second.has_syn=true;
   224     return *this;
   225   }
   226 
   227   ArgParser &ArgParser::mandatoryGroup(const std::string &group)
   228   {
   229     GroupData &g=_groups[group];
   230     g.mandatory=true;
   231     return *this;
   232   }
   233 
   234   ArgParser &ArgParser::other(const std::string &name,
   235                               const std::string &help)
   236   {
   237     _others_help.push_back(OtherArg(name,help));
   238     return *this;
   239   }
   240 
   241   void ArgParser::show(std::ostream &os,Opts::const_iterator i) const
   242   {
   243     os << "-" << i->first;
   244     if(i->second.has_syn)
   245       for(Opts::const_iterator j=_opts.begin();j!=_opts.end();++j)
   246         if(j->second.syn&&j->second.help==i->first)
   247           os << "|-" << j->first;
   248     switch(i->second.type) {
   249     case STRING:
   250       os << " str";
   251       break;
   252     case INTEGER:
   253       os << " int";
   254       break;
   255     case DOUBLE:
   256       os << " num";
   257       break;
   258     default:
   259       break;
   260     }
   261   }
   262 
   263   void ArgParser::show(std::ostream &os,Groups::const_iterator i) const
   264   {
   265     GroupData::Opts::const_iterator o=i->second.opts.begin();
   266     while(o!=i->second.opts.end()) {
   267       show(os,_opts.find(*o));
   268       ++o;
   269       if(o!=i->second.opts.end()) os<<'|';
   270     }
   271   }
   272 
   273   void ArgParser::showHelp(Opts::const_iterator i) const
   274   {
   275     if(i->second.help.size()==0||i->second.syn) return;
   276     std::cerr << "  ";
   277     show(std::cerr,i);
   278     std::cerr << std::endl;
   279     std::cerr << "     " << i->second.help << std::endl;
   280   }
   281   void ArgParser::showHelp(std::vector<ArgParser::OtherArg>::const_iterator i)
   282     const
   283   {
   284     if(i->help.size()==0) return;
   285     std::cerr << "  " << i->name << std::endl
   286               << "     " << i->help << std::endl;
   287   }
   288 
   289   void ArgParser::shortHelp() const
   290   {
   291     const unsigned int LINE_LEN=77;
   292     const std::string indent("    ");
   293     std::cerr << "Usage:\n  " << _command_name;
   294     int pos=_command_name.size()+2;
   295     for(Groups::const_iterator g=_groups.begin();g!=_groups.end();++g) {
   296       std::ostringstream cstr;
   297       cstr << ' ';
   298       if(!g->second.mandatory) cstr << '[';
   299       show(cstr,g);
   300       if(!g->second.mandatory) cstr << ']';
   301       if(pos+cstr.str().size()>LINE_LEN) {
   302         std::cerr << std::endl << indent;
   303         pos=indent.size();
   304       }
   305       std::cerr << cstr.str();
   306       pos+=cstr.str().size();
   307     }
   308     for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i)
   309       if(!i->second.ingroup&&!i->second.syn) {
   310         std::ostringstream cstr;
   311         cstr << ' ';
   312         if(!i->second.mandatory) cstr << '[';
   313         show(cstr,i);
   314         if(!i->second.mandatory) cstr << ']';
   315         if(pos+cstr.str().size()>LINE_LEN) {
   316           std::cerr << std::endl << indent;
   317           pos=indent.size();
   318         }
   319         std::cerr << cstr.str();
   320         pos+=cstr.str().size();
   321       }
   322     for(std::vector<OtherArg>::const_iterator i=_others_help.begin();
   323         i!=_others_help.end();++i)
   324       {
   325         std::ostringstream cstr;
   326         cstr << ' ' << i->name;
   327 
   328         if(pos+cstr.str().size()>LINE_LEN) {
   329           std::cerr << std::endl << indent;
   330           pos=indent.size();
   331         }
   332         std::cerr << cstr.str();
   333         pos+=cstr.str().size();
   334       }
   335     std::cerr << std::endl;
   336   }
   337 
   338   void ArgParser::showHelp() const
   339   {
   340     shortHelp();
   341     std::cerr << "Where:\n";
   342     for(std::vector<OtherArg>::const_iterator i=_others_help.begin();
   343         i!=_others_help.end();++i) showHelp(i);
   344     for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i);
   345     exit(1);
   346   }
   347 
   348 
   349   void ArgParser::unknownOpt(std::string arg) const
   350   {
   351     std::cerr << "\nUnknown option: " << arg << "\n";
   352     std::cerr << "\nType '" << _command_name <<
   353       " --help' to obtain a short summary on the usage.\n\n";
   354     exit(1);
   355   }
   356 
   357   void ArgParser::requiresValue(std::string arg, OptType t) const
   358   {
   359     std::cerr << "Argument '" << arg << "' requires a";
   360     switch(t) {
   361     case STRING:
   362       std::cerr << " string";
   363       break;
   364     case INTEGER:
   365       std::cerr << "n integer";
   366       break;
   367     case DOUBLE:
   368       std::cerr << " floating point";
   369       break;
   370     default:
   371       break;
   372     }
   373     std::cerr << " value\n\n";
   374     showHelp();
   375   }
   376 
   377 
   378   void ArgParser::checkMandatories() const
   379   {
   380     bool ok=true;
   381     for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i)
   382       if(i->second.mandatory&&!i->second.set)
   383         {
   384           if(ok)
   385             std::cerr << _command_name
   386                       << ": The following mandatory arguments are missing.\n";
   387           ok=false;
   388           showHelp(i);
   389         }
   390     for(Groups::const_iterator i=_groups.begin();i!=_groups.end();++i)
   391       if(i->second.mandatory||i->second.only_one)
   392         {
   393           int set=0;
   394           for(GroupData::Opts::const_iterator o=i->second.opts.begin();
   395               o!=i->second.opts.end();++o)
   396             if(_opts.find(*o)->second.set) ++set;
   397           if(i->second.mandatory&&!set) {
   398             std::cerr << _command_name <<
   399               ": At least one of the following arguments is mandatory.\n";
   400             ok=false;
   401             for(GroupData::Opts::const_iterator o=i->second.opts.begin();
   402                 o!=i->second.opts.end();++o)
   403               showHelp(_opts.find(*o));
   404           }
   405           if(i->second.only_one&&set>1) {
   406             std::cerr << _command_name <<
   407               ": At most one of the following arguments can be given.\n";
   408             ok=false;
   409             for(GroupData::Opts::const_iterator o=i->second.opts.begin();
   410                 o!=i->second.opts.end();++o)
   411               showHelp(_opts.find(*o));
   412           }
   413         }
   414     if(!ok) {
   415       std::cerr << "\nType '" << _command_name <<
   416         " --help' to obtain a short summary on the usage.\n\n";
   417       exit(1);
   418     }
   419   }
   420 
   421   ArgParser &ArgParser::parse()
   422   {
   423     for(int ar=1; ar<_argc; ++ar) {
   424       std::string arg(_argv[ar]);
   425       if (arg[0] != '-' || arg.size() == 1) {
   426         _file_args.push_back(arg);
   427       }
   428       else {
   429         Opts::iterator i = _opts.find(arg.substr(1));
   430         if(i==_opts.end()) unknownOpt(arg);
   431         else {
   432           if(i->second.syn) i=_opts.find(i->second.help);
   433           ParData &p(i->second);
   434           if (p.type==BOOL) *p.bool_p=true;
   435           else if (p.type==FUNC) p.func_p.p(p.func_p.data);
   436           else if(++ar==_argc) requiresValue(arg, p.type);
   437           else {
   438             std::string val(_argv[ar]);
   439             std::istringstream vals(val);
   440             switch(p.type) {
   441             case STRING:
   442               *p.string_p=val;
   443               break;
   444             case INTEGER:
   445               vals >> *p.int_p;
   446               break;
   447             case DOUBLE:
   448               vals >> *p.double_p;
   449               break;
   450             default:
   451               break;
   452             }
   453             if(p.type!=STRING&&(!vals||!vals.eof()))
   454               requiresValue(arg, p.type);
   455           }
   456           p.set = true;
   457         }
   458       }
   459     }
   460     checkMandatories();
   461 
   462     return *this;
   463   }
   464 
   465 }