1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
#ifndef SIMPLECLPARSER_H
#define SIMPLECLPARSER_H
#include "EPropertyList.h"
/**
Copyright (C) 2002, stephan@wanderinghorse.net
Released under the GNU Lesser General Public License
ESimpleCLParser is an object for handling command line options. Use it like
this:
#include <iostream>
#include "ESimpleCLParser.h"
ESimpleCLParser opts;
#define VERBOSE if( opts.getBool( "verbose", false ) ) cerr
int main( int argc, char **argv ) {
opts.setArgs( argc, argv );
opts.set( "dosomething", ! opts.getBool( "donothing", false ) );
if( ! opts.getBool( "dosomething", true ) ) { exit( 0 )); }
int myint = opts.getInt( "width" );
double myangle = opts.getDouble( "angle", 0.0 );
VERBOSE << "This is a verbose message." << endl;
return opts.getInt( "errorcode", 0 );
}
(that code's just off the top of my head - it may not compile as-is.)
See the EPropertyList object's API for a full list of accessor functions.
Supported command-line formats:
-foo bar [that is, -foo == "bar"]
is the same as:
[--foo bar] [-foo=bar] [--foo=bar]
-foo -bar false [-foo == true, -bar == false]
-foo -bar=false [same]
--double-dashed "some string value"
--double-dashed="some string value" [same as previous line]
Whether you use single or double dashes is irrelevant, but you must call
getXXX() with the same key as was actually passed on the command-line,
like so:
int width = opts.getInt( "-width", opts.getInt( "--width", 42 ) );
will check for -width first, then --width, defaulting to 42.
Alternately, if you use this form:
opts.getString( "foo" ); // WITHOUT a dash
the following options are searched:
a) foo
b) -foo
c) --foo
so the above call may actually result in getting the value from -foo or
--foo. This is a potential logic problem if your application uses two
semantically-different arguments like -force and
--force. In this case a call to getXXX( "force" ) would find -force
and not --force. Use getXXX( "-force" ) or getXXX("--force") to
avoid this ambiguity. The dashed versions of an argument are only
sought after if getXXX() is called without a dash before the key.
A note to Qt users: call setArgs() on this object before calling
QApplication a(argc, argv ), or QApplication will steal any argument
called -name (and possibly others), removing it from argv. i.e.,
if you do not call setArgs() on this object first, QApplication may
steal arguments so you'll never see them. Been there, done that.
Known Bugs and/or gotchyas:
Negative numbers:
--boolflag -123=something
will be parsed as:
[--boolflag == true] [-123=something]
Search the .cpp file for 'negative' and you'll find where this bug lives.
Since numeric arguments are so rare this is not such a big deal, i think.
i can think of only a few real-world examples which use args like -1:
ssh, [GNU] xargs, lpr, ...
Along those same lines:
--bool -234 --foobar
will be parsed as:
[--bool == -234] [--foobar == true]
Which i consider to be correct. If you want to set --bool to a negative
number use: --bool=-123
i hate the inconsistency this adds, though. :/
*/
class ESimpleCLParser : public EPropertyList
{
public:
ESimpleCLParser();
ESimpleCLParser( int argc, char *argv[], int startAt=1 );
virtual ~ESimpleCLParser();
/**
get/setHelp() text for a given key.
*/
virtual void setHelp( const std::string &key, const std::string &text );
virtual const std::string getHelp( const std::string &key ) const;
/**
getString() is overridden to add a special case to all getXXX() calls
made via the EPropertyList API: if a getXXX key ) function is called with
a key which does not start with a dash (-) character and they key cannot
be found in our list then -key and --key will be tried.
This means that, assuming the above sample code is in place, the following
would work:
~/ > myapp --foo=17.34
...
double d = opts.getDouble( "foo", 0.0 ); // d == 17.34
As will this:
opts.set( "--mykey", "myvalue" );
...
cerr << "mykey="<< opts.getString( "mykey" ) << endl;
Note, however, that command-line arguments passed without a leading dash
are not treated as arguments, and will not be inside this object if the command-line
arguments are passed in via setArgs().
Additionally, it is important to note that if key is passed in with a leading "-"
then the additional "dash checking" is NOT done. That is, if you call:
opts.getString( "-d", 0.0 );
then ONLY the entry -d will match, and not --d.
*/
virtual std::string getString( const std::string &key, const std::string & defaultVal = std::string() ) const;
/**
* Makes a half-hearted attempt to parse out any args (begining with "-").
* Any args without values passed after them are assigned the value true.
* Sample valid command lines:
*
* foo --a --b foo --c bar --f
* (--a and --f == true, --b == "foo" and --c == "bar")
* foo --a eat --b this --c "you lazy bum"
* (--a==eat, --b==this, --c=="you lazy bum")
* foo --a=b --c d
* (--a == b, --c == d)
*
* These are identical for purposes of getXXX( "c" ):
* [... -c=-1.0 ...] [... -c -1.0 ...] [... --c 1.0 ...] [... --c=1.0 ...]
*
*
* To get the values, call the EPropertyList API functions like:
* int foo = parser.getInt( "--i" ); // getInt("i") now works for -i or --i :)
* bool bar = parser.getBool( "--b" ); // or getBool( "b") for -b or --b
* 'startat' says which element in argv[] to start with. This defaults to 1 because it
* is assumed that this will be passed from main(), and we don't need the application's
* name (argv[0]) in the args list (if it doesn't start with a dash it wouldn't
* be treated as an argument, anyway).
* If argpre = 0 then it uses the default argument prefix (defaults to "-").
* If it is >0 then that is used as a char * prefix
* for all arguments.
*
* Note that the values are added to this object (or overwrite existing entries), and the list
* is not cleared by this function.
*/
virtual int setArgs( int argc, char *argv[], int startAt=0,const char *argpre = "-" );
/**
* Similar to parse( int... ) except that this one reads a whole line of options, parses that into
* an array, then passes it to parse(...). Note that this _may_ (but should not, ideally) behave slightly
* differently from arguments passed to the other form, which typically come in as command-line args
* (parsed by your shell). This functions uses a EStringTokenizer to do it's parsing, so
* any differences in behaviour should be resolved there. i am not aware of any differences.
*/
virtual int setArgs( std::string args, std::string separators = " " );
/**
Creates a "usage"-like string for this object containing all keys for which
setHelp() has been called. If showcurrentvals is true then the current values
are also added to th string, otherwise they are left out.
Note that the order of the dumped help text/keys is currently undefined,
but appears to be alphabetic (this is certainly C++-lib-dependent, though.)
TODO: maintain the order of args, using the order from setHelp().
Sample:
in main() do:
ESimpleCLParser args;
args.setArgs( argc, argv );
if( args.getBool( "help", args.getBool( "?", false ) ) )
{ // triggers on --help, -help, -? or --?
cerr << args.dumpHelp();
exit( 0 );
}
Note regarding ELib::libArgs():
By default the object returned by ELib::libArgs() might have some help for elib
options like e-debug and e-verbose. To remove them simply setHelp( "e-verbose", "" )
before calling this function.
*/
virtual const std::string dumpHelp( bool showcurrentvals = true ) const;
/**
Returns true if any of the following are set to any value: -help, --help, -?, --?
*/
virtual bool isHelpSet();
private:
EPropertyList helpmap;
};
#endif // SIMPLECLPARSER_H
|