]> git.tdb.fi Git - libs/core.git/blob - source/core/getopt.h
Improve GetOpt help generation
[libs/core.git] / source / core / getopt.h
1 /* $Id$
2
3 This file is part of libmspcore
4 Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7 #ifndef MSP_CORE_GETOPT_H_
8 #define MSP_CORE_GETOPT_H_
9
10 #include <sstream>
11 #include <string>
12 #include <vector>
13 #include "except.h"
14
15 namespace Msp {
16
17 class GetOpt
18 {
19 public:
20         enum ArgType
21         {
22                 NO_ARG,
23                 OPTIONAL_ARG,
24                 REQUIRED_ARG
25         };
26         
27         class OptBase
28         {
29         public:
30                 OptBase           &set_help(const std::string &);
31                 OptBase           &set_help(const std::string &, const std::string &);
32                 char              get_short() const               { return shrt; }
33                 const std::string &get_long() const               { return lng; }
34                 ArgType           get_arg_type() const            { return arg_type; }
35                 const std::string &get_help() const               { return help; }
36                 const std::string &get_metavar() const            { return metavar; }
37                 unsigned          get_seen_count() const          { return seen_count; }
38                 virtual void      process()=0;
39                 virtual void      process(const std::string &)=0;
40                 virtual ~OptBase() { }
41         protected:
42                 char        shrt;
43                 std::string lng;
44                 ArgType     arg_type;
45                 unsigned    seen_count;
46                 std::string help;
47                 std::string metavar;
48
49                 OptBase(char, const std::string &, ArgType);
50         };
51
52 private:
53         template<typename T>
54         class Option: public OptBase
55         {
56         public:
57                 Option(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d) { }
58
59                 virtual void process()
60                 {
61                         if(arg_type==REQUIRED_ARG)
62                                 throw UsageError("--"+lng+" requires an argument");
63                         process_();
64                         ++seen_count;
65                 }
66
67                 virtual void process(const std::string &a)
68                 {
69                         if(arg_type==NO_ARG)
70                                 throw UsageError("--"+lng+" takes no argument");
71
72                         T tmp;
73                         std::istringstream ss(a);
74                         ss>>tmp;
75                         if(ss.fail())
76                                 throw UsageError("Invalid argument for --"+lng);
77
78                         data=tmp;
79                         ++seen_count;
80                 }
81         private:
82                 T &data;
83
84                 void process_() { }
85         };
86
87         template<typename T>
88         class ListOption: public OptBase
89         {
90         public:
91                 ListOption(char s, const std::string &l, T &d, ArgType a): OptBase(s, l, a), data(d)
92                 { if(arg_type!=REQUIRED_ARG) throw Exception("ListOption with arg_type!=REQUIRED makes no sense"); }
93
94                 virtual void process()
95                 {
96                         throw UsageError("--"+lng+" requires an argument");
97                 }
98
99                 virtual void process(const std::string &a)
100                 {
101                         typename T::value_type tmp;
102                         std::istringstream ss(a);
103                         ss>>tmp;
104                         if(ss.fail())
105                                 throw UsageError("Invalid argument for --"+lng);
106
107                         data.push_back(tmp);
108                         ++seen_count;
109                 }
110         private:
111                 T &data;
112         };
113
114         std::list<OptBase *> opts;
115         std::vector<std::string> args;
116
117 public:
118         ~GetOpt();
119
120         const std::vector<std::string> &get_args() const { return args; }
121
122         template<typename T>
123         OptBase &add_option(char s, const std::string &l, T &d, ArgType a=NO_ARG)
124         { opts.push_back(new Option<T>(s, l, d, a)); return *opts.back(); }
125         
126         template<typename T>
127         OptBase &add_option(char s, const std::string &l, std::list<T> &d, ArgType a=REQUIRED_ARG)
128         { opts.push_back(new ListOption<std::list<T> >(s, l, d, a)); return *opts.back(); }
129         
130         template<typename T>
131         OptBase &add_option(const std::string &l, T &d, ArgType a)
132         { return add_option(0, l, d, a); }
133
134         std::string generate_usage(const std::string &) const;
135         std::string generate_help() const;
136         void operator()(unsigned, const char *const *);
137 private:
138
139         OptBase &get_option(char);
140         OptBase &get_option(const std::string &);
141         unsigned process_long(const char *const *);
142         unsigned process_short(const char *const *);
143 };
144
145 template<> inline void GetOpt::Option<bool>::process_()     { data=true; }
146 template<> inline void GetOpt::Option<unsigned>::process_() { ++data; }
147
148 } // namespace Msp
149
150 #endif