SHORE API
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
av_parser.hpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright 2008,2009,2010,2011,2012 Stephan Ossowski, Korbinian Schneeberger,
4  * Felix Ott, Joerg Hagmann, Alf Scotland, Sebastian Bender
5  *
6  * This file is part of SHORE.
7  *
8  * SHORE is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * SHORE is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with SHORE. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
25 
26 #ifndef SHORE_PROGRAM_AV_PARSER_HPP__
27 #define SHORE_PROGRAM_AV_PARSER_HPP__
28 
29 #include <map>
30 #include <set>
31 #include <stdexcept>
32 #include <string>
33 #include <utility>
34 #include <vector>
35 
36 #include <unistd.h>
37 #include <getopt.h>
38 
39 #include "shore/base/stringops.hpp"
40 #include "shore/datatype/coor.hpp"
41 #include "shore/base/mathops.hpp"
42 
43 #include <boost/utility/enable_if.hpp>
44 #include <boost/type_traits.hpp>
45 
46 namespace shore {
47 
50 {
59 };
60 
61 S_MAKE_ENUM_TRAITS(OptionFlags)
62 
63 struct opt_base
65 {
67  char shortopt;
69  std::string longopt;
71  std::string id;
73  std::string label;
74 
75  bool is_switch;
76  bool multiple;
77  OptionFlags arg_default;
79  std::string info;
81  std::string aux_info;
82 
83  opt_base(const char sh,const std::string& lo);
84 
85  bool is_option() const;
86 
87  virtual ~opt_base() {}
88 
90  virtual void *ptr() const=0;
91 
93  virtual void store_arg(const char*const sval,const bool clear_arg)=0;
94 
96  virtual std::string argdefault_string() const=0;
97 
99  virtual std::string arg_format() const=0;
100 };
101 
102 template<typename T>
103 std::string typestr(const T *const value,
104  typename boost::disable_if<boost::is_integral<T> >::type *dummy_int=0,
105  typename boost::disable_if<boost::is_float<T> >::type *dummy_float=0)
106 {
107  return "STRING";
108 }
109 
110 template<typename T>
111 std::string typestr(const T *const value,
112  typename boost::enable_if<boost::is_integral<T> >::type *dummy_int=0)
113 {
114  return "INT";
115 }
116 
117 template<typename T>
118 std::string typestr(const T *const value,
119  typename boost::enable_if<boost::is_float<T> >::type *dummy_float=0)
120 {
121  return "FLOAT";
122 }
123 
124 inline std::string typestr(const char *value)
125 {
126  return "CHAR";
127 }
128 
129 template<typename T>
130 std::string typestr(const shore::relabs<T> *const value)
131 {
132  return typestr((T*)0)+"[%]";
133 }
134 
135 template<typename T>
136 std::string typestr(const std::vector<T> *const value)
137 {
138  return typestr((T*)0)+"[,...]";
139 }
140 
141 template<typename T>
142 std::string typestr(const std::vector<std::vector<T> >*const value)
143 {
144  return typestr((T*)0)+"[:...][,...]";
145 }
146 
147 template<typename T>
148 std::string typestr(const std::set<T> *const value)
149 {
150  return typestr((T*)0)+"[,...]";
151 }
152 
156 template<typename T>
157 struct opt_base1
158 :public opt_base
159 {
160  T* valueptr;
161 
162  opt_base1(const char sh,const std::string& lo,T*const ptr)
163  :opt_base(sh,lo),valueptr(ptr)
164  {}
165 
166  virtual void *ptr() const
167  {
168  return valueptr;
169  }
170 
171  virtual std::string arg_format() const
172  {
173  return typestr((T*)0);
174  }
175 };
176 
178 template<typename T>
179 struct opt_base2
180 :public opt_base1<T>
181 {
182  opt_base2(const char sh,const std::string& lo,T*const ptr)
183  :opt_base1<T>(sh,lo,ptr)
184  {}
185 
186  virtual void store_arg(const char*const sval,const bool clear_arg)
187  {
189  }
190 
191  virtual std::string argdefault_string() const
192  {
194  }
195 };
196 
198 template<class T>
199 struct av_option
200 :public opt_base2<T>
201 {
202  av_option(const char sh,const std::string& lo,T*const ptr)
203  :opt_base2<T>(sh,lo,ptr)
204  {}
205 };
206 
208 
213 {
214  public:
215 
218  struct usage_error
219  :public std::runtime_error
220  {
221  usage_error(const std::string& m=std::string());
222  };
223 
224  private:
225 
227  struct opt_cmp
228  {
229  opt_base* o1;
230  opt_cmp(opt_base* o);
231  bool operator()(opt_base*const o2);
232  };
233 
234  // setup variables
236  bool m_posixly_correct;
237 
239  std::string m_currentGroup;
240 
242  std::vector<opt_base *> m_options;
243 
244  std::vector<std::string> m_groupnames;
245  std::map<std::string,std::vector<const opt_base *> > m_opt_groups;
246 
248  std::vector<opt_base *> m_residualargs;
249  std::vector<std::string> m_residualarg_names;
250 
252  std::map<const opt_base *,std::set<const opt_base *> > m_conflicts;
254  std::map<const opt_base *,std::set<const opt_base *> > m_requirements;
255 
257  std::map<std::string,opt_base *> m_havespec;
259  std::map<std::string,std::set<const opt_base *> > m_needspec_con;
261  std::map<std::string,std::set<const opt_base *> > m_needspec_req;
263  std::map<std::string,std::set<const opt_base *> > m_needspec_revreq;
265  std::map<std::string,size_t> m_needspec_residual;
266 
267  // used by operator() / parse_conffile()
269  std::set<const opt_base *> m_parsedOptions;
271  std::set<const void *> m_alteredValues;
272 
275  std::map<const opt_base *,std::set<const opt_base *> > m_required;
276 
279  std::map<const opt_base *,std::set<const opt_base *> > m_forbidden;
280 
281 
283  int m_ac;
285  char** m_av;
287  int m_new_ac;
289  char** m_new_av;
290 
291 
293  bool m_have_aux_info;
294 
296  av_parser(const av_parser&);
297 
299  void setup_dependencies(
300  opt_base *const opt,const std::string &conflicts_with);
301 
304  std::set<const opt_base *> alternative_dependencies(
305  const opt_base *opt,const opt_base *requiredby);
306 
308  void consistency_check();
309 
311  void update_dependencies(const opt_base *const opt);
312 
313  public:
314 
315  av_parser();
316  ~av_parser();
317 
319  void set_posixly_correct(const bool p);
320 
322  std::string set_optiongroup(const std::string &grp=std::string());
323 
325  template<class T>
326  void add_option(const std::string &longshort,
327  T *target,
328  const std::string &info,
329  const std::string &aux_info=std::string())
330  {
331  add_option(longshort,"",target,info,OPT_SET,aux_info);
332  }
333 
335  template<class T>
336  void add_option(const std::string& longshort,
337  T* target,
338  const std::string &info,
339  const OptionFlags def,
340  const std::string &aux_info=std::string())
341  {
342  add_option(longshort,"",target,info,def,aux_info);
343  }
344 
346  template<class T>
347  void add_option(const std::string &longshort,
348  const std::string &conflicts_with,
349  T *target,
350  const std::string &info,
351  const std::string &aux_info=std::string())
352  {
353  add_option(longshort,conflicts_with,target,info,OPT_SET,aux_info);
354  }
355 
357  template<class T>
358  void add_option(const std::string &longshort,
359  const std::string &conflicts_with,
360  T *target,
361  const std::string &info,
362  const OptionFlags def,
363  const std::string &aux_info=std::string())
364  {
365  std::vector<std::string> tok=shore::split(longshort,',');
366 
367  av_option<T>* opt;
368 
369  if(tok.size()==1)
370  opt=new av_option<T>(char(0),tok[0],target);
371  else if((tok.size()==2)&&(tok[1].size()==1))
372  opt=new av_option<T>(tok[1][0],tok[0],target);
373  else
374  throw std::logic_error("invalid option specification");
375 
376  const std::vector<opt_base *>::const_iterator conflspec=
377  std::find_if(m_options.begin(),m_options.end(),opt_cmp(opt));
378 
379  if(conflspec!=m_options.end())
380  throw std::logic_error("multiple or conflicting option"
381  " specification: "
382  +opt->label+" <-> "+(*conflspec)->label);
383 
384  opt->info=info;
385  opt->aux_info=aux_info;
386  opt->arg_default=def;
387 
388  setup_dependencies(opt,conflicts_with);
389 
390  m_options.push_back(opt);
391 
392  if(!(aux_info.empty()||m_currentGroup.empty()))
393  m_have_aux_info=true;
394 
395  if(m_opt_groups[m_currentGroup].empty())
396  m_groupnames.push_back(m_currentGroup);
397 
398  m_opt_groups[m_currentGroup].push_back(opt);
399  }
400 
402  template<typename T>
403  void add_residualargs(T *const target,
404  const std::string &name,
405  const OptionFlags def)
406  {
407  add_residualargs(target,name,"",def);
408  }
409 
411  template<typename T>
412  void add_residualargs(T *const target,
413  const std::string &name,
414  const std::string &conflicts_with=std::string(),
415  const OptionFlags def=OPT_NOTSET,
416  typename boost::disable_if<boost::is_const<T> >::type *dummy=0)
417  {
418  m_residualargs.push_back(new av_option<T>(char(0),"",target));
419  m_residualargs.back()->arg_default=def;
420  m_residualargs.back()->id='@'+name;
421  m_residualargs.back()->label=name;
422  m_residualarg_names.push_back(name);
423 
424  setup_dependencies(m_residualargs.back(),conflicts_with);
425  }
426 
428  void add_residualargs(const std::string &opt_id,const std::string &name);
429 
431  bool allows_options() const;
432 
434  bool allows_residualargs() const;
435 
437  bool have_aux_info() const;
438 
440  void operator()(int ac,char* av[]);
441 
443  void parse_conffile(const std::string &fn,const std::string &section,
444  const std::set<std::string> &noinclude=std::set<std::string>());
445 
447  void dependency_check();
448 
450  int get_argc() const;
451 
453  char **get_argv() const;
454 
456  int get_residual_argc() const;
457 
459  char **get_residual_argv() const;
460 
463  bool is_altered(const void*const ptr) const;
464 
465  void set_altered(const void*const ptr);
466 
468  size_t num_altered() const;
469 
470  enum SummaryType
471  {
472  SUMMARY_STD,
473  SUMMARY_COMPACT,
474  SUMMARY_VERBOSE
475  };
476 
478  std::string get_optionsummary(const SummaryType typ=SUMMARY_STD) const;
479 
481  std::string get_usagestring() const;
482 };
483 
485 
487 template<class T,class U>
488 struct av_option<std::pair<T,U> >
489 :public opt_base1<std::pair<T,U> >
490 {
491  av_option(const char sh,const std::string& lo,std::pair<T,U>*const ptr)
492  :opt_base1<std::pair<T,U> >(sh,lo,ptr)
493  {}
494 
495  virtual void store_arg(const char*const sval,const bool clear_arg)
496  {
497  const std::vector<std::string> svv=shore::split(sval,',');
498 
499  if(svv.size()!=2)
500  throw std::runtime_error(
501  "arg is an invalid pair"\
502  " - exactly two values separated by a comma required");
503 
504  opt_base1<std::pair<T,U> >::valueptr->first=shore::parse_value<T>(svv[0]);
505  opt_base1<std::pair<T,U> >::valueptr->second=shore::parse_value<U>(svv[1]);
506  }
507 
508  virtual std::string argdefault_string() const
509  {
510  return shore::to_string(opt_base1<std::pair<T,U> >::valueptr->first,6)
511  +","+shore::to_string(opt_base1<std::pair<T,U> >::valueptr->second,6);
512  }
513 
514  virtual std::string arg_format() const
515  {
516  return typestr((T*)0)+','+typestr((U*)0);
517  }
518 };
519 
521 template<class T>
522 struct av_option<std::vector<T> >
523 :public opt_base1<std::vector<T> >
524 {
525  av_option(const char sh,const std::string& lo,std::vector<T>*const ptr)
526  :opt_base1<std::vector<T> >(sh,lo,ptr)
527  {
528  opt_base1<std::vector<T> >::multiple=true;
529  }
530 
531  virtual void store_arg(const char*const sval,const bool clear_arg)
532  {
533  // temporary result, only store if parsing succeeds
534  const T parsed=shore::parse_value<T>(sval);
535 
536  if(clear_arg) opt_base1<std::vector<T> >::valueptr->clear();
537  opt_base1<std::vector<T> >::valueptr->push_back(parsed);
538  }
539 
540  virtual std::string argdefault_string() const
541  {
542  return shore::join(*opt_base1<std::vector<T> >::valueptr,",");
543  }
544 };
545 
547 template<class T>
548 struct av_option<std::set<T> >
549 :public opt_base1<std::set<T> >
550 {
551  av_option(const char sh,const std::string& lo,std::set<T>*const ptr)
552  :opt_base1<std::set<T> >(sh,lo,ptr)
553  {
554  opt_base1<std::set<T> >::multiple=true;
555  }
556 
557  virtual void store_arg(const char*const sval,const bool clear_arg)
558  {
559  // temporary result, only store if parsing succeeds
560  const T parsed=shore::parse_value<T>(sval);
561 
562  if(clear_arg) opt_base1<std::set<T> >::valueptr->clear();
563  opt_base1<std::set<T> >::valueptr->insert(parsed);
564  }
565 
566  virtual std::string argdefault_string() const
567  {
568  return shore::join(opt_base1<std::set<T> >::valueptr->begin(),
569  opt_base1<std::set<T> >::valueptr->end(),",");
570  }
571 };
572 
574 template<class T>
575 struct av_option<std::vector<std::vector<T> > >
576 :public opt_base1<std::vector<std::vector<T> > >
577 {
578  av_option(const char sh,const std::string& lo,
579  std::vector<std::vector<T> >*const ptr)
581  {
582  opt_base1<std::vector<std::vector<T> > >::multiple=true;
583  }
584 
585  virtual void store_arg(const char*const sval,const bool clear_arg)
586  {
587  // temporary results, only store if parsing succeeds
588  const std::vector<std::string> items=shore::split(sval,':');
589  std::vector<T> iv;
590 
591  for(size_t j=0;j<items.size();++j)
592  {
593  if(!items[j].empty()) iv.push_back(shore::parse_value<T>(items[j]));
594  }
595 
596  if(clear_arg) opt_base1<std::vector<std::vector<T> > >::valueptr->clear();
597  opt_base1<std::vector<std::vector<T> > >::valueptr->push_back(iv);
598  }
599 
600  virtual std::string argdefault_string() const
601  {
602  std::vector<std::string> ret;
603  for(size_t i=0;i<opt_base1<std::vector<std::vector<T> > >::valueptr->size();++i)
604  ret.push_back(shore::join((*opt_base1<std::vector<std::vector<T> > >::valueptr)[i],":"));
605  return shore::join(ret,",");
606  }
607 };
608 
610 template<>
611 struct av_option<bool>
612 :public opt_base2<bool>
613 {
614  av_option(const char sh,const std::string& lo,bool*const ptr)
615  :opt_base2<bool>(sh,lo,ptr)
616  {
618  }
619 
620  virtual void store_arg(const char*const sval,const bool clear_arg)
621  {
622  if(sval==0) (*opt_base2<bool>::valueptr)=true;
623  else opt_base2<bool>::store_arg(sval,clear_arg);
624  }
625 
626  virtual std::string argdefault_string() const
627  {
628  return (*opt_base2<bool>::valueptr)?"*":"";
629  }
630 };
631 
632 struct unary
633 {
634  int n;
635  unary(): n(0) {}
636 
637  unary(const int k): n(k) {}
638 
639  unary(const bool b): n(b?1:0) {}
640 
641  operator bool() const
642  {
643  return n>0;
644  }
645 
646  operator int() const
647  {
648  return n;
649  }
650 };
651 
653 template<>
654 struct av_option<unary>
655 :public opt_base1<unary>
656 {
657  av_option(const char sh,const std::string& lo,unary*const ptr)
658  :opt_base1<unary>(sh,lo,ptr)
659  {
662  }
663 
664  virtual void store_arg(const char*const sval,const bool clear_arg)
665  {
666  if(clear_arg) opt_base1<unary>::valueptr->n=0;
667  if(sval==0) ++(opt_base1<unary>::valueptr->n);
669  }
670 
671  virtual std::string argdefault_string() const
672  {
673  return ((opt_base1<unary>::valueptr->n)>0)?
674  std::string(opt_base1<unary>::valueptr->n,'*'):"";
675  }
676 };
677 
678 } // namespace shore
679 
680 #endif // SHORE_PROGRAM_AV_PARSER_HPP__
681