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, 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