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, const char *opt_string, option *long_options)
00090 {
00091   _argc = argc;
00092   _argv = argv;
00093 
00094   _opts.clear();
00095   _items.clear();
00096 
00097 #ifdef _GNU_SOURCE
00098   _program_name = strdup(basename( argv[0] ));
00099 #else
00100   // Non-GNU variants may modify the sting in place
00101   char *tmp = strdup(argv[0]);
00102   _program_name = strdup(basename(tmp));
00103   free(tmp);
00104 #endif
00105 
00106   if (long_options == NULL) {
00107     int c ;
00108     char tmp[2];
00109 
00110     while ((c = getopt(argc, argv, opt_string)) != -1) {
00111       if (c == '?') {
00112         throw UnknownArgumentException(c);
00113       } else if (c == ':') {
00114         throw MissingArgumentException(c);
00115       }
00116       sprintf(tmp, "%c", c);
00117       _opts[ tmp ] = optarg;
00118     }
00119   } else {
00120     int opt_ind = 0;
00121     int c;
00122     while ((c = getopt_long(argc, argv, opt_string, long_options, &opt_ind)) != -1) {
00123       if (c == '?') {
00124         throw UnknownArgumentException(c);
00125       } else if (c == 0) {
00126         // long options
00127         _opts[ long_options[opt_ind].name ] = optarg;
00128       } else {
00129         char tmp[2];
00130         sprintf(tmp, "%c", c);
00131         _opts[ tmp ] = optarg;
00132       }
00133     }
00134   }
00135 
00136   _items.clear();
00137   int ind = optind;
00138   while (ind < argc) {
00139     _items.push_back( argv[ind++] );
00140   }
00141 
00142 }
00143 
00144 
00145 /** Destructor. */
00146 ArgumentParser::~ArgumentParser()
00147 {
00148   free(_program_name);
00149   _opts.clear();
00150 }
00151 
00152 
00153 /** Check if argument has been supplied.
00154  * @param argn argument name to check for
00155  * @return true, if the argument was given on the command line, false otherwise
00156  */
00157 bool
00158 ArgumentParser::has_arg(const char *argn)
00159 {
00160   return (_opts.count((char *)argn) > 0);
00161 }
00162 
00163 
00164 /** Get argument value.
00165  * Use this method to get the value supplied to the given option.
00166  * @param argn argument name to retrieve
00167  * @return the argument value. Pointer to static program array. Do not free!
00168  * Returns NULL if argument was not supplied on command line.
00169  */
00170 const char *
00171 ArgumentParser::arg(const char *argn)
00172 {
00173   if (_opts.count((char *)argn) > 0) {
00174     return _opts[ (char *)argn ];
00175   } else {
00176     return NULL;
00177   }
00178 }
00179 
00180 
00181 /** Get argument while checking availability.
00182  * The argument will be a newly allocated copy of the string. You have to
00183  * free it after you are done with it.
00184  * @param argn argument name to retrieve
00185  * @param value a pointer to a newly allocated copy of the argument value will
00186  * be stored here if the argument has been found.
00187  * The value is unchanged if argument was not supplied.
00188  * @return true, if the argument was supplied, false otherwise
00189  */
00190 bool
00191 ArgumentParser::arg(const char *argn, char **value)
00192 {
00193   if (_opts.count((char *)argn) > 0) {
00194     *value = strdup(_opts[ (char *)argn ]);
00195     return true;
00196   } else {
00197     return false;
00198   }
00199 }
00200 
00201 
00202 /** Parse host:port string.
00203  * The value referenced by the given argn is parsed for the pattern "host:port". If the
00204  * string does not match this pattern an exception is thrown.
00205  * The host will be a newly allocated copy of the string. You have to
00206  * free it after you are done with it. If no port is supplied in the string (plain
00207  * hostname string) the port argument is left unchanged. If the argument has not
00208  * been supplied at all both values are left unchanged. Thus it is safe to put the default
00209  * values into the variables before passing them to this method. Note however that you
00210  * have to free the returned host string in case of a successful return, and only in
00211  * that case probably!
00212  * @param argn argument name to retrieve
00213  * @param host Upon successful return contains a pointer to a newly alloated string
00214  * with the hostname part. Free it after you are finished.
00215  * @param port upon successful return contains the port part
00216  * @return true, if the argument was supplied, false otherwise
00217  * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
00218  */
00219 bool
00220 ArgumentParser::parse_hostport(const char *argn, char **host, unsigned short int *port)
00221 {
00222   if (_opts.count((char *)argn) > 0) {
00223     char *tmpvalue = strdup(_opts[ (char *)argn ]);
00224 
00225     if ( strchr(tmpvalue, ':') != NULL ) {
00226       char *save_ptr;
00227       *host = strtok_r(tmpvalue, ":", &save_ptr);
00228       char *tmpport = strtok_r(NULL, "", &save_ptr);
00229 
00230       int port_num = atoi(tmpport);
00231       if ( (port_num < 0) || (port_num > 0xFFFF) ) {
00232         throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
00233       }
00234       *port = port_num;
00235     } else {
00236       *host = tmpvalue;
00237     }
00238 
00239     return true;
00240   } else {
00241     return false;
00242   }
00243 }
00244 
00245 
00246 /** Parse host:port string.
00247  * The value referenced by the given argn is parsed for the pattern "host:port". If the
00248  * string does not match this pattern an exception is thrown.
00249  * If no port is supplied in the string (plain
00250  * hostname string) the port argument is left unchanged. If the argument has not
00251  * been supplied at all both values are left unchanged. Thus it is safe to put the default
00252  * values into the variables before passing them to this method.
00253  * @param argn argument name to retrieve
00254  * @param host Upon successful return contains the hostname part
00255  * @param port upon successful return contains the port part (unchanged if not supplied)
00256  * @return true, if the argument was supplied, false otherwise
00257  * @exception OutOfBoundsException thrown if port is not in the range [0..65535]
00258  */
00259 bool
00260 ArgumentParser::parse_hostport(const char *argn, std::string &host, unsigned short int &port)
00261 {
00262   if (_opts.count(argn) == 0) return false;
00263 
00264   std::string tmpvalue = _opts[argn];
00265 
00266   size_t col_idx = tmpvalue.find_last_of(':');
00267   if ( col_idx == tmpvalue.npos ) {
00268     host = tmpvalue;
00269   }
00270   else
00271   {
00272     host = tmpvalue.substr(0, col_idx);
00273     std::string tmpport = tmpvalue.substr(col_idx + 1);
00274 
00275     int port_num = atoi(tmpport.c_str());
00276     if ( (port_num < 0) || (port_num > 0xFFFF) ) {
00277       throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
00278     }
00279     port = port_num;
00280   }
00281   return true;
00282 }
00283 
00284 
00285 /** Parse argument as integer.
00286  * Converts the value of the given argument to an integer.
00287  * @param argn argument name to retrieve
00288  * @return value of string as long int
00289  * @exception IllegalArgumentException thrown if the value cannot be properly
00290  * converted to an integer
00291  * @exception Exception thrown if the argument has not been supplied
00292  */
00293 long int
00294 ArgumentParser::parse_int(const char *argn)
00295 {
00296   if (_opts.count((char *)argn) > 0) {
00297     char *endptr;
00298     long int rv = strtol(_opts[argn], &endptr, 10);
00299     if ( endptr[0] != 0 ) {
00300       throw IllegalArgumentException("Supplied argument is not of type int");
00301     }
00302     return rv;
00303   } else {
00304     throw Exception("Value for '%s' not available", argn);
00305   }
00306 }
00307 
00308 
00309 /** Parse argument as double.
00310  * Converts the value of the given argument to a double.
00311  * @param argn argument name to retrieve
00312  * @return value of string as double
00313  * @exception IllegalArgumentException thrown if the value cannot be properly
00314  * converted to a double
00315  * @exception Exception thrown if the argument has not been supplied
00316  */
00317 double
00318 ArgumentParser::parse_float(const char *argn)
00319 {
00320   if (_opts.count((char *)argn) > 0) {
00321     char *endptr;
00322     double rv = strtod(_opts[argn], &endptr);
00323     if ( endptr[0] != 0 ) {
00324       throw IllegalArgumentException("Supplied argument is not of type double");
00325     }
00326     return rv;
00327   } else {
00328     throw Exception("Value for '%s' not available", argn);
00329   }
00330 }
00331 
00332 
00333 /** Parse item as integer.
00334  * Converts the value of the given item to an integer.
00335  * @param index item index
00336  * @return value of string as long int
00337  * @exception IllegalArgumentException thrown if the value cannot be properly
00338  * converted to an integer
00339  * @exception Exception thrown if the argument has not been supplied
00340  */
00341 long int
00342 ArgumentParser::parse_item_int(unsigned int index)
00343 {
00344   if (index < _items.size()) {
00345     char *endptr;
00346     long int rv = strtol(_items[index], &endptr, 10);
00347     if ( endptr[0] != 0 ) {
00348       throw IllegalArgumentException("Supplied argument is not of type int");
00349     }
00350     return rv;
00351   } else {
00352     throw Exception("Value for item %u not available", index);
00353   }
00354 }
00355 
00356 
00357 /** Parse item as double.
00358  * Converts the value of the given item to a double.
00359  * @param index item index
00360  * @return value of string as double
00361  * @exception IllegalArgumentException thrown if the value cannot be properly
00362  * converted to a double
00363  * @exception Exception thrown if the argument has not been supplied
00364  */
00365 double
00366 ArgumentParser::parse_item_float(unsigned int index)
00367 {
00368   if (index < _items.size()) {
00369     char *endptr;
00370     double rv = strtod(_items[index], &endptr);
00371     if ( endptr[0] != 0 ) {
00372       throw IllegalArgumentException("Supplied argument is not of type double");
00373     }
00374     return rv;
00375   } else {
00376     throw Exception("Value for item %u not available", index);
00377   }
00378 }
00379 
00380 
00381 /** Get non-option items.
00382  * @return pointer to vector of pointer to non-argument values. Handled internally,
00383  * do not free or delete!
00384  */
00385 const std::vector< const char* > &
00386 ArgumentParser::items() const
00387 {
00388   return _items;
00389 }
00390 
00391 
00392 /** Get number of non-option items.
00393  * @return number of non-opt items.
00394  */
00395 std::vector< const char* >::size_type
00396 ArgumentParser::num_items() const
00397 {
00398   return _items.size();
00399 }
00400 
00401 
00402 /** Get number of arguments.
00403  * @return number of arguments
00404  */
00405 int
00406 ArgumentParser::argc() const
00407 {
00408   return _argc;
00409 }
00410 
00411 
00412 /** Program argument array as supplied to constructor.
00413  * @return argument array.
00414  */
00415 const char **
00416 ArgumentParser::argv() const
00417 {
00418   return (const char **)_argv;
00419 }
00420 
00421 
00422 /** Get name of program.
00423  * @return the name of the program (argv[0] of argument vector supplied to constructor).
00424  */
00425 const char *
00426 ArgumentParser::program_name() const
00427 {
00428   return _program_name;
00429 }
00430 
00431 } // end namespace fawkes