Fawkes API  Fawkes Development Version
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 #include <string>
00031 
00032 namespace fawkes {
00033 
00034 /** @class ArgumentParser <utils/system/argparser.h>
00035  * Parse command line arguments.
00036  * Interface to GNU getopt and getopt_long. Parses command line arguments and
00037  * separates long and short options.
00038  *
00039  * The supplied opt_string is a string containing the legitimate option
00040  * characters. A character c denotes an option of the type "-c" (single dash).
00041  * If such a character is followed by a colon, the option requires an argument,
00042  * Two colons mean an option takes an optional arg.
00043  *
00044  * If long_options is supplied options started out by two dashes are recognized.
00045  * Long option names may be abbreviated if the abbreviation is unique or is an
00046  * exact match for some defined option. A long option may take a parameter, of
00047  * the form --arg=param or --arg param.
00048  *
00049  * long_options is a pointer to the first element of an array of struct option
00050  * declared in <getopt.h> as
00051  *
00052  * @code
00053  * struct option {
00054  *   const char *name;
00055  *   int has_arg;
00056  *   int *flag;
00057  *   int val;
00058  * };
00059  * @endcode
00060  *
00061  * The meanings of the different fields are:
00062  *
00063  * name   is the name of the long option.
00064  *
00065  *  has_arg   is: no_argument (or 0) if the option does not take  an  argument;
00066  *            required_argument  (or  1)  if  the  option  requires  an  argument;
00067  *            or optional_argument (or 2) if the option takes an optional argument.
00068  *
00069  *     flag   specifies  how results are returned for a long option.  If flag is
00070  *            NULL, then getopt_long() returns val.  (For example, the calling
00071  *            program may set val to the equivalent short option character.)
00072  *            Otherwise, getopt_long() returns 0, and flag points to a variable
00073  *            which is set to val if the option is found, but left unchanged if the
00074  *            option is not found. Handled internally in ArgumentParser
00075  *
00076  * For more information see man 3 getopt.
00077  *
00078  * All arguments that do not belong to parsed options are stored as items and can
00079  * be retrieved via items().
00080  */
00081 
00082 
00083 /** Constructor
00084  * @param argc argument count.
00085  * @param argv argument vector
00086  * @param opt_string option string, see ArgumentParser
00087  * @param long_options long options, see ArgumentParser
00088  */
00089 ArgumentParser::ArgumentParser(int argc, char **argv,
00090                                const char *opt_string, option *long_options)
00091 {
00092   __argc = argc;
00093   __argv = argv;
00094 
00095   __opt_string = opt_string;
00096 
00097   if (long_options) {
00098     option *tmplo = long_options;
00099     while (tmplo->name != 0) {
00100       __long_opts.push_back(*tmplo);
00101       tmplo += 1;
00102     }
00103   }
00104 
00105   __opts.clear();
00106   __items.clear();
00107 
00108 #ifdef _GNU_SOURCE
00109   __program_name = strdup(basename( argv[0] ));
00110 #else
00111   // Non-GNU variants may modify the sting in place
00112   char *tmp = strdup(argv[0]);
00113   __program_name = strdup(basename(tmp));
00114   free(tmp);
00115 #endif
00116 
00117   if (long_options == NULL) {
00118     int c ;
00119     char tmp[2];
00120 
00121     while ((c = getopt(argc, argv, opt_string)) != -1) {
00122       if (c == '?') {
00123         throw UnknownArgumentException(c);
00124       } else if (c == ':') {
00125         throw MissingArgumentException(c);
00126       }
00127       sprintf(tmp, "%c", c);
00128       __opts[ tmp ] = optarg;
00129     }
00130   } else {
00131     int opt_ind = 0;
00132     int c;
00133     while ((c = getopt_long(argc, argv, opt_string, long_options, &opt_ind)) != -1) {
00134       if (c == '?') {
00135         throw UnknownArgumentException(c);
00136       } else if (c == 0) {
00137         // long options
00138         __opts[ long_options[opt_ind].name ] = optarg;
00139       } else {
00140         char tmp[2];
00141         sprintf(tmp, "%c", c);
00142         __opts[ tmp ] = optarg;
00143       }
00144     }
00145   }
00146 
00147   __items.clear();
00148   int ind = optind;
00149   while (ind < argc) {
00150     __items.push_back( argv[ind++] );
00151   }
00152 
00153 }
00154 
00155 
00156 /** Destructor. */
00157 ArgumentParser::~ArgumentParser()
00158 {
00159   free(__program_name);
00160   __opts.clear();
00161 }
00162 
00163 
00164 /** Check if argument has been supplied.
00165  * @param argn argument name to check for
00166  * @return true, if the argument was given on the command line, false otherwise
00167  */
00168 bool
00169 ArgumentParser::has_arg(const char *argn)
00170 {
00171   return (__opts.count((char *)argn) > 0);
00172 }
00173 
00174 
00175 /** Get argument value.
00176  * Use this method to get the value supplied to the given option.
00177  * @param argn argument name to retrieve
00178  * @return the argument value. Pointer to static program array. Do not free!
00179  * Returns NULL if argument was not supplied on command line.
00180  */
00181 const char *
00182 ArgumentParser::arg(const char *argn)
00183 {
00184   if ((__opts.count(argn) > 0) && (__opts[argn] != NULL)) {
00185     return __opts[ (char *)argn ];
00186   } else {
00187     return NULL;
00188   }
00189 }
00190 
00191 
00192 /** Get argument while checking availability.
00193  * The argument will be a newly allocated copy of the string. You have to
00194  * free it after you are done with it.
00195  * @param argn argument name to retrieve
00196  * @param value a pointer to a newly allocated copy of the argument value will
00197  * be stored here if the argument has been found.
00198  * The value is unchanged if argument was not supplied.
00199  * @return true, if the argument was supplied, false otherwise
00200  */
00201 bool
00202 ArgumentParser::arg(const char *argn, char **value)
00203 {
00204   if ((__opts.count(argn) > 0) && (__opts[argn] != NULL)) {
00205     *value = strdup(__opts[ (char *)argn ]);
00206     return true;
00207   } else {
00208     return false;
00209   }
00210 }
00211 
00212 
00213 /** Parse host:port string.
00214  * The value referenced by the given argn is parsed for the pattern "host:port".
00215  * If the string does not match this pattern an exception is thrown.
00216  * The host will be a newly allocated copy of the string. You have to
00217  * free it after you are done with it. If no port is supplied in the string (plain
00218  * hostname string) the port argument is left unchanged. If the argument has not
00219  * been supplied at all both values are left unchanged. Thus it is safe to put the
00220  * default values into the variables before passing them to this method. Note
00221  * however that you have to free the returned host string in case of a successful
00222  * return, and only in that case probably!
00223  * @param argn argument name to retrieve
00224  * @param host Upon successful return contains a pointer to a newly alloated string
00225  * with the hostname part. Free it after you are finished.
00226  * @param port upon successful return contains the port part
00227  * @return true, if the argument was supplied, false otherwise
00228  * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
00229  */
00230 bool
00231 ArgumentParser::parse_hostport(const char *argn, char **host,
00232                                unsigned short int *port)
00233 {
00234   if ((__opts.count(argn) > 0) && (__opts[argn] != NULL)) {
00235     char *tmpvalue = strdup(__opts[ (char *)argn ]);
00236 
00237     if ( strchr(tmpvalue, ':') != NULL ) {
00238       char *save_ptr;
00239       *host = strtok_r(tmpvalue, ":", &save_ptr);
00240       char *tmpport = strtok_r(NULL, "", &save_ptr);
00241 
00242       int port_num = atoi(tmpport);
00243       if ( (port_num < 0) || (port_num > 0xFFFF) ) {
00244         throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
00245       }
00246       *port = port_num;
00247     } else {
00248       *host = tmpvalue;
00249     }
00250 
00251     return true;
00252   } else {
00253     return false;
00254   }
00255 }
00256 
00257 
00258 /** Parse host:port string.
00259  * The value referenced by the given argn is parsed for the pattern "host:port". If the
00260  * string does not match this pattern an exception is thrown.
00261  * If no port is supplied in the string (plain
00262  * hostname string) the port argument is left unchanged. If the argument has not
00263  * been supplied at all both values are left unchanged. Thus it is safe to put the default
00264  * values into the variables before passing them to this method.
00265  * @param argn argument name to retrieve
00266  * @param host Upon successful return contains the hostname part
00267  * @param port upon successful return contains the port part (unchanged if not supplied)
00268  * @return true, if the argument was supplied, false otherwise
00269  * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
00270  */
00271 bool
00272 ArgumentParser::parse_hostport(const char *argn, std::string &host, unsigned short int &port)
00273 {
00274   if ((__opts.count(argn) == 0) || (__opts[argn] == NULL)) return false;
00275 
00276   std::string tmpvalue = __opts[argn];
00277 
00278   size_t col_idx = tmpvalue.find_last_of(':');
00279   if ( col_idx == tmpvalue.npos ) {
00280     host = tmpvalue;
00281   }
00282   else
00283   {
00284     host = tmpvalue.substr(0, col_idx);
00285     std::string tmpport = tmpvalue.substr(col_idx + 1);
00286 
00287     int port_num = atoi(tmpport.c_str());
00288     if ( (port_num < 0) || (port_num > 0xFFFF) ) {
00289       throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
00290     }
00291     port = port_num;
00292   }
00293   return true;
00294 }
00295 
00296 
00297 /** Parse argument as integer.
00298  * Converts the value of the given argument to an integer.
00299  * @param argn argument name to retrieve
00300  * @return value of string as long int
00301  * @exception IllegalArgumentException thrown if the value cannot be properly
00302  * converted to an integer
00303  * @exception Exception thrown if the argument has not been supplied
00304  */
00305 long int
00306 ArgumentParser::parse_int(const char *argn)
00307 {
00308   if ((__opts.count(argn) > 0) && (__opts[argn] != NULL)) {
00309     char *endptr;
00310     long int rv = strtol(__opts[argn], &endptr, 10);
00311     if ( endptr[0] != 0 ) {
00312       throw IllegalArgumentException("Supplied argument is not of type int");
00313     }
00314     return rv;
00315   } else {
00316     throw Exception("Value for '%s' not available", argn);
00317   }
00318 }
00319 
00320 
00321 /** Parse argument as double.
00322  * Converts the value of the given argument to a double.
00323  * @param argn argument name to retrieve
00324  * @return value of string as double
00325  * @exception IllegalArgumentException thrown if the value cannot be properly
00326  * converted to a double
00327  * @exception Exception thrown if the argument has not been supplied
00328  */
00329 double
00330 ArgumentParser::parse_float(const char *argn)
00331 {
00332   if ((__opts.count(argn) > 0) && (__opts[argn] != NULL)) {
00333     char *endptr;
00334     double rv = strtod(__opts[argn], &endptr);
00335     if ( endptr[0] != 0 ) {
00336       throw IllegalArgumentException("Supplied argument is not of type double");
00337     }
00338     return rv;
00339   } else {
00340     throw Exception("Value for '%s' not available", argn);
00341   }
00342 }
00343 
00344 
00345 /** Parse item as integer.
00346  * Converts the value of the given item to an integer.
00347  * @param index item index
00348  * @return value of string as long int
00349  * @exception IllegalArgumentException thrown if the value cannot be properly
00350  * converted to an integer
00351  * @exception Exception thrown if the argument has not been supplied
00352  */
00353 long int
00354 ArgumentParser::parse_item_int(unsigned int index)
00355 {
00356   if (index < __items.size()) {
00357     char *endptr;
00358     long int rv = strtol(__items[index], &endptr, 10);
00359     if ( endptr[0] != 0 ) {
00360       throw IllegalArgumentException("Supplied argument is not of type int");
00361     }
00362     return rv;
00363   } else {
00364     throw Exception("Value for item %u not available", index);
00365   }
00366 }
00367 
00368 
00369 /** Parse item as double.
00370  * Converts the value of the given item to a double.
00371  * @param index item index
00372  * @return value of string as double
00373  * @exception IllegalArgumentException thrown if the value cannot be properly
00374  * converted to a double
00375  * @exception Exception thrown if the argument has not been supplied
00376  */
00377 double
00378 ArgumentParser::parse_item_float(unsigned int index)
00379 {
00380   if (index < __items.size()) {
00381     char *endptr;
00382     double rv = strtod(__items[index], &endptr);
00383     if ( endptr[0] != 0 ) {
00384       throw IllegalArgumentException("Supplied argument is not of type double");
00385     }
00386     return rv;
00387   } else {
00388     throw Exception("Value for item %u not available", index);
00389   }
00390 }
00391 
00392 
00393 /** Get non-option items.
00394  * @return pointer to vector of pointer to non-argument values. Handled internally,
00395  * do not free or delete!
00396  */
00397 const std::vector< const char* > &
00398 ArgumentParser::items() const
00399 {
00400   return __items;
00401 }
00402 
00403 
00404 /** Get number of non-option items.
00405  * @return number of non-opt items.
00406  */
00407 std::vector< const char* >::size_type
00408 ArgumentParser::num_items() const
00409 {
00410   return __items.size();
00411 }
00412 
00413 
00414 /** Get number of arguments.
00415  * @return number of arguments
00416  */
00417 int
00418 ArgumentParser::argc() const
00419 {
00420   return __argc;
00421 }
00422 
00423 
00424 /** Program argument array as supplied to constructor.
00425  * @return argument array.
00426  */
00427 const char **
00428 ArgumentParser::argv() const
00429 {
00430   return (const char **)__argv;
00431 }
00432 
00433 
00434 /** Get name of program.
00435  * @return the name of the program (argv[0] of argument vector supplied to constructor).
00436  */
00437 const char *
00438 ArgumentParser::program_name() const
00439 {
00440   return __program_name;
00441 }
00442 
00443 
00444 } // end namespace fawkes