]>
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 | |
1d644c06 | 27 | bool |
155eacb6 | 28 | OptionSet::isOption(std::string::size_type pos) const |
7419f059 | 29 | { |
1d644c06 | 30 | return pos == 1 || pos == 2; |
7419f059 RC |
31 | } |
32 | ||
33 | void | |
1d644c06 | 34 | OptionSet::processOne() |
7419f059 | 35 | { |
155eacb6 AG |
36 | std::string &option (argv[0]); |
37 | std::string::size_type pos = option.find_first_not_of("-"); | |
1d644c06 RC |
38 | |
39 | if (!isOption(pos)) { | |
40 | /* Push the non option into storage */ | |
8effde7a JT |
41 | if (nonOptionHandler) { |
42 | lastResult = nonOptionHandler->Process(option.c_str(), 0); | |
43 | } else { | |
44 | nonoptions.push_back(option); | |
45 | lastResult = Option::Ok; | |
46 | } | |
1d644c06 | 47 | } else { |
8effde7a | 48 | doOption(option, pos); |
1d644c06 | 49 | } |
7419f059 RC |
50 | } |
51 | ||
8effde7a JT |
52 | void |
53 | OptionSet::findOption(std::string &option, std::string::size_type const &pos, | |
54 | Option *&theOption, int & prefixIndex) const | |
7419f059 | 55 | { |
8effde7a JT |
56 | theOption = NULL; |
57 | prefixIndex = 0; | |
1d644c06 RC |
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); | |
8effde7a | 64 | return; |
1d644c06 RC |
65 | } |
66 | } else { | |
8effde7a JT |
67 | /* pos == 2 */ |
68 | std::vector<std::string> prefixes = (*i)->longOptionPrefixes(); | |
69 | for (std::vector<std::string>::const_iterator j = prefixes.begin(); | |
70 | j != prefixes.end(); | |
71 | j++) | |
72 | { | |
73 | std::string prefixedOption = *j + (*i)->longOption(); | |
74 | if (option.find(prefixedOption) == 0) { | |
1d644c06 | 75 | theOption = (*i); |
8effde7a JT |
76 | prefixIndex = j - prefixes.begin(); |
77 | return; | |
78 | } | |
1d644c06 RC |
79 | } |
80 | } | |
7419f059 | 81 | } |
1d644c06 RC |
82 | } |
83 | ||
84 | bool | |
85 | OptionSet::doNoArgumentOption(std::string &option, std::string::size_type const &pos) | |
86 | { | |
87 | if (pos == 1 && option.size() > 1) { | |
88 | /* Parameter when none allowed */ | |
89 | ||
90 | if (option.find("=") == 1) | |
91 | /* How best to provide failure state ? */ | |
92 | return false; | |
93 | ||
94 | argv.insert(argv.begin() + 1,"-" + option.substr(1)); | |
7419f059 | 95 | } |
1d644c06 RC |
96 | |
97 | if (pos == 2) { | |
155eacb6 | 98 | if (option.find("=") != std::string::npos) |
1d644c06 RC |
99 | /* How best to provide failure state ? */ |
100 | return false; | |
7419f059 | 101 | } |
1d644c06 RC |
102 | return true; |
103 | } | |
104 | ||
105 | /* TODO: factor this better */ | |
106 | void | |
155eacb6 | 107 | OptionSet::doOption(std::string &option, std::string::size_type const &pos) |
1d644c06 RC |
108 | { |
109 | lastResult = Option::Failed; | |
110 | option.erase(0, pos); | |
8effde7a JT |
111 | Option *theOption = NULL; |
112 | int prefixIndex = 0; | |
113 | findOption(option, pos, theOption, prefixIndex); | |
1d644c06 | 114 | char const *optionValue = NULL; |
155eacb6 | 115 | std::string value; |
1d644c06 RC |
116 | |
117 | if (theOption == NULL) | |
118 | return; | |
119 | ||
120 | switch (theOption->argument()) { | |
121 | ||
122 | case Option::None: | |
8effde7a JT |
123 | if (!doNoArgumentOption (option, pos)) |
124 | return; | |
125 | break; | |
1d644c06 RC |
126 | |
127 | case Option::Optional: { | |
1d644c06 RC |
128 | if (pos == 1) { |
129 | if (option.size() == 1) { | |
130 | /* Value in next argv */ | |
131 | ||
132 | if (argv.size() > 1) { | |
155eacb6 | 133 | std::string::size_type maybepos = argv[1].find_first_not_of("-"); |
1d644c06 | 134 | |
f003c558 | 135 | if (!isOption(maybepos)) { |
1d644c06 RC |
136 | /* not an option */ |
137 | value = argv[1]; | |
138 | argv.erase(argv.begin() + 1); | |
f003c558 | 139 | } |
1d644c06 RC |
140 | } |
141 | } else { | |
142 | /* value if present is in this argv */ | |
143 | ||
144 | if (option.find ("=") == 1) { | |
145 | /* option present */ | |
146 | value = option.substr(2); | |
147 | } else | |
148 | /* no option present */ | |
149 | argv.insert(argv.begin() + 1,"-" + option.substr(1)); | |
150 | } | |
151 | } | |
152 | ||
153 | if (pos == 2) { | |
155eacb6 | 154 | std::string::size_type vpos = option.find("="); |
1d644c06 | 155 | |
155eacb6 | 156 | if (vpos != std::string::npos) { |
1d644c06 RC |
157 | /* How best to provide failure state ? */ |
158 | ||
159 | if (vpos == option.size() - 1) | |
160 | /* blank value */ | |
161 | return; | |
162 | ||
163 | value = option.substr(vpos + 1); | |
164 | } else { | |
165 | /* Value in next argv */ | |
166 | ||
167 | if (argv.size() > 1) { | |
155eacb6 | 168 | std::string::size_type maybepos = argv[1].find_first_not_of("-"); |
1d644c06 | 169 | |
f003c558 | 170 | if (!isOption(maybepos)) { |
1d644c06 RC |
171 | value = argv[1]; |
172 | argv.erase(argv.begin() + 1); | |
f003c558 | 173 | } |
1d644c06 RC |
174 | } |
175 | } | |
176 | } | |
177 | ||
178 | if (value.size()) { | |
179 | optionValue = value.c_str(); | |
7419f059 | 180 | } |
1d644c06 RC |
181 | |
182 | } | |
183 | break; | |
184 | ||
185 | case Option::Required: { | |
1d644c06 RC |
186 | if (pos == 1) { |
187 | if (option.size() == 1) { | |
188 | /* Value in next argv */ | |
189 | ||
190 | if (argv.size() < 2) | |
191 | /* but there aren't any */ | |
192 | return; | |
193 | ||
155eacb6 | 194 | std::string::size_type maybepos = argv[1].find_first_not_of("-"); |
1d644c06 RC |
195 | |
196 | if (isOption(maybepos)) | |
197 | /* The next argv is an option */ | |
198 | return; | |
199 | ||
200 | value = argv[1]; | |
201 | argv.erase(argv.begin() + 1); | |
202 | } else { | |
203 | if (option.find ("=") != 1 || option.size() < 3) | |
204 | /* no option passed */ | |
205 | return; | |
206 | ||
207 | value = option.substr(2); | |
208 | } | |
209 | ||
210 | argv.insert(argv.begin() + 1,"-" + option.substr(1)); | |
211 | } | |
212 | ||
213 | if (pos == 2) { | |
155eacb6 | 214 | std::string::size_type vpos = option.find("="); |
1d644c06 | 215 | |
155eacb6 | 216 | if (vpos != std::string::npos) { |
1d644c06 RC |
217 | /* How best to provide failure state ? */ |
218 | ||
219 | if (vpos == option.size() - 1) | |
220 | return; | |
221 | ||
222 | value = option.substr(vpos + 1); | |
223 | } else { | |
224 | /* Value in next argv */ | |
225 | ||
226 | if (argv.size() < 2) | |
227 | /* but there aren't any */ | |
228 | return; | |
229 | ||
155eacb6 | 230 | std::string::size_type maybepos = argv[1].find_first_not_of("-"); |
1d644c06 RC |
231 | |
232 | if (isOption(maybepos)) | |
233 | /* The next argv is an option */ | |
234 | return; | |
235 | ||
236 | value = argv[1]; | |
237 | argv.erase(argv.begin() + 1); | |
238 | } | |
239 | } | |
240 | ||
241 | optionValue = value.c_str(); | |
242 | } | |
243 | break; | |
b1b204c8 JT |
244 | } |
245 | theOption->setPresent(true); | |
8effde7a | 246 | lastResult = theOption->Process(optionValue, prefixIndex); |
1d644c06 RC |
247 | } |
248 | ||
249 | OptionSet::OptionSet () {} | |
250 | ||
251 | OptionSet::~OptionSet () | |
252 | {} | |
253 | ||
254 | void | |
255 | OptionSet::Init() | |
256 | { | |
257 | options = std::vector<Option *> (); | |
155eacb6 AG |
258 | argv = std::vector<std::string> (); |
259 | nonoptions = std::vector<std::string> (); | |
260 | remainingargv = std::vector<std::string> (); | |
1d644c06 RC |
261 | nonOptionHandler = NULL; |
262 | } | |
263 | ||
264 | bool | |
265 | OptionSet::process (Option *aNonOptionHandler) | |
266 | { | |
267 | nonOptionHandler = aNonOptionHandler; | |
268 | if (options.size() == 0 && nonOptionHandler == NULL) | |
269 | return false; | |
270 | ||
271 | while (argv.size()) { | |
272 | processOne(); | |
273 | switch (lastResult) { | |
274 | ||
275 | case Option::Failed: | |
276 | return false; | |
277 | ||
278 | case Option::Ok: | |
279 | argv.erase(argv.begin()); | |
280 | break; | |
281 | ||
282 | case Option::Stop: | |
283 | if (argv.size() > 1) { | |
284 | // dies: copy(argv.begin() + 1, argv.end(), remainingargv.begin()); | |
155eacb6 | 285 | for (std::vector<std::string>::iterator i = argv.begin() + 1; i != argv.end(); ++i) |
1d644c06 | 286 | remainingargv.push_back(*i); |
7419f059 | 287 | } |
1d644c06 RC |
288 | return true; |
289 | } | |
7419f059 | 290 | } |
1d644c06 RC |
291 | |
292 | return true; | |
293 | } | |
294 | ||
295 | bool | |
296 | OptionSet::Process (int argc, char **argV, Option *nonOptionHandler) | |
297 | { | |
298 | if (argc == 1) { | |
299 | return true; | |
300 | } | |
301 | ||
302 | argv.clear(); | |
303 | nonoptions.clear(); | |
304 | remainingargv.clear(); | |
305 | ||
306 | for (int counter = 1; counter < argc; ++counter) | |
155eacb6 | 307 | argv.push_back(std::string(argV[counter])); |
1d644c06 RC |
308 | |
309 | return process(nonOptionHandler); | |
310 | } | |
311 | ||
312 | bool | |
313 | OptionSet::Process (std::vector<std::string> const &parms, Option *nonOptionHandler) | |
314 | { | |
315 | if (parms.size() == 0) | |
316 | return true; | |
317 | argv = parms; | |
318 | nonoptions.clear(); | |
319 | remainingargv.clear(); | |
320 | return process(nonOptionHandler); | |
7419f059 RC |
321 | } |
322 | ||
323 | //FIXME: check for conflicts. | |
324 | void | |
325 | OptionSet::Register (Option * anOption) | |
326 | { | |
6f1abe45 | 327 | options.push_back(anOption); |
7419f059 | 328 | } |
1ae8e28d | 329 | |
efe6ef67 JT |
330 | static bool |
331 | comp_long_option(const Option *a, const Option *b) | |
332 | { | |
333 | return (a->longOption().compare(b->longOption()) < 0); | |
334 | } | |
335 | ||
1ae8e28d | 336 | void |
20f237b4 | 337 | OptionSet::ParameterUsage (std::ostream &aStream, StrLookup strLookup) |
1ae8e28d | 338 | { |
efe6ef67 | 339 | std::sort(options.begin(), options.end(), comp_long_option); |
20f237b4 | 340 | for_each (options.begin(), options.end(), DefaultFormatter (aStream, strLookup)); |
1ae8e28d | 341 | } |
6f1abe45 RC |
342 | |
343 | std::vector<Option *> const & | |
344 | OptionSet::optionsInSet() const | |
345 | { | |
346 | return options; | |
347 | } | |
1d644c06 | 348 | |
155eacb6 | 349 | std::vector<std::string> const & |
1d644c06 RC |
350 | OptionSet::nonOptions() const |
351 | { | |
352 | return nonoptions; | |
353 | } | |
354 | ||
155eacb6 | 355 | std::vector<std::string> const & |
1d644c06 RC |
356 | OptionSet::remainingArgv() const |
357 | { | |
358 | return remainingargv; | |
359 | } |