COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/arg_parser.cc @ 2391:14a343be7a5a

Last change on this file since 2391:14a343be7a5a was 2391:14a343be7a5a, checked in by Alpar Juttner, 12 years ago

Happy New Year to all source files!

File size: 9.2 KB
Line 
1/* -*- C++ -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library
4 *
5 * Copyright (C) 2003-2007
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
21namespace 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, char **argv) :_argc(argc), _argv(argv),
30                                               _command_name(argv[0]) {
31    option("-help","Print a short help message",_showHelp,this);
32    synonym("help","-help");
33    synonym("h","-help");
34
35  }
36
37  ArgParser &ArgParser::option(const std::string &name,
38                               const std::string &help,
39                               int &value, bool obl)
40  {
41    ParData p;
42    p.int_p=&value;
43    p.help=help;
44    p.type=INTEGER;
45    p.mandatory=obl;
46    _opts[name]=p;
47    return *this;
48  }
49
50  ArgParser &ArgParser::option(const std::string &name,
51                               const std::string &help,
52                               double &value, bool obl)
53  {
54    ParData p;
55    p.double_p=&value;
56    p.help=help;
57    p.type=DOUBLE;
58    p.mandatory=obl;
59    _opts[name]=p;
60    return *this;
61  }
62
63  ArgParser &ArgParser::option(const std::string &name,
64                               const std::string &help,
65                               bool &value, bool obl)
66  {
67    ParData p;
68    p.bool_p=&value;
69    p.help=help;
70    p.type=BOOL;
71    p.mandatory=obl;
72    _opts[name]=p;
73
74    value = false;
75
76    return *this;
77  }
78
79  ArgParser &ArgParser::option(const std::string &name,
80                               const std::string &help,
81                               std::string &value, bool obl)
82  {
83    ParData p;
84    p.string_p=&value;
85    p.help=help;
86    p.type=STRING;
87    p.mandatory=obl;
88    _opts[name]=p;
89    return *this;
90  }
91
92  ArgParser &ArgParser::option(const std::string &name,
93                               const std::string &help,
94                               void (*func)(void *),void *data)
95  {
96    ParData p;
97    p.func_p.p=func;
98    p.func_p.data=data;
99    p.help=help;
100    p.type=FUNC;
101    p.mandatory=false;
102    _opts[name]=p;
103    return *this;
104  }
105  ArgParser &ArgParser::optionGroup(const std::string &group,
106                                    const std::string &opt)
107  {
108    Opts::iterator i = _opts.find(opt);
109    if(i==_opts.end()) exit(3); ///\todo throw exception instead
110    else if(i->second.ingroup) exit(3); ///\todo throw exception instead
111    else {
112      GroupData &g=_groups[group];
113      g.opts.push_back(opt);
114      i->second.ingroup=true;
115    }
116    return *this;
117  }
118
119  ArgParser &ArgParser::onlyOneGroup(const std::string &group)
120  {
121    GroupData &g=_groups[group];
122    g.only_one=true;
123    return *this;
124  }
125
126  ArgParser &ArgParser::synonym(const std::string &syn,
127                                const std::string &opt)
128  {
129    Opts::iterator o = _opts.find(opt);
130    Opts::iterator s = _opts.find(syn);
131    if(o==_opts.end()||s!=_opts.end())
132      exit(3); ///\todo throw exception instead
133    else {
134      ParData p;
135      p.help=opt;
136      p.mandatory=false;
137      p.syn=true;
138      _opts[syn]=p;
139      o->second.has_syn=true;
140    }
141    return *this;
142  }
143
144  ArgParser &ArgParser::mandatoryGroup(const std::string &group)
145  {
146    GroupData &g=_groups[group];
147    g.mandatory=true;
148    return *this;
149  }
150
151  ArgParser &ArgParser::other(const std::string &name,
152                              const std::string &help)
153  {
154    _others_help.push_back(OtherArg(name,help));
155    return *this;
156  }
157
158  void ArgParser::show(std::ostream &os,Opts::iterator i)
159  {
160    os << "-" << i->first;
161    if(i->second.has_syn)
162      for(Opts::iterator j=_opts.begin();j!=_opts.end();++j)
163        if(j->second.syn&&j->second.help==i->first)
164          os << "|-" << j->first;
165    switch(i->second.type) {
166    case STRING:
167      os << " str";
168      break;
169    case INTEGER:
170      os << " int";
171      break;
172    case DOUBLE:
173      os << " num";
174      break;
175    default:
176      break;
177    }
178  }
179
180  void ArgParser::show(std::ostream &os,Groups::iterator i)
181  {
182    GroupData::Opts::iterator o=i->second.opts.begin();
183    while(o!=i->second.opts.end()) {
184      show(os,_opts.find(*o));
185      ++o;
186      if(o!=i->second.opts.end()) os<<'|';
187    }
188  }
189   
190  void ArgParser::showHelp(Opts::iterator i)
191  {
192    if(i->second.help.size()==0||i->second.syn) return;
193    std::cerr << "  ";
194    show(std::cerr,i);
195    std::cerr << std::endl;
196    std::cerr << "     " << i->second.help << std::endl;
197  }
198  void ArgParser::showHelp(std::vector<ArgParser::OtherArg>::iterator i)
199  {
200    if(i->help.size()==0) return;
201    std::cerr << "  " << i->name << std::endl
202              << "     " << i->help << std::endl;
203  }
204   
205  void ArgParser::shortHelp()
206  {
207    const unsigned int LINE_LEN=77;
208    const std::string indent("    ");
209    std::cerr << "Usage:\n  " << _command_name;
210    int pos=_command_name.size()+2;
211    for(Groups::iterator g=_groups.begin();g!=_groups.end();++g) {
212      std::ostringstream cstr;
213      cstr << ' ';
214      if(!g->second.mandatory) cstr << '[';
215      show(cstr,g);
216      if(!g->second.mandatory) cstr << ']';
217      if(pos+cstr.str().size()>LINE_LEN) {
218        std::cerr << std::endl << indent;
219        pos=indent.size();
220      }
221      std::cerr << cstr.str();
222      pos+=cstr.str().size();
223    }
224    for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
225      if(!i->second.ingroup&&!i->second.syn) {
226        std::ostringstream cstr;
227        cstr << ' ';
228        if(!i->second.mandatory) cstr << '[';
229        show(cstr,i);
230        if(!i->second.mandatory) cstr << ']';
231        if(pos+cstr.str().size()>LINE_LEN) {
232          std::cerr << std::endl << indent;
233          pos=indent.size();
234        }
235        std::cerr << cstr.str();
236        pos+=cstr.str().size();
237      }
238    for(std::vector<OtherArg>::iterator i=_others_help.begin();
239        i!=_others_help.end();++i)
240      {
241        std::ostringstream cstr;
242        cstr << ' ' << i->name;
243     
244        if(pos+cstr.str().size()>LINE_LEN) {
245          std::cerr << std::endl << indent;
246          pos=indent.size();
247        }
248        std::cerr << cstr.str();
249        pos+=cstr.str().size();
250      }
251    std::cerr << std::endl;
252  }
253   
254  void ArgParser::showHelp()
255  {
256    shortHelp();
257    std::cerr << "Where:\n";
258    for(std::vector<OtherArg>::iterator i=_others_help.begin();
259        i!=_others_help.end();++i) showHelp(i);
260    for(Opts::iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i);
261    exit(1);
262  }
263   
264     
265  void ArgParser::unknownOpt(std::string arg)
266  {
267    std::cerr << "\nUnknown option: " << arg << "\n";
268    std::cerr << "\nType '" << _command_name <<
269      " --help' to obtain a short summary on the usage.\n\n";
270    exit(1);
271  }
272   
273  void ArgParser::requiresValue(std::string arg, OptType t)
274  {
275    std::cerr << "Argument '" << arg << "' requires a";
276    switch(t) {
277    case STRING:
278      std::cerr << " string";
279      break;
280    case INTEGER:
281      std::cerr << "n integer";
282      break;
283    case DOUBLE:
284      std::cerr << " floating point";
285      break;
286    default:
287      break;
288    }
289    std::cerr << " value\n\n";
290    showHelp();
291  }
292   
293
294  void ArgParser::checkMandatories()
295  {
296    bool ok=true;
297    for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
298      if(i->second.mandatory&&!i->second.set)
299        {
300          if(ok)
301            std::cerr << _command_name
302                      << ": The following mandatory arguments are missing.\n";
303          ok=false;
304          showHelp(i);
305        }
306    for(Groups::iterator i=_groups.begin();i!=_groups.end();++i)
307      if(i->second.mandatory||i->second.only_one)
308        {
309          int set=0;
310          for(GroupData::Opts::iterator o=i->second.opts.begin();
311              o!=i->second.opts.end();++o)
312            if(_opts.find(*o)->second.set) ++set;
313          if(i->second.mandatory&&!set) {
314            std::cerr << _command_name
315                      << ": At least one of the following arguments is mandatory.\n";
316            ok=false;
317            for(GroupData::Opts::iterator o=i->second.opts.begin();
318                o!=i->second.opts.end();++o)
319              showHelp(_opts.find(*o));
320          }
321          if(i->second.only_one&&set>1) {
322            std::cerr << _command_name
323                      << ": At most one of the following arguments can be given.\n";
324            ok=false;
325            for(GroupData::Opts::iterator o=i->second.opts.begin();
326                o!=i->second.opts.end();++o)
327              showHelp(_opts.find(*o));
328          }
329        }
330    if(!ok) {
331      std::cerr << "\nType '" << _command_name <<
332        " --help' to obtain a short summary on the usage.\n\n";
333      exit(1);
334    }
335  }
336
337  ArgParser &ArgParser::parse()
338  {
339    for(int ar=1; ar<_argc; ++ar) {
340      std::string arg(_argv[ar]);
341      if (arg[0] != '-' || arg.size() == 1) {
342        _file_args.push_back(arg);
343      }
344      else {
345        Opts::iterator i = _opts.find(arg.substr(1));
346        if(i==_opts.end()) unknownOpt(arg);
347        else {
348          if(i->second.syn) i=_opts.find(i->second.help);
349          ParData &p(i->second);
350          if (p.type==BOOL) *p.bool_p=true;
351          else if (p.type==FUNC) p.func_p.p(p.func_p.data);
352          else if(++ar==_argc) requiresValue(arg, p.type);
353          else {
354            std::string val(_argv[ar]);
355            std::istringstream vals(val);
356            switch(p.type) {
357            case STRING:
358              *p.string_p=val;
359              break;
360            case INTEGER:
361              vals >> *p.int_p;
362              break;
363            case DOUBLE:
364              vals >> *p.double_p;
365              break;
366            default:
367              break;
368            }
369            if(p.type!=STRING&&(!vals||!vals.eof()))
370              requiresValue(arg, p.type);
371          }
372          p.set = true;
373        }
374      }
375    }
376    checkMandatories();
377
378    return *this;
379  } 
380   
381}
Note: See TracBrowser for help on using the repository browser.