Fawkes API Fawkes Development Version
|
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