argparser.cpp

00001
00002 /***************************************************************************
00003  *  argparser.cpp - Implementation of the argument parser
00004  *
00005  *  Generated: Mon May 30 13:25:33 2005 (from FireVision)
00006  *  Copyright  2005-2006  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <utils/system/argparser.h>
00025 #include <core/exceptions/software.h>
00026 #include <libgen.h>
00027 #include <cstdio>
00028 #include <cstdlib>
00029 #include <cstring>
00030
00031 namespace fawkes {
00032 
00033 /** @class ArgumentParser utils/system/argparser.h
00034  * Parse command line arguments.
00035  * Interface to GNU getopt and getopt_long. Parses command line arguments and
00036  * separates long and short options.
00037  *
00038  * The supplied opt_string is a string containing the legitimate option
00039  * characters. A character c denotes an option of the type "-c" (single dash).
00040  * If such a character is followed by a colon, the option requires an argument,
00041  * Two colons mean an option takes an optional arg.
00042  *
00043  * If long_options is supplied options started out by two dashes are recognized.
00044  * Long option names may be abbreviated if the abbreviation is unique or is an
00045  * exact match for some defined option. A long option may take a parameter, of
00046  * the form --arg=param or --arg param.
00047  *
00048  * long_options is a pointer to the first element of an array of struct option
00049  * declared in <getopt.h> as
00050  *
00051  * @code
00052  * struct option {
00053  *   const char *name;
00054  *   int has_arg;
00055  *   int *flag;
00056  *   int val;
00057  * };
00058  * @endcode
00059  *
00060  * The meanings of the different fields are:
00061  *
00062  * name   is the name of the long option.
00063  *
00064  *  has_arg   is: no_argument (or 0) if the option does not take  an  argument;
00065  *            required_argument  (or  1)  if  the  option  requires  an  argument;
00066  *            or optional_argument (or 2) if the option takes an optional argument.
00067  *
00068  *     flag   specifies  how results are returned for a long option.  If flag is
00069  *            NULL, then getopt_long() returns val.  (For example, the calling
00070  *            program may set val to the equivalent short option character.)
00071  *            Otherwise, getopt_long() returns 0, and flag points to a variable
00072  *            which is set to val if the option is found, but left unchanged if the
00073  *            option is not found. Handled internally in ArgumentParser
00074  *
00075  * For more information see man 3 getopt.
00076  *
00077  * All arguments that do not belong to parsed options are stored as items and can
00078  * be retrieved via items().
00079  */
00080
00081 
00082 /** Constructor
00083  * @param argc argument count.
00084  * @param argv argument vector
00085  * @param opt_string option string, see ArgumentParser
00086  * @param long_options long options, see ArgumentParser
00087  */
00088 ArgumentParser::ArgumentParser(int argc, char **argv, const char *opt_string, option *long_options)
00089 {
00090   _argc = argc;
00091   _argv = argv;
00092
00093   _opts.clear();
00094   _items.clear();
00095
00096 #ifdef _GNU_SOURCE
00097   _program_name = strdup(basename( argv[0] ));
00098 #else
00099   // Non-GNU variants may modify the sting in place
00100   char *tmp = strdup(argv[0]);
00101   _program_name = strdup(basename(tmp));
00102   free(tmp);
00103 #endif
00104 
00105   if (long_options == NULL) {
00106     int c ;
00107     char tmp[2];
00108
00109     while ((c = getopt(argc, argv, opt_string)) != -1) {
00110       if (c == '?') {
00111         throw UnknownArgumentException(c);
00112       } else if (c == ':') {
00113         throw MissingArgumentException(c);
00114       }
00115       sprintf(tmp, "%c", c);
00116       _opts[ tmp ] = optarg;
00117     }
00118   } else {
00119     int opt_ind = 0;
00120     int c;
00121     while ((c = getopt_long(argc, argv, opt_string, long_options, &opt_ind)) != -1) {
00122       if (c == '?') {
00123         throw UnknownArgumentException(c);
00124       } else if (c == 0) {
00125         // long options
00126         _opts[ long_options[opt_ind].name ] = optarg;
00127       } else {
00128         char tmp[2];
00129         sprintf(tmp, "%c", c);
00130         _opts[ tmp ] = optarg;
00131       }
00132     }
00133   }
00134
00135   _items.clear();
00136   int ind = optind;
00137   while (ind < argc) {
00138     _items.push_back( argv[ind++] );
00139   }
00140
00141 }
00142
00143 
00144 /** Destructor. */
00145 ArgumentParser::~ArgumentParser()
00146 {
00147   free(_program_name);
00148   _opts.clear();
00149 }
00150
00151 
00152 /** Check if argument has been supplied.
00153  * @param argn argument name to check for
00154  * @return true, if the argument was given on the command line, false otherwise
00155  */
00156 bool
00157 ArgumentParser::has_arg(const char *argn)
00158 {
00159   return (_opts.count((char *)argn) > 0);
00160 }
00161
00162 
00163 /** Get argument value.
00164  * Use this method to get the value supplied to the given option.
00165  * @param argn argument name to retrieve
00166  * @return the argument value. Pointer to static program array. Do not free!
00167  * Returns NULL if argument was not supplied on command line.
00168  */
00169 const char *
00170 ArgumentParser::arg(const char *argn)
00171 {
00172   if (_opts.count((char *)argn) > 0) {
00173     return _opts[ (char *)argn ];
00174   } else {
00175     return NULL;
00176   }
00177 }
00178
00179 
00180 /** Get argument while checking availability.
00181  * The argument will be a newly allocated copy of the string. You have to
00182  * free it after you are done with it.
00183  * @param argn argument name to retrieve
00184  * @param value a pointer to a newly allocated copy of the argument value will
00185  * be stored here if the argument has been found.
00186  * The value is unchanged if argument was not supplied.
00187  * @return true, if the argument was supplied, false otherwise
00188  */
00189 bool
00190 ArgumentParser::arg(const char *argn, char **value)
00191 {
00192   if (_opts.count((char *)argn) > 0) {
00193     *value = strdup(_opts[ (char *)argn ]);
00194     return true;
00195   } else {
00196     return false;
00197   }
00198 }
00199
00200 
00201 /** Parse host:port string.
00202  * The value referenced by the given argn is parsed for the pattern "host:port". If the
00203  * string does not match this pattern an exception is thrown.
00204  * The host will be a newly allocated copy of the string. You have to
00205  * free it after you are done with it. If no port is supplied in the string (plain
00206  * hostname string) the port argument is left unchanged. If the argument has not
00207  * been supplied at all both values are left unchanged. Thus it is safe to put the default
00208  * values into the variables before passing them to this method. Note however that you
00209  * have to free the returned host string in case of a successful return, and only in
00210  * that case probably!
00211  * @param argn argument name to retrieve
00212  * @param host Upon successful return contains a pointer to a newly alloated string
00213  * with the hostname part. Free it after you are finished.
00214  * @param port upon successful return contains the port part
00215  * @return true, if the argument was supplied, false otherwise
00216  * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
00217  */
00218 bool
00219 ArgumentParser::parse_hostport(const char *argn, char **host, unsigned short int *port)
00220 {
00221   if (_opts.count((char *)argn) > 0) {
00222     char *tmpvalue = strdup(_opts[ (char *)argn ]);
00223
00224     if ( strchr(tmpvalue, ':') != NULL ) {
00225       char *save_ptr;
00226       *host = strtok_r(tmpvalue, ":", &save_ptr);
00227       char *tmpport = strtok_r(NULL, "", &save_ptr);
00228
00229       int port_num = atoi(tmpport);
00230       if ( (port_num < 0) || (port_num > 0xFFFF) ) {
00231         throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
00232       }
00233       *port = port_num;
00234     } else {
00235       *host = tmpvalue;
00236     }
00237
00238     return true;
00239   } else {
00240     return false;
00241   }
00242 }
00243
00244 
00245 /** Parse argument as integer.
00246  * Converts the value of the given argument to an integer.
00247  * @param argn argument name to retrieve
00248  * @return value of string as long int
00249  * @exception IllegalArgumentException thrown if the value cannot be properly
00250  * converted to an integer
00251  * @exception Exception thrown if the argument has not been supplied
00252  */
00253 long int
00254 ArgumentParser::parse_int(const char *argn)
00255 {
00256   if (_opts.count((char *)argn) > 0) {
00257     char *endptr;
00258     long int rv = strtol(_opts[argn], &endptr, 10);
00259     if ( endptr[0] != 0 ) {
00260       throw IllegalArgumentException("Supplied argument is not of type int");
00261     }
00262     return rv;
00263   } else {
00264     throw Exception("Value for '%s' not available", argn);
00265   }
00266 }
00267
00268 
00269 /** Parse argument as double.
00270  * Converts the value of the given argument to a double.
00271  * @param argn argument name to retrieve
00272  * @return value of string as double
00273  * @exception IllegalArgumentException thrown if the value cannot be properly
00274  * converted to a double
00275  * @exception Exception thrown if the argument has not been supplied
00276  */
00277 double
00278 ArgumentParser::parse_float(const char *argn)
00279 {
00280   if (_opts.count((char *)argn) > 0) {
00281     char *endptr;
00282     double rv = strtod(_opts[argn], &endptr);
00283     if ( endptr[0] != 0 ) {
00284       throw IllegalArgumentException("Supplied argument is not of type double");
00285     }
00286     return rv;
00287   } else {
00288     throw Exception("Value for '%s' not available", argn);
00289   }
00290 }
00291
00292 
00293 /** Parse item as integer.
00294  * Converts the value of the given item to an integer.
00295  * @param index item index
00296  * @return value of string as long int
00297  * @exception IllegalArgumentException thrown if the value cannot be properly
00298  * converted to an integer
00299  * @exception Exception thrown if the argument has not been supplied
00300  */
00301 long int
00302 ArgumentParser::parse_item_int(unsigned int index)
00303 {
00304   if (index < _items.size()) {
00305     char *endptr;
00306     long int rv = strtol(_items[index], &endptr, 10);
00307     if ( endptr[0] != 0 ) {
00308       throw IllegalArgumentException("Supplied argument is not of type int");
00309     }
00310     return rv;
00311   } else {
00312     throw Exception("Value for item %u not available", index);
00313   }
00314 }
00315
00316 
00317 /** Parse item as double.
00318  * Converts the value of the given item to a double.
00319  * @param index item index
00320  * @return value of string as double
00321  * @exception IllegalArgumentException thrown if the value cannot be properly
00322  * converted to a double
00323  * @exception Exception thrown if the argument has not been supplied
00324  */
00325 double
00326 ArgumentParser::parse_item_float(unsigned int index)
00327 {
00328   if (index < _items.size()) {
00329     char *endptr;
00330     double rv = strtod(_items[index], &endptr);
00331     if ( endptr[0] != 0 ) {
00332       throw IllegalArgumentException("Supplied argument is not of type double");
00333     }
00334     return rv;
00335   } else {
00336     throw Exception("Value for item %u not available", index);
00337   }
00338 }
00339
00340 
00341 /** Get non-option items.
00342  * @return pointer to vector of pointer to non-argument values. Handled internally,
00343  * do not free or delete!
00344  */
00345 const std::vector< const char* > &
00346 ArgumentParser::items() const
00347 {
00348   return _items;
00349 }
00350
00351 
00352 /** Get number of non-option items.
00353  * @return number of non-opt items.
00354  */
00355 std::vector< const char* >::size_type
00356 ArgumentParser::num_items() const
00357 {
00358   return _items.size();
00359 }
00360
00361 
00362 /** Get number of arguments.
00363  * @return number of arguments
00364  */
00365 int
00366 ArgumentParser::argc() const
00367 {
00368   return _argc;
00369 }
00370
00371 
00372 /** Program argument array as supplied to constructor.
00373  * @return argument array.
00374  */
00375 const char **
00376 ArgumentParser::argv() const
00377 {
00378   return (const char **)_argv;
00379 }
00380
00381 
00382 /** Get name of program.
00383  * @return the name of the program (argv[0] of argument vector supplied to constructor).
00384  */
00385 const char *
00386 ArgumentParser::program_name() const
00387 {
00388   return _program_name;
00389 }
00390
00391 } // end namespace fawkes