]>
Commit | Line | Data |
---|---|---|
7419f059 RC |
1 | /* |
2 | * Copyright (c) 2002 Robert Collins. | |
6f1abe45 | 3 | * Copyright (c) 2003 Robert Collins. |
7419f059 RC |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * A copy of the GNU General Public License can be found at | |
11 | * http://www.gnu.org/ | |
12 | * | |
13 | * Written by Robert Collins <robertc@hotmail.com> | |
14 | * | |
15 | */ | |
16 | ||
17 | #if HAVE_CONFIG_H | |
18 | #include "autoconf.h" | |
19 | #endif | |
20 | #include "getopt++/OptionSet.h" | |
21 | #include "getopt++/Option.h" | |
20e315e1 | 22 | #include "getopt++/DefaultFormatter.h" |
7419f059 | 23 | |
1ae8e28d | 24 | #include <iostream> |
2e0aaec9 | 25 | #include <algorithm> |
1ae8e28d | 26 | |
e930272e RC |
27 | using namespace std; |
28 | ||
1d644c06 RC |
29 | bool |
30 | OptionSet::isOption(string::size_type pos) const | |
7419f059 | 31 | { |
1d644c06 | 32 | return pos == 1 || pos == 2; |
7419f059 RC |
33 | } |
34 | ||
35 | void | |
1d644c06 | 36 | OptionSet::processOne() |
7419f059 | 37 | { |
1d644c06 RC |
38 | string &option (argv[0]); |
39 | string::size_type pos = option.find_first_not_of("-"); | |
40 | ||
41 | if (!isOption(pos)) { | |
42 | /* Push the non option into storage */ | |
43 | if (nonOptionHandler) { | |
44 | lastResult = nonOptionHandler->Process(option.c_str()); | |
45 | } else { | |
46 | nonoptions.push_back(option); | |
47 | lastResult = Option::Ok; | |
48 | } | |
49 | } else { | |
50 | doOption(option, pos); | |
51 | } | |
7419f059 RC |
52 | } |
53 | ||
1d644c06 RC |
54 | Option * |
55 | OptionSet::findOption(string &option, string::size_type const &pos) const | |
7419f059 | 56 | { |
1d644c06 RC |
57 | Option *theOption = NULL; |
58 | ||
59 | for (std::vector<Option *>::const_iterator i = options.begin(); i != options.end(); | |
60 | ++i) { | |
61 | if (pos == 1) { | |
62 | if (option[0] == (*i)->shortOption()[0]) { | |
63 | theOption = (*i); | |
64 | } | |
65 | } else { | |
66 | /* pos == 2 : todo - prefix matches */ | |
67 | ||
68 | if (option.find((*i)->longOption()) == 0) { | |
69 | theOption = (*i); | |
70 | } | |
71 | } | |
7419f059 | 72 | } |
1d644c06 RC |
73 | return theOption; |
74 | } | |
75 | ||
76 | bool | |
77 | OptionSet::doNoArgumentOption(std::string &option, std::string::size_type const &pos) | |
78 | { | |
79 | if (pos == 1 && option.size() > 1) { | |
80 | /* Parameter when none allowed */ | |
81 | ||
82 | if (option.find("=") == 1) | |
83 | /* How best to provide failure state ? */ | |
84 | return false; | |
85 | ||
86 | argv.insert(argv.begin() + 1,"-" + option.substr(1)); | |
7419f059 | 87 | } |
1d644c06 RC |
88 | |
89 | if (pos == 2) { | |
90 | if (option.find("=") != string::npos) | |
91 | /* How best to provide failure state ? */ | |
92 | return false; | |
7419f059 | 93 | } |
1d644c06 RC |
94 | return true; |
95 | } | |
96 | ||
97 | /* TODO: factor this better */ | |
98 | void | |
99 | OptionSet::doOption(string &option, string::size_type const &pos) | |
100 | { | |
101 | lastResult = Option::Failed; | |
102 | option.erase(0, pos); | |
103 | Option *theOption = findOption(option, pos); | |
104 | char const *optionValue = NULL; | |
dbfe3c19 | 105 | string value; |
1d644c06 RC |
106 | |
107 | if (theOption == NULL) | |
108 | return; | |
109 | ||
110 | switch (theOption->argument()) { | |
111 | ||
112 | case Option::None: | |
113 | if (!doNoArgumentOption (option, pos)) | |
114 | return; | |
115 | break; | |
116 | ||
117 | case Option::Optional: { | |
1d644c06 RC |
118 | if (pos == 1) { |
119 | if (option.size() == 1) { | |
120 | /* Value in next argv */ | |
121 | ||
122 | if (argv.size() > 1) { | |
123 | string::size_type maybepos = argv[1].find_first_not_of("-"); | |
124 | ||
125 | if (!isOption(maybepos)) | |
126 | /* not an option */ | |
127 | value = argv[1]; | |
128 | argv.erase(argv.begin() + 1); | |
129 | } | |
130 | } else { | |
131 | /* value if present is in this argv */ | |
132 | ||
133 | if (option.find ("=") == 1) { | |
134 | /* option present */ | |
135 | value = option.substr(2); | |
136 | } else | |
137 | /* no option present */ | |
138 | argv.insert(argv.begin() + 1,"-" + option.substr(1)); | |
139 | } | |
140 | } | |
141 | ||
142 | if (pos == 2) { | |
143 | string::size_type vpos = option.find("="); | |
144 | ||
145 | if (vpos != string::npos) { | |
146 | /* How best to provide failure state ? */ | |
147 | ||
148 | if (vpos == option.size() - 1) | |
149 | /* blank value */ | |
150 | return; | |
151 | ||
152 | value = option.substr(vpos + 1); | |
153 | } else { | |
154 | /* Value in next argv */ | |
155 | ||
156 | if (argv.size() > 1) { | |
157 | string::size_type maybepos = argv[1].find_first_not_of("-"); | |
158 | ||
159 | if (!isOption(maybepos)) | |
160 | value = argv[1]; | |
161 | argv.erase(argv.begin() + 1); | |
162 | } | |
163 | } | |
164 | } | |
165 | ||
166 | if (value.size()) { | |
167 | optionValue = value.c_str(); | |
7419f059 | 168 | } |
1d644c06 RC |
169 | |
170 | } | |
171 | break; | |
172 | ||
173 | case Option::Required: { | |
1d644c06 RC |
174 | if (pos == 1) { |
175 | if (option.size() == 1) { | |
176 | /* Value in next argv */ | |
177 | ||
178 | if (argv.size() < 2) | |
179 | /* but there aren't any */ | |
180 | return; | |
181 | ||
182 | string::size_type maybepos = argv[1].find_first_not_of("-"); | |
183 | ||
184 | if (isOption(maybepos)) | |
185 | /* The next argv is an option */ | |
186 | return; | |
187 | ||
188 | value = argv[1]; | |
189 | argv.erase(argv.begin() + 1); | |
190 | } else { | |
191 | if (option.find ("=") != 1 || option.size() < 3) | |
192 | /* no option passed */ | |
193 | return; | |
194 | ||
195 | value = option.substr(2); | |
196 | } | |
197 | ||
198 | argv.insert(argv.begin() + 1,"-" + option.substr(1)); | |
199 | } | |
200 | ||
201 | if (pos == 2) { | |
202 | string::size_type vpos = option.find("="); | |
203 | ||
204 | if (vpos != string::npos) { | |
205 | /* How best to provide failure state ? */ | |
206 | ||
207 | if (vpos == option.size() - 1) | |
208 | return; | |
209 | ||
210 | value = option.substr(vpos + 1); | |
211 | } else { | |
212 | /* Value in next argv */ | |
213 | ||
214 | if (argv.size() < 2) | |
215 | /* but there aren't any */ | |
216 | return; | |
217 | ||
218 | string::size_type maybepos = argv[1].find_first_not_of("-"); | |
219 | ||
220 | if (isOption(maybepos)) | |
221 | /* The next argv is an option */ | |
222 | return; | |
223 | ||
224 | value = argv[1]; | |
225 | argv.erase(argv.begin() + 1); | |
226 | } | |
227 | } | |
228 | ||
229 | optionValue = value.c_str(); | |
230 | } | |
231 | break; | |
232 | } | |
233 | lastResult = theOption->Process(optionValue); | |
234 | } | |
235 | ||
236 | OptionSet::OptionSet () {} | |
237 | ||
238 | OptionSet::~OptionSet () | |
239 | {} | |
240 | ||
241 | void | |
242 | OptionSet::Init() | |
243 | { | |
244 | options = std::vector<Option *> (); | |
245 | argv = std::vector<string> (); | |
246 | nonoptions = std::vector<string> (); | |
247 | remainingargv = std::vector<string> (); | |
248 | nonOptionHandler = NULL; | |
249 | } | |
250 | ||
251 | bool | |
252 | OptionSet::process (Option *aNonOptionHandler) | |
253 | { | |
254 | nonOptionHandler = aNonOptionHandler; | |
255 | if (options.size() == 0 && nonOptionHandler == NULL) | |
256 | return false; | |
257 | ||
258 | while (argv.size()) { | |
259 | processOne(); | |
260 | switch (lastResult) { | |
261 | ||
262 | case Option::Failed: | |
263 | return false; | |
264 | ||
265 | case Option::Ok: | |
266 | argv.erase(argv.begin()); | |
267 | break; | |
268 | ||
269 | case Option::Stop: | |
270 | if (argv.size() > 1) { | |
271 | // dies: copy(argv.begin() + 1, argv.end(), remainingargv.begin()); | |
272 | for (std::vector<string>::iterator i = argv.begin() + 1; i != argv.end(); ++i) | |
273 | remainingargv.push_back(*i); | |
7419f059 | 274 | } |
1d644c06 RC |
275 | return true; |
276 | } | |
7419f059 | 277 | } |
1d644c06 RC |
278 | |
279 | return true; | |
280 | } | |
281 | ||
282 | bool | |
283 | OptionSet::Process (int argc, char **argV, Option *nonOptionHandler) | |
284 | { | |
285 | if (argc == 1) { | |
286 | return true; | |
287 | } | |
288 | ||
289 | argv.clear(); | |
290 | nonoptions.clear(); | |
291 | remainingargv.clear(); | |
292 | ||
293 | for (int counter = 1; counter < argc; ++counter) | |
294 | argv.push_back(string(argV[counter])); | |
295 | ||
296 | return process(nonOptionHandler); | |
297 | } | |
298 | ||
299 | bool | |
300 | OptionSet::Process (std::vector<std::string> const &parms, Option *nonOptionHandler) | |
301 | { | |
302 | if (parms.size() == 0) | |
303 | return true; | |
304 | argv = parms; | |
305 | nonoptions.clear(); | |
306 | remainingargv.clear(); | |
307 | return process(nonOptionHandler); | |
7419f059 RC |
308 | } |
309 | ||
310 | //FIXME: check for conflicts. | |
311 | void | |
312 | OptionSet::Register (Option * anOption) | |
313 | { | |
6f1abe45 | 314 | options.push_back(anOption); |
7419f059 | 315 | } |
1ae8e28d | 316 | |
1ae8e28d RC |
317 | void |
318 | OptionSet::ParameterUsage (ostream &aStream) | |
319 | { | |
1d644c06 | 320 | for_each (options.begin(), options.end(), DefaultFormatter (aStream)); |
1ae8e28d | 321 | } |
6f1abe45 RC |
322 | |
323 | std::vector<Option *> const & | |
324 | OptionSet::optionsInSet() const | |
325 | { | |
326 | return options; | |
327 | } | |
1d644c06 RC |
328 | |
329 | std::vector<string> const & | |
330 | OptionSet::nonOptions() const | |
331 | { | |
332 | return nonoptions; | |
333 | } | |
334 | ||
335 | std::vector<string> const & | |
336 | OptionSet::remainingArgv() const | |
337 | { | |
338 | return remainingargv; | |
339 | } |