Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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  char *tmpvalue = strdup(__opts[ (char *)argn ]);
236 
237  if ( strchr(tmpvalue, ':') != NULL ) {
238  char *save_ptr;
239  *host = strtok_r(tmpvalue, ":", &save_ptr);
240  char *tmpport = strtok_r(NULL, "", &save_ptr);
241 
242  int port_num = atoi(tmpport);
243  if ( (port_num < 0) || (port_num > 0xFFFF) ) {
244  throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
245  }
246  *port = port_num;
247  } else {
248  *host = tmpvalue;
249  }
250 
251  return true;
252  } else {
253  return false;
254  }
255 }
256 
257 
258 /** Parse host:port string.
259  * The value referenced by the given argn is parsed for the pattern "host:port". If the
260  * string does not match this pattern an exception is thrown.
261  * If no port is supplied in the string (plain
262  * hostname string) the port argument is left unchanged. If the argument has not
263  * been supplied at all both values are left unchanged. Thus it is safe to put the default
264  * values into the variables before passing them to this method.
265  * @param argn argument name to retrieve
266  * @param host Upon successful return contains the hostname part
267  * @param port upon successful return contains the port part (unchanged if not supplied)
268  * @return true, if the argument was supplied, false otherwise
269  * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
270  */
271 bool
272 ArgumentParser::parse_hostport(const char *argn, std::string &host, unsigned short int &port)
273 {
274  if ((__opts.count(argn) == 0) || (__opts[argn] == NULL)) return false;
275 
276  std::string tmpvalue = __opts[argn];
277 
278  size_t col_idx = tmpvalue.find_last_of(':');
279  if ( col_idx == tmpvalue.npos ) {
280  host = tmpvalue;
281  }
282  else
283  {
284  host = tmpvalue.substr(0, col_idx);
285  std::string tmpport = tmpvalue.substr(col_idx + 1);
286 
287  int port_num = atoi(tmpport.c_str());
288  if ( (port_num < 0) || (port_num > 0xFFFF) ) {
289  throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
290  }
291  port = port_num;
292  }
293  return true;
294 }
295 
296 
297 /** Parse argument as integer.
298  * Converts the value of the given argument to an integer.
299  * @param argn argument name to retrieve
300  * @return value of string as long int
301  * @exception IllegalArgumentException thrown if the value cannot be properly
302  * converted to an integer
303  * @exception Exception thrown if the argument has not been supplied
304  */
305 long int
306 ArgumentParser::parse_int(const char *argn)
307 {
308  if ((__opts.count(argn) > 0) && (__opts[argn] != NULL)) {
309  char *endptr;
310  long int rv = strtol(__opts[argn], &endptr, 10);
311  if ( endptr[0] != 0 ) {
312  throw IllegalArgumentException("Supplied argument is not of type int");
313  }
314  return rv;
315  } else {
316  throw Exception("Value for '%s' not available", argn);
317  }
318 }
319 
320 
321 /** Parse argument as double.
322  * Converts the value of the given argument to a double.
323  * @param argn argument name to retrieve
324  * @return value of string as double
325  * @exception IllegalArgumentException thrown if the value cannot be properly
326  * converted to a double
327  * @exception Exception thrown if the argument has not been supplied
328  */
329 double
331 {
332  if ((__opts.count(argn) > 0) && (__opts[argn] != NULL)) {
333  char *endptr;
334  double rv = strtod(__opts[argn], &endptr);
335  if ( endptr[0] != 0 ) {
336  throw IllegalArgumentException("Supplied argument is not of type double");
337  }
338  return rv;
339  } else {
340  throw Exception("Value for '%s' not available", argn);
341  }
342 }
343 
344 
345 /** Parse item as integer.
346  * Converts the value of the given item to an integer.
347  * @param index item index
348  * @return value of string as long int
349  * @exception IllegalArgumentException thrown if the value cannot be properly
350  * converted to an integer
351  * @exception Exception thrown if the argument has not been supplied
352  */
353 long int
355 {
356  if (index < __items.size()) {
357  char *endptr;
358  long int rv = strtol(__items[index], &endptr, 10);
359  if ( endptr[0] != 0 ) {
360  throw IllegalArgumentException("Supplied argument is not of type int");
361  }
362  return rv;
363  } else {
364  throw Exception("Value for item %u not available", index);
365  }
366 }
367 
368 
369 /** Parse item as double.
370  * Converts the value of the given item to a double.
371  * @param index item index
372  * @return value of string as double
373  * @exception IllegalArgumentException thrown if the value cannot be properly
374  * converted to a double
375  * @exception Exception thrown if the argument has not been supplied
376  */
377 double
379 {
380  if (index < __items.size()) {
381  char *endptr;
382  double rv = strtod(__items[index], &endptr);
383  if ( endptr[0] != 0 ) {
384  throw IllegalArgumentException("Supplied argument is not of type double");
385  }
386  return rv;
387  } else {
388  throw Exception("Value for item %u not available", index);
389  }
390 }
391 
392 
393 /** Get non-option items.
394  * @return pointer to vector of pointer to non-argument values. Handled internally,
395  * do not free or delete!
396  */
397 const std::vector< const char* > &
399 {
400  return __items;
401 }
402 
403 
404 /** Get number of non-option items.
405  * @return number of non-opt items.
406  */
407 std::vector< const char* >::size_type
409 {
410  return __items.size();
411 }
412 
413 
414 /** Get number of arguments.
415  * @return number of arguments
416  */
417 int
419 {
420  return __argc;
421 }
422 
423 
424 /** Program argument array as supplied to constructor.
425  * @return argument array.
426  */
427 const char **
429 {
430  return (const char **)__argv;
431 }
432 
433 
434 /** Get name of program.
435  * @return the name of the program (argv[0] of argument vector supplied to constructor).
436  */
437 const char *
439 {
440  return __program_name;
441 }
442 
443 
444 } // end namespace fawkes
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:330
double parse_item_float(unsigned int index)
Parse item as double.
Definition: argparser.cpp:378
const std::vector< const char * > & items() const
Get non-option items.
Definition: argparser.cpp:398
int argc() const
Get number of arguments.
Definition: argparser.cpp:418
long int parse_int(const char *argn)
Parse argument as integer.
Definition: argparser.cpp:306
ArgumentParser(int argc, char **argv, const char *opt_string, option *long_options=NULL)
Constructor.
Definition: argparser.cpp:89
Base class for exceptions in Fawkes.
Definition: exception.h:36
~ArgumentParser()
Destructor.
Definition: argparser.cpp:157
const char ** argv() const
Program argument array as supplied to constructor.
Definition: argparser.cpp:428
const char * program_name() const
Get name of program.
Definition: argparser.cpp:438
bool has_arg(const char *argn)
Check if argument has been supplied.
Definition: argparser.cpp:169
std::vector< const char * >::size_type num_items() const
Get number of non-option items.
Definition: argparser.cpp:408
Thrown if unknown argument was supplied.
Definition: argparser.h:40
Index out of bounds.
Definition: software.h:88
Expected parameter is missing.
Definition: software.h:82
long int parse_item_int(unsigned int index)
Parse item as integer.
Definition: argparser.cpp:354