forked from winkj/httpup
-
Notifications
You must be signed in to change notification settings - Fork 1
/
argparser.h
242 lines (194 loc) · 6.83 KB
/
argparser.h
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
////////////////////////////////////////////////////////////////////////
// FILE: argparser.h
// AUTHOR: Johannes Winkelmann, jw@tks6.net
// COPYRIGHT: (c) 2004 by Johannes Winkelmann
// ---------------------------------------------------------------------
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
////////////////////////////////////////////////////////////////////////
#ifndef _ARGPARSER_H_
#define _ARGPARSER_H_
#include <map>
#include <vector>
#include <string>
// TODO:
// -- important
// - allow multiple occurences of arguments:
// prt-get --config-append="..." --config-append="..."
// - Allow global --help, --usage
// - check for duplicate entries
// -- nice to have
// 2. allow optional values for args, like --with-gtk[=DIR]
// 4. improve predefined commands: allow descriptions even for such
// 7. Add predefined --version, show in usage; add Contact text
// 8. Allow disabling of predefined options
// 9. make parseError more convenient (passing cmd->name all over...)
class APOpt;
class APCmd;
/**
* \brief argument parser class
*
* Yet another argument parser, meant to speed up development of new
* applications. Its focus is on being object oriented and safe to use
*/
class ArgParser
{
public:
/**
* types of argument number checking
*/
enum ArgNumberCheck { NONE, MIN, EQ, MAX };
/*
* APOpt and APCmd are the classes used in client code, to make
* efficient comparison of the selected command.
*
* In addition, it's currently mainly for programs which use a
* command syntax, much like CVS
*/
class APOpt
{
public:
friend class ArgParser;
APOpt() : id(-1), m_initialized(false) {}
bool operator ==(const APOpt& other) const { return other.id == id; }
void init(const std::string& longName,
char shortName,
const std::string& description,
const bool valueRequired=false,
const std::string& valueName="") {
m_initialized = true;
m_longName = longName;
m_shortName = shortName;
m_description = description;
m_valueRequired = valueRequired;
m_valueName = valueName;
}
private:
int id;
std::string m_longName;
char m_shortName;
std::string m_description;
bool m_valueRequired;
std::string m_valueName;
bool m_initialized;
};
class APCmd
{
public:
friend class ArgParser;
APCmd() : id(-1) {}
bool operator ==(const APCmd& other) const { return other.id == id; }
private:
int id;
};
private:
// internal representation of options and commands
class Option
{
public:
int id;
std::string description;
char shortName;
std::string longName;
bool requiresValue;
std::string valueName;
};
class Command
{
public:
int id;
std::string name;
std::string description;
ArgNumberCheck argNumberCheck;
unsigned int argNumber;
std::string otherArguments;
std::map<int, Option*> mandatoryOptions;
std::map<int, Option*> options;
ArgParser::APCmd* apCmd;
};
public:
ArgParser();
virtual ~ArgParser();
/**
* add a command
*
* \param cmd a reference to the command; use it to compare the actually selected command against this one after parsing
* \param name the name of the command to be parsed from the command line
* \param description a description, used for the help screens
* \param argNumberCheck what kind of argument number checking
* \param argNumber optional number of arguments
* \param otherOptions value to display in the help screen for following (non option) arguments
*/
int addCommand(APCmd& cmd,
const std::string& name,
const std::string& description,
ArgNumberCheck argNumberCheck,
const int argNumber=-1,
const std::string& otherArguments="");
/**
* add an option to a command - this will fail with an assertion
* of \a key has not been initialized using init()
*
* \param cmd the command to add an option to
* \param key the option reference; use it to check for certain options after parsing
* \param required whether this option is required
* \param longName the long name of this command (to be used with '--'); leave it empty if you don't want to use a long option name
* \param shortName the short name of this command (to be used with '-'); pass 0 if you don't want to use a short option name
* \param description the description of this option, to be used in the help screen
* \param valueRequired whether this option requires a value
* \param valueName the name of the value, to be used in the help screen
*/
int addOption(const APCmd& cmd,
APOpt& key,
bool required);
/**
* the actual parsing. Highly recommended :-)
*/
void parse(int argc, char** argv);
/**
* the command which was parsed, to be used to compare against
* actual APCmd obtained from addCommand calls
*/
APCmd command() const;
/**
* the name of the application, from argv[0]
*/
std::string appName() const;
/**
* \return true if \a key is set, false otherwise
*/
bool isSet(const APOpt& key) const;
/**
* \return the value attached to the option \key if any
*/
std::string getOptionValue(const APOpt& key) const;
/**
* the remaining arguments
*/
const std::vector<std::string>& otherArguments() const;
/**
* \return an application identification to be used in the usage
*/
virtual std::string getAppIdentification() const { return ""; }
private:
std::string generateHelpForCommand(const std::string& command) const;
std::string generateUsage() const;
bool isSet(int key) const;
std::string generateOptionString(Option* o) const;
void parseError(const std::string& error, const std::string& cmd="") const;
std::map<std::string, Command*> m_commands;
std::map<int, Command*> m_commandIdMap;
std::map<int, Option*> m_options;
std::map<char, Option*> m_optionsByShortName;
std::map<std::string, Option*> m_optionsByLongName;
std::map<int, std::string> m_setOptions;
std::vector<std::string> m_otherArguments;
APCmd m_command;
std::string m_appName;
int m_cmdIdCounter;
int m_optIdCounter;
APOpt PREDEFINED_CMD_HELP;
};
#endif /* _ARGPARSER_H_ */