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