Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members

argv_parser.h

00001 #ifndef s11n_ARGV_PARSER_H 00002 #define s11n_ARGV_PARSER_H 1 00003 00004 // Author: stephan@s11n.net 00005 // License: Public Domain 00006 00007 #include "property_store.h" 00008 namespace s11n { 00009 /** 00010 argv_parser is an object for parsing command line options. It exists 00011 in the s11n source tree only to ease development of test apps, 00012 and should not be considered to be part of the core library. 00013 00014 00015 00016 Use it like this: 00017 00018 <pre> 00019 #include &lt;iostream&gt; 00020 #include "argv_parser.h" 00021 00022 #define VERBOSE if( opts.get( "verbose", false ) ) cerr 00023 00024 int main( int argc, char **argv ) 00025 { 00026 argv_parser & opts = argv_parser::args( argc, argv ); 00027 opts.set( "dosomething", ! opts.get_bool( "donothing", false ) ); 00028 if( ! opts.get( "dosomething", true ) ) { exit( 0 )); } 00029 int myint = opts.get( "width", 20 ); 00030 double myangle = opts.get( "angle", 0.0 ); 00031 00032 VERBOSE << "This is a verbose message." << endl; 00033 return opts.get( "errorcode", 0 ); 00034 } 00035 </pre> 00036 (that code's just off the top of my head - it may not compile as-is.) 00037 00038 Note that client code outside of main can then get access 00039 to the args via the static function args(): 00040 00041 <pre> 00042 argv_parser & opts = argv_parser::args(); 00043 </pre> 00044 00045 See the property_store object's API for a full list of accessor functions. 00046 00047 Supported command-line formats: 00048 <pre> 00049 -foo bar [that is, -foo == "bar"] 00050 is the same as: 00051 [--foo bar] [-foo=bar] [--foo=bar] 00052 00053 -foo -bar false [-foo == true, -bar == false] 00054 -foo -bar=false [same] 00055 --double-dashed "some string value" 00056 --double-dashed="some string value" [same as previous line] 00057 </pre> 00058 00059 Whether you use single or double dashes is irrelevant, but you must call 00060 get() with the same key as was actually passed on the command-line, 00061 like so: 00062 00063 int width = opts.getInt( "-width", opts.getInt( "--width", 42 ) ); 00064 will check for -width first, then --width, defaulting to 42. 00065 00066 Alternately, if you use this form: 00067 opts.get_string( "foo" ); // WITHOUT a dash 00068 the following options are searched: 00069 <ol> 00070 <li>foo 00071 <li>-foo 00072 <li>--foo 00073 </ol> 00074 00075 so the above call may actually result in getting the value from -foo or 00076 --foo. This is a potential logic problem if your application uses two 00077 semantically-different, like-named arguments like -force and 00078 --force. In this case a call to get( "force" ) would find -force 00079 and not --force. Use get( "-force" ) or get("--force") to 00080 avoid this ambiguity. The dashed versions of an argument are only 00081 sought after if get() is called without a dash before the key. 00082 00083 These sample dash-searching rules apply to is_set(). 00084 00085 00086 A note to Qt users: call args() on this object before calling 00087 QApplication a(argc, argv ), or QApplication will steal any argument 00088 called -name (and possibly others), removing it from argv. i.e., 00089 if you do not call args() on this object first, QApplication may 00090 steal arguments so you'll never see them. Been there, done that. 00091 00092 Known Bugs and/or gotchyas: 00093 00094 Negative numbers: 00095 00096 <pre> 00097 --boolflag -123=something 00098 </pre> 00099 00100 will be parsed as: 00101 00102 <pre> 00103 [--boolflag == true] [-123=something] 00104 </pre> 00105 00106 Search the .cpp file for 'negative' and you'll find where this bug lives. 00107 Since numeric arguments are so rare this is not such a big deal, i think. 00108 i can think of only a few real-world examples which use args like -1: 00109 ssh, [GNU] xargs, head, tail, lpr, ... okay, maybe they aren't so uncommon :/ 00110 00111 Along those same lines: 00112 00113 <pre> 00114 --bool -234 --foobar 00115 </pre> 00116 will be parsed as: 00117 <pre> 00118 [--bool == -234] [--foobar == true] 00119 </pre> 00120 00121 Which i consider to be correct for most cases. If you want to set 00122 --bool to a negative number use: --bool=-123 00123 If you want to force a boolean value in this case: 00124 00125 <pre> 00126 --bool=true -234 546 00127 </pre> 00128 00129 parses as: 00130 00131 <pre> 00132 --bool=true 00133 -234=456 00134 </pre> 00135 00136 i hate the inconsistency this adds, though. :/ 00137 */ 00138 00139 class argv_parser : public property_store 00140 { 00141 public: 00142 /** 00143 Creates a new parser using the given 00144 arguments array and arg count. 00145 */ 00146 argv_parser( int argc, char *argv[], int startAt=0 ); 00147 argv_parser(); 00148 virtual ~argv_parser(); 00149 00150 /** 00151 args( int, char * ) should be called once from your 00152 main() if you want clients to be able to use args() 00153 to get at them. 00154 */ 00155 static argv_parser & args( int argc, char *argv[] ); 00156 00157 /** 00158 Returns the object containing the arguments 00159 supplied to args(int,char**). 00160 */ 00161 static argv_parser & args(); 00162 00163 /** 00164 get/set_help() text for a given key. 00165 */ 00166 virtual void set_help( const std::string &key, const std::string &text ); 00167 00168 /** 00169 Returns the help text associated with key. 00170 */ 00171 virtual const std::string getHelp( const std::string &key ) const; 00172 00173 /** 00174 Re-implemented to check keys -FOO and --FOO if key FOO is 00175 not found. 00176 */ 00177 virtual bool is_set( const std::string &key ) const; 00178 00179 /** 00180 get_string() is overridden to add a special case to 00181 all get() calls made via the property_store API: if 00182 a get() function is called with a key which does 00183 not start with a dash (-) character and they key 00184 cannot be found in our list then -key and --key 00185 will be tried. 00186 00187 This means that, assuming the above sample code is 00188 in place, the following would work: 00189 00190 <pre> 00191 ~/ > myapp --foo=17.34 00192 ... 00193 double d = opts.getDouble( "foo", 0.0 ); // d == 17.34 00194 </pre> 00195 00196 As will this: 00197 <pre> 00198 opts.set( "--mykey", "myvalue" ); 00199 ... 00200 cerr << "mykey="<< opts.get_string( "mykey" ) << endl; 00201 </pre> 00202 00203 Note, however, that command-line arguments passed 00204 without a leading dash are not treated as 00205 arguments, and will not be inside this object if 00206 the command-line arguments are passed in via 00207 args(). Additionally, it is important to note that 00208 if key is passed in with a leading "-" then the 00209 additional "dash checking" is NOT done. That is, if 00210 you call: 00211 00212 <pre> 00213 opts.get_string( "-d", 0.0 ); 00214 </pre> 00215 00216 then ONLY the entry -d will match, and not --d. 00217 */ 00218 virtual std::string get_string( const std::string &key, const std::string & defaultVal = std::string() ) const; 00219 00220 /** 00221 * Makes a half-hearted attempt to parse out any args (begining with "-"). 00222 * Any args without values passed after them are assigned the value true. 00223 * Sample valid command lines: 00224 * 00225 <pre> 00226 * foo --a --b foo --c bar --f 00227 * (--a and --f == true, --b == "foo" and --c == "bar") 00228 * foo --a eat --b this --c "you lazy bum" 00229 * (--a==eat, --b==this, --c=="you lazy bum") 00230 * foo --a=b --c d 00231 * (--a == b, --c == d) 00232 </pre> 00233 * 00234 * These are identical for purposes of get( "c" ): 00235 <pre> 00236 * [... -c=-1.0 ...] [... -c -1.0 ...] [... --c 1.0 ...] [... --c=1.0 ...] 00237 </pre> 00238 * 00239 * 00240 * To get the values, call the property_store API functions like: 00241 <pre> 00242 * int foo = parser.getInt( "--i" ); // getInt("i") now works for -i or --i :) 00243 * bool bar = parser.get_bool( "--b" ); // or get_bool( "b") for -b or --b 00244 </pre> 00245 * 'startat' says which element in argv[] to start with. 00246 * 00247 * If argpre = 0 then it uses the default argument prefix (defaults to "-"). 00248 * If it is >0 then that is used as a char * prefix 00249 * for all arguments. 00250 * 00251 * This function also stores all processed values in a way familiar to bash and perl users: 00252 * $0 = the first argument, 00253 * $1 = the second arg 00254 * etc. 00255 * Thus given: 00256 <pre> 00257 * ./foo --arg1 val1 --arg2=foo 00258 </pre> 00259 * We have: 00260 <pre> 00261 * myargs["$1"] == "--arg1" 00262 * myargs["$3"] == "--arg2=foo" (it is arguably useful to split these, but then usage would be 00263 * inconsistent with bash/perl. However, as it is now it is inconsistent 00264 * with the results of "--arg2 foo" :/) 00265 </pre> 00266 * Note that the values are added to this object (or overwrite existing entries), and the list 00267 * is not cleared by this function. 00268 */ 00269 virtual int args( int argc, char *argv[], int startAt, const char *argpre = "-" ); 00270 00271 /** 00272 * Similar to parse( int... ) except that this one reads a whole line of options, parses that into 00273 * an array, then passes it to parse(...). Note that this _may_ (but should not, ideally) behave slightly 00274 * differently from arguments passed to the other form, which typically come in as command-line args 00275 * (parsed by your shell). This functions uses a stdstring_tokenizer to do it's parsing, so 00276 * any differences in behaviour should be resolved there. i am not aware of any differences. 00277 */ 00278 virtual int args( std::string args, std::string separators = " " ); 00279 00280 /** 00281 Creates a "usage"-like string for this object containing all keys for which 00282 set_help() has been called. If showcurrentvals is true then the current values 00283 are also added to th string, otherwise they are left out. 00284 00285 Note that the order of the dumped help text/keys is 00286 alphabetic (because that's how the container object 00287 stores them). 00288 00289 TODO: maintain the order of args, using the order from set_help(). 00290 00291 Sample: 00292 00293 <pre> 00294 in main() do: 00295 argv_parser & args = argv_parser::args( argc, argv ); 00296 if( args.is_hel_set() ) 00297 { // triggers on --help, -help, -? or --? 00298 cerr << args.dump_help(); 00299 exit( 0 ); // some apps exit with a non-zero for help, some don't. 00300 } 00301 </pre> 00302 */ 00303 virtual const std::string dump_help( bool showcurrentvals = true ) const; 00304 00305 /** 00306 Returns true if -help --help, -? or --? is set. 00307 */ 00308 virtual bool is_help_set(); 00309 00310 private: 00311 property_store helpmap; 00312 }; 00313 }; // namespace s11n 00314 #endif // s11n_ARGV_PARSER_H

Generated on Wed Jul 28 16:04:14 2004 for s11n by doxygen 1.3.7