Fawkes API Fawkes Development Version
argparser.cpp
1
2/***************************************************************************
3 * argparser.cpp - Implementation of the argument parser
4 *
5 * Generated: Mon May 30 13:25:33 2005 (from FireVision)
6 * Copyright 2005-2006 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/exceptions/software.h>
25#include <utils/system/argparser.h>
26
27#include <cstdio>
28#include <cstdlib>
29#include <cstring>
30#include <libgen.h>
31#include <string>
32
33namespace fawkes {
34
35/** @class ArgumentParser <utils/system/argparser.h>
36 * Parse command line arguments.
37 * Interface to GNU getopt and getopt_long. Parses command line arguments and
38 * separates long and short options.
39 *
40 * The supplied opt_string is a string containing the legitimate option
41 * characters. A character c denotes an option of the type "-c" (single dash).
42 * If such a character is followed by a colon, the option requires an argument,
43 * Two colons mean an option takes an optional arg.
44 *
45 * If long_options is supplied options started out by two dashes are recognized.
46 * Long option names may be abbreviated if the abbreviation is unique or is an
47 * exact match for some defined option. A long option may take a parameter, of
48 * the form --arg=param or --arg param.
49 *
50 * long_options is a pointer to the first element of an array of struct option
51 * declared in <getopt.h> as
52 *
53 * @code
54 * struct option {
55 * const char *name;
56 * int has_arg;
57 * int *flag;
58 * int val;
59 * };
60 * @endcode
61 *
62 * The meanings of the different fields are:
63 *
64 * name is the name of the long option.
65 *
66 * has_arg is: no_argument (or 0) if the option does not take an argument;
67 * required_argument (or 1) if the option requires an argument;
68 * or optional_argument (or 2) if the option takes an optional argument.
69 *
70 * flag specifies how results are returned for a long option. If flag is
71 * NULL, then getopt_long() returns val. (For example, the calling
72 * program may set val to the equivalent short option character.)
73 * Otherwise, getopt_long() returns 0, and flag points to a variable
74 * which is set to val if the option is found, but left unchanged if the
75 * option is not found. Handled internally in ArgumentParser
76 *
77 * For more information see man 3 getopt.
78 *
79 * All arguments that do not belong to parsed options are stored as items and can
80 * be retrieved via items().
81 */
82
83/** Constructor
84 * @param argc argument count.
85 * @param argv argument vector
86 * @param opt_string option string, see ArgumentParser
87 * @param long_options long options, see ArgumentParser
88 */
89ArgumentParser::ArgumentParser(int argc, char **argv, const char *opt_string, option *long_options)
90{
91 argc_ = argc;
92 argv_ = argv;
93
94 opt_string_ = opt_string;
95
96 if (long_options) {
97 option *tmplo = long_options;
98 while (tmplo->name != 0) {
99 long_opts_.push_back(*tmplo);
100 tmplo += 1;
101 }
102 }
103
104 opts_.clear();
105 items_.clear();
106
107#ifdef _GNU_SOURCE
108 program_name_ = strdup(basename(argv[0]));
109#else
110 // Non-GNU variants may modify the sting in place
111 char *tmp = strdup(argv[0]);
112 program_name_ = strdup(basename(tmp));
113 free(tmp);
114#endif
115
116 if (long_options == NULL) {
117 int c;
118 char tmp[2];
119
120 while ((c = getopt(argc, argv, opt_string)) != -1) {
121 if (c == '?') {
123 } else if (c == ':') {
125 }
126 sprintf(tmp, "%c", c);
127 opts_[tmp] = optarg;
128 }
129 } else {
130 int opt_ind = 0;
131 int c;
132 while ((c = getopt_long(argc, argv, opt_string, long_options, &opt_ind)) != -1) {
133 if (c == '?') {
135 } else if (c == 0) {
136 // long options
137 opts_[long_options[opt_ind].name] = optarg;
138 } else {
139 char tmp[2];
140 sprintf(tmp, "%c", c);
141 opts_[tmp] = optarg;
142 }
143 }
144 }
145
146 items_.clear();
147 int ind = optind;
148 while (ind < argc) {
149 items_.push_back(argv[ind++]);
150 }
151}
152
153/** Destructor. */
155{
156 free(program_name_);
157 opts_.clear();
158}
159
160/** Check if argument has been supplied.
161 * @param argn argument name to check for
162 * @return true, if the argument was given on the command line, false otherwise
163 */
164bool
165ArgumentParser::has_arg(const char *argn)
166{
167 return (opts_.count((char *)argn) > 0);
168}
169
170/** Get argument value.
171 * Use this method to get the value supplied to the given option.
172 * @param argn argument name to retrieve
173 * @return the argument value. Pointer to static program array. Do not free!
174 * Returns NULL if argument was not supplied on command line.
175 */
176const char *
177ArgumentParser::arg(const char *argn)
178{
179 if ((opts_.count(argn) > 0) && (opts_[argn] != NULL)) {
180 return opts_[(char *)argn];
181 } else {
182 return NULL;
183 }
184}
185
186/** Get argument while checking availability.
187 * The argument will be a newly allocated copy of the string. You have to
188 * free it after you are done with it.
189 * @param argn argument name to retrieve
190 * @param value a pointer to a newly allocated copy of the argument value will
191 * be stored here if the argument has been found.
192 * The value is unchanged if argument was not supplied.
193 * @return true, if the argument was supplied, false otherwise
194 */
195bool
196ArgumentParser::arg(const char *argn, char **value)
197{
198 if ((opts_.count(argn) > 0) && (opts_[argn] != NULL)) {
199 *value = strdup(opts_[(char *)argn]);
200 return true;
201 } else {
202 return false;
203 }
204}
205
206/** Parse host:port string.
207 * The value referenced by the given argn is parsed for the pattern "host:port".
208 * If the string does not match this pattern an exception is thrown.
209 * The host will be a newly allocated copy of the string. You have to
210 * free it after you are done with it. If no port is supplied in the string (plain
211 * hostname string) the port argument is left unchanged. If the argument has not
212 * been supplied at all both values are left unchanged. Thus it is safe to put the
213 * default values into the variables before passing them to this method. Note
214 * however that you have to free the returned host string in case of a successful
215 * return, and only in that case probably!
216 * @param argn argument name to retrieve
217 * @param host Upon successful return contains a pointer to a newly alloated string
218 * with the hostname part. Free it after you are finished.
219 * @param port upon successful return contains the port part
220 * @return true, if the argument was supplied, false otherwise
221 * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
222 */
223bool
224ArgumentParser::parse_hostport(const char *argn, char **host, unsigned short int *port)
225{
226 if ((opts_.count(argn) > 0) && (opts_[argn] != NULL)) {
227 parse_hostport_s(opts_[(char *)argn], host, port);
228 return true;
229 } else {
230 return false;
231 }
232}
233
234/** Parse host:port string.
235 * The value referenced by the given argn is parsed for the pattern "host:port".
236 * If the string does not match this pattern an exception is thrown.
237 * The host will be a newly allocated copy of the string. You have to
238 * free it after you are done with it. If no port is supplied in the string (plain
239 * hostname string) the port argument is left unchanged. If the argument has not
240 * been supplied at all both values are left unchanged. Thus it is safe to put the
241 * default values into the variables before passing them to this method. Note
242 * however that you have to free the returned host string in case of a successful
243 * return, and only in that case probably!
244 * @param s string to parse
245 * @param host Upon successful return contains a pointer to a newly alloated string
246 * with the hostname part. Free it after you are finished.
247 * @param port upon successful return contains the port part
248 * @exception Exception thrown on parsing error
249 */
250void
251ArgumentParser::parse_hostport_s(const char *s, char **host, unsigned short int *port)
252{
253 std::string tmp = s;
254 size_t num_colons = 0;
255 std::string::size_type idx = 0;
256 while ((idx = tmp.find(':', idx)) != std::string::npos) {
257 idx += 1;
258 num_colons += 1;
259 }
260
261 if (num_colons == 1) {
262 idx = tmp.find(':');
263 *host = strdup(tmp.substr(0, idx).c_str());
264 if (!tmp.substr(idx + 1).empty()) {
265 *port = atoi(tmp.substr(idx + 1).c_str());
266 }
267 } else if (num_colons > 1) {
268 // IPv6
269 if (tmp[0] == '[') {
270 // notation that actually contains a port
271 std::string::size_type closing_idx = tmp.find(']');
272 if (closing_idx == std::string::npos) {
273 throw Exception("No closing bracket for IPv6 address");
274 } else if (closing_idx < (tmp.length() - 1)) {
275 // there might be a port
276 if (tmp[closing_idx + 1] != ':') {
277 throw Exception("Expected colon after closing IPv6 address bracket");
278 } else if (closing_idx > tmp.length() - 3) {
279 throw Exception(
280 "Malformed IPv6 address with port, not enough characters after closing bracket");
281 } else {
282 *host = strdup(tmp.substr(1, closing_idx - 1).c_str());
283 *port = atoi(tmp.substr(closing_idx + 2).c_str());
284 }
285 } else {
286 // Just an IPv6 in bracket notation
287 *host = strdup(tmp.substr(1, closing_idx - 2).c_str());
288 }
289 } else {
290 // no port, just an IPv6 address
291 *host = strdup(tmp.c_str());
292 }
293 } else {
294 // no port given
295 *host = strdup(tmp.c_str());
296 }
297}
298
299/** Parse host:port string.
300 * The value referenced by the given argn is parsed for the pattern "host:port". If the
301 * string does not match this pattern an exception is thrown.
302 * If no port is supplied in the string (plain
303 * hostname string) the port argument is left unchanged. If the argument has not
304 * been supplied at all both values are left unchanged. Thus it is safe to put the default
305 * values into the variables before passing them to this method.
306 * @param argn argument name to retrieve
307 * @param host Upon successful return contains the hostname part
308 * @param port upon successful return contains the port part (unchanged if not supplied)
309 * @return true, if the argument was supplied, false otherwise
310 * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
311 */
312bool
313ArgumentParser::parse_hostport(const char *argn, std::string &host, unsigned short int &port)
314{
315 if ((opts_.count(argn) == 0) || (opts_[argn] == NULL))
316 return false;
317
318 char * tmp_host = NULL;
319 unsigned short int tmp_port = port;
320 if (parse_hostport(argn, &tmp_host, &tmp_port)) {
321 host = tmp_host;
322 port = tmp_port;
323 return true;
324 }
325 return false;
326}
327
328/** Parse host:port string.
329 * The value referenced by the given argn is parsed for the pattern "host:port". If the
330 * string does not match this pattern an exception is thrown.
331 * If no port is supplied in the string (plain
332 * hostname string) the port argument is left unchanged. If the argument has not
333 * been supplied at all both values are left unchanged. Thus it is safe to put the default
334 * values into the variables before passing them to this method.
335 * @param s string to parse
336 * @param host Upon successful return contains the hostname part
337 * @param port upon successful return contains the port part (unchanged if not supplied)
338 * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
339 */
340void
341ArgumentParser::parse_hostport_s(const char *s, std::string &host, unsigned short int &port)
342{
343 char * tmp_host = NULL;
344 unsigned short int tmp_port = port;
345 parse_hostport_s(s, &tmp_host, &tmp_port);
346 host = tmp_host;
347 port = tmp_port;
348}
349
350/** Parse argument as integer.
351 * Converts the value of the given argument to an integer.
352 * @param argn argument name to retrieve
353 * @return value of string as long int
354 * @exception IllegalArgumentException thrown if the value cannot be properly
355 * converted to an integer
356 * @exception Exception thrown if the argument has not been supplied
357 */
358long int
360{
361 if ((opts_.count(argn) > 0) && (opts_[argn] != NULL)) {
362 char * endptr;
363 long int rv = strtol(opts_[argn], &endptr, 10);
364 if (endptr[0] != 0) {
365 throw IllegalArgumentException("Supplied argument is not of type int");
366 }
367 return rv;
368 } else {
369 throw Exception("Value for '%s' not available", argn);
370 }
371}
372
373/** Parse argument as double.
374 * Converts the value of the given argument to a double.
375 * @param argn argument name to retrieve
376 * @return value of string as double
377 * @exception IllegalArgumentException thrown if the value cannot be properly
378 * converted to a double
379 * @exception Exception thrown if the argument has not been supplied
380 */
381double
383{
384 if ((opts_.count(argn) > 0) && (opts_[argn] != NULL)) {
385 char * endptr;
386 double rv = strtod(opts_[argn], &endptr);
387 if (endptr[0] != 0) {
388 throw IllegalArgumentException("Supplied argument is not of type double");
389 }
390 return rv;
391 } else {
392 throw Exception("Value for '%s' not available", argn);
393 }
394}
395
396/** Parse item as integer.
397 * Converts the value of the given item to an integer.
398 * @param index item index
399 * @return value of string as long int
400 * @exception IllegalArgumentException thrown if the value cannot be properly
401 * converted to an integer
402 * @exception Exception thrown if the argument has not been supplied
403 */
404long int
406{
407 if (index < items_.size()) {
408 char * endptr;
409 long int rv = strtol(items_[index], &endptr, 10);
410 if (endptr[0] != 0) {
411 throw IllegalArgumentException("Supplied argument is not of type int");
412 }
413 return rv;
414 } else {
415 throw Exception("Value for item %u not available", index);
416 }
417}
418
419/** Parse item as double.
420 * Converts the value of the given item to a double.
421 * @param index item index
422 * @return value of string as double
423 * @exception IllegalArgumentException thrown if the value cannot be properly
424 * converted to a double
425 * @exception Exception thrown if the argument has not been supplied
426 */
427double
429{
430 if (index < items_.size()) {
431 char * endptr;
432 double rv = strtod(items_[index], &endptr);
433 if (endptr[0] != 0) {
434 throw IllegalArgumentException("Supplied argument is not of type double");
435 }
436 return rv;
437 } else {
438 throw Exception("Value for item %u not available", index);
439 }
440}
441
442/** Get non-option items.
443 * @return pointer to vector of pointer to non-argument values. Handled internally,
444 * do not free or delete!
445 */
446const std::vector<const char *> &
448{
449 return items_;
450}
451
452/** Get number of non-option items.
453 * @return number of non-opt items.
454 */
455std::vector<const char *>::size_type
457{
458 return items_.size();
459}
460
461/** Get number of arguments.
462 * @return number of arguments
463 */
464int
466{
467 return argc_;
468}
469
470/** Program argument array as supplied to constructor.
471 * @return argument array.
472 */
473const char **
475{
476 return (const char **)argv_;
477}
478
479/** Get name of program.
480 * @return the name of the program (argv[0] of argument vector supplied to constructor).
481 */
482const char *
484{
485 return program_name_;
486}
487
488} // end namespace fawkes
int argc() const
Get number of arguments.
Definition: argparser.cpp:465
const char * program_name() const
Get name of program.
Definition: argparser.cpp:483
~ArgumentParser()
Destructor.
Definition: argparser.cpp:154
double parse_item_float(unsigned int index)
Parse item as double.
Definition: argparser.cpp:428
ArgumentParser(int argc, char **argv, const char *opt_string, option *long_options=NULL)
Constructor.
Definition: argparser.cpp:89
const std::vector< const char * > & items() const
Get non-option items.
Definition: argparser.cpp:447
static void parse_hostport_s(const char *s, char **host, unsigned short int *port)
Parse host:port string.
Definition: argparser.cpp:251
const char * arg(const char *argn)
Get argument value.
Definition: argparser.cpp:177
bool parse_hostport(const char *argn, char **host, unsigned short int *port)
Parse host:port string.
Definition: argparser.cpp:224
std::vector< constchar * >::size_type num_items() const
Get number of non-option items.
Definition: argparser.cpp:456
const char ** argv() const
Program argument array as supplied to constructor.
Definition: argparser.cpp:474
double parse_float(const char *argn)
Parse argument as double.
Definition: argparser.cpp:382
long int parse_int(const char *argn)
Parse argument as integer.
Definition: argparser.cpp:359
long int parse_item_int(unsigned int index)
Parse item as integer.
Definition: argparser.cpp:405
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:165
Base class for exceptions in Fawkes.
Definition: exception.h:36
Expected parameter is missing.
Definition: software.h:80
Thrown if required argument was missing.
Definition: argparser.h:52
Thrown if unknown argument was supplied.
Definition: argparser.h:39
Fawkes library namespace.