-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharg.hh
281 lines (249 loc) · 7.61 KB
/
arg.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/* arg.hh
*
* Copyright (C) 2010,2018 Chun-Chung Chen <cjj@u.washington.edu>
*
* This file is part of arg.
*
* arg is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with arg. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <vector>
#include <string>
#include <sstream>
#include <typeinfo>
#include <memory>
namespace arg {
/// proxy to values of command line options, need to know where to store the values
class Value
{
public:
virtual ~Value();
virtual void set(std::string const & str); ///<convert the str to value and put it in storage
virtual std::string to_str() const; ///<convert the value to a string
virtual std::string get_type() const; ///<type name of the value
};
/// signature for callback functions
typedef bool (CallBack)(int, std::string const &, void *);
/// options to be parsed
class Option
{
int key;
std::string name;
std::shared_ptr<Value> store_ptr; ///<pointer to storage space
bool store_optional; ///<if value string is optional
std::string store_str; ///<default value string
bool * set_bool;
bool bool_value;
int * set_var; ///<variable to set
int set_value; ///<value to set
bool set_once; ///<if can only set once
int set_init; ///<initial value,
CallBack * call_func; ///<callback function
void * call_data; ///<data to pass to callback function
std::string help_text;
std::string help_var;
bool help_default; ///<whether to show default value of store
public:
/// command-line option with key and name
Option(
int key, ///< unique single character key for the option
std::string const & name ///<name for the option
);
~Option();
// option modifiers
template<typename T> Option & stow(T & t); ///<stow value to streamable variable
Option & store(std::shared_ptr<Value> ptr = 0); ///<store value to "* ptr", the Value will be released by the Option
Option & optional(std::string const & str = ""); ///<value is optional defaulting to "str"
Option & set(int * var, int value = - 1); ///<set "* var" to "value"
Option & set(bool & var, bool value = true); ///<set "* var" to "value"
Option & once(int init = 0); ///<can only be set once, with distinct value, "init"
Option & call(CallBack * func, void * data); ///<call function "* func" with "data" as extra argument
Option & help(std::string const & text, std::string const & var = ""); ///<help text
Option & help_word(std::string const & var); ///<help word
Option & show_default(bool do_show = true); ///<show default value in help
bool take_value();
bool need_value();
int get_key();
std::string const & get_name();
enum HelpFormat {
HF_REGULAR,
HF_NODASH
};
std::string get_help(HelpFormat format = HF_REGULAR);
void process();
void process(std::string const & str);
};
/// Positional arguments on command line
class Argument
{
std::string name;
std::shared_ptr<Value> store_ptr; ///<pointer to storage space
std::string help_text;
public:
/// positional argument with name
Argument(
std::string const & name ///<name for the argument
);
~Argument();
// option modifiers
template<typename T> Argument & stow(T & t); ///<stow value to streamable variable
Argument & store(std::shared_ptr<Value> ptr = 0); ///<store value to "* ptr", the Value will be released by the Argument
Argument & help(std::string const & text); ///<help text
std::string const & get_name(); ///<get name of the argument
enum HelpFormat {
HF_REGULAR,
HF_NODASH
};
std::string get_help(); ///<get help text
void process(std::string const & str); ///<process string data
};
/// The command-line parser
class Parser
{
std::string header_text;
std::string version_info;
protected:
std::string prog_name; ///<name to identify the program
std::vector<std::shared_ptr<Option>> opt_list;
std::vector<std::shared_ptr<Argument>> arg_list;
std::vector<std::string> arg_strs;
struct HelpLine {
std::string msg;
std::shared_ptr<Option> opt;
HelpLine(std::string const & m, std::shared_ptr<Option> o);
};
std::vector<HelpLine> help_list;
public:
~Parser();
void add_help(std::string const & msg); ///<add additional help text between option helps
Option & add_opt(int key, std::string const & name = "", bool hide = false); ///<add an Option
Option & add_opt(std::string const & name, bool hide = false); ///<add an Option without a specified key
Option & get_opt(std::string const & name); ///<get an existing Option
std::vector<std::string> & args(); ///<get the argument list
/// perform command-line parsing
void parse(
int argc, ///<count of command-line tokens
char * argv[], ///<c-string array of command-line tokens
bool ignore_unknown = false ///<whether to ignore unknown options
);
void set_header(std::string const & text); ///<set the header in help
std::string const & get_header() const; ///<get the header text of help
// find existing options
std::shared_ptr<Option> find(int key);
std::shared_ptr<Option> find(std::string const & name);
// removing options
void remove(int key);
void remove(std::string const & name);
void remove_all(); // remove all options
std::string get_help();
// default options
Option & add_opt_help();
Option & add_opt_version(std::string const & version);
// positional arguments
Argument & add_arg(std::string const & name);
};
/// A Parser that is a Value itself
class SubParser :
public Value,
public Parser
{
char sep;
public:
SubParser();
void set(std::string const & str); // parse the str
std::string get_help();
void set_sep(char s); // set the separator to s from ','
// default options
Option & add_opt_help();
};
// Errors:
class Error
{
protected:
std::string msg;
public:
Error();
Error(std::string const & msg);
std::string get_msg();
};
class OptError : // option processing error
public Error
{
protected:
std::string opt;
public:
OptError(std::string const & opt);
OptError(std::string const & opt, std::string const & msg);
};
class ConvError : // conversion error
public Error
{
public:
ConvError(std::string const & str, std::string const & type);
};
class UnknError : // unknow option error
public Error
{
public:
UnknError(std::string const & opt);
};
class MissingError : // missing argument
public Error
{
public:
MissingError(std::string const & type);
};
// Templates:
// value types that have << and >> defined for istream/ostream
template <typename T>
class StreamableValue :
public Value
{
T & ptr;
public:
StreamableValue(T & t) :
ptr(t)
{
}
void set(std::string const & str)
{
std::istringstream s(str);
T tmp;
s >> tmp;
if (s.bad() || ! s.eof()) throw ConvError(str, typeid(T).name());
ptr = tmp;
}
std::string to_str() const
{
std::ostringstream s;
s << ptr;
return s.str();
}
std::string get_type() const
{
return typeid(T).name();
}
};
template<typename T>
Option & Option::stow(T & t)
{
return store(std::make_shared<StreamableValue<T>>(t));
}
template<typename T>
Argument & Argument::stow(T & t)
{
return store(std::make_shared<StreamableValue<T>>(t));
}
}