JavaPopt is based on the GNU/Linux popt library for C programs, but with modifications to make it more suitable for the Java environment. Developers familiar with C popt should find JavaPopt straightforward.
This software has been made available in the hope that it will be found useful. There is no warranty; please e-mail comments, bug reports and (even better) bug fixes to the author. Please feel free to use this software in any way you see fit, except to claim it as your own work.
java -classpath classes:moreclasses -Xdebug -Dx.y=hello -Dx.c=hello2 myclass rpm -i --force -nodeps mypackage.rpm g++ -I include1 -I include2 -fstrict -mcpu=i386 file1.cpp file2.cppIt the first example, the switch `-classpath' is followed by one argument, and this combination should appear exactly once in the invocation. `-Xdebug', similarly, appears exactly once, but has no arguments. There can be any number of `-D' switches, but note that the argument follows `-D' directly, there is no space between the -D and argument.
In Popt terminology, `-class' and `-D' are `switch arguments', that is, they are introduced and specified by switches (-xxx). `-Xdebug' is also a switch argument, but with no arguments. We will refer to this simply as a `switch' or a `flag'. `myclass' is a `non-switch argument'. It is not introduced by a switch, and therefore its interpretation depends on the order in which it appears on the command line.
In the second example we have three different types of flag: a single-char flag `-i', a long-name flag `--force'
and a long-name flag `-nodeps' specified as if it were a single-char flag. Each of these must appear
exactly once, or not at all. Conventionally some
applications support the grouping of single-char flags, e.g., rm -rf file, which is
equivalent to rm -r -f file. The `rpm' example also requires a single non-switch argument.
In the third example we have a repeated switch argument `-I', where the argument and the switch can appear any number of times. There is a also a long-name switch argument where the argument `-mcpu=i386' where the argument is separated from the switch by an equal sign, not a space.
String name = popt.getString("name");
it does not matter how the name was supplied. This means that the command-line syntax can be
modified without changing the logic of the program.
String, Integer and
Double are supported. String is, of course, the most general, and
can contain any text. Double and Integer attempt to convert the supplied
text into the appropriate class. This may fail, of course, if the command-line does not
supply appropriate data. There is, as yet, no support for other Java type (Date, for
example), so these should be entered as Strings and converted by the application.
parseSwitchArguments() to separate the switch and
non-switch arguments, and then retrieving the non-switch arguments by
calling getLeftoverArgs().
Or, as another alternative, the application can set a bunch of non-switch
args by calling setLeftoverArgs() and then call parseNonSwitchArgs
to process them.
Here is an example of this mode of operation.
Popt popt = new Popt (args);
// Tell Popt what arguments we accept. There are two versions of addSwitchSpec(), both
// used here. The first version is for flags, which don't take any arguments. The
// second is for switch arguments, where the argument name and type are required. Note that
// the argument name is only used for usage messages.
// The arguments for the first versions are: identifier, shortname,
// longname, isCompulsory, description, allowDuplicates
// For the second version the additional arguments are for the name and type
popt.addSwitchSpec ("version", 'v', "version", false, "show version", false);
popt.addSwitchSpec ("double", 'd', "double", false, "a real number", "double", Double.class, true);
popt.addSwitchSpec ("string", 's', "string", false, "a piece of text", "string", String.class, true);
popt.addSwitchSpec ("integer", 'i', "integer", false, "an integer", "string", Integer.class, true);
popt.addSwitchSpec ("longflag", (char)0, "longflag", false, "a flag", true);
// addNonSwitchSpec() specifies arguments that are not introduced by switches. If there are
// a variable number of them the application may prefer to handle them itself.
popt.addNonSwitchSpec ("message", "message", false, "a piece of text", String.class);
// Add help arguments for --help, -h, and -?
popt.addHelp (true, true, true);
// Parse the command line.
// parse() returns false if it fails
if (popt.parse() == false)
{
// Parse failed: say why...
System.err.println (popt.getErrorMessage());
System.err.println ("Usage: Popt " + popt.getShortUsage());
// ...and show the usage message
System.err.println (popt.getUsage());
}
else if (popt.supplied("help"))
{
// `help' is a flag, not at argument. It is either supplied or not
System.out.println ("Usage: Popt " + popt.getShortUsage());
System.out.println (popt.getUsage());
}
else if (popt.supplied("version"))
{
// `version' is also a flag
System.out.println ("JavaPopt version 1.0 (c)2000 Kevin Boone");
}
else
{
// `double' takes a value (a number). If supplied, get the number.
if (popt.supplied("double"))
System.out.println ("double=" + popt.getDouble("double"));
else
System.out.println ("double argument not supplied");
// ... process other arguments ...
}
PoptParseHandler. This
interface can be implemented by any class that wants to know when an argument has
been matched. If has one method, handleArg which is called for each
match, specifying the identifier and the argument as an Object. The
application's implementation of PoptParseHandler is responsible for
casting this Object into the real type.
A parse handler is set like this:
popt.setPoptParseHandler(new MyParseHandler());
setting it to null disables this feature.
Now, every time the duplicate copies are matched the handler will be called, and
it can take whatever action is required. The handler should return true
if the processing was successful, and false otherwise; in the latter
case parsing will be abandonned. The handler should ideally call setErrorMessage
on the supplied Popt object, because the application will probably go on to
call getErrorMessage() to find why parsing failed.
getShortUsage() and getUsage
for more details.
In addition, it can add `help' arguments to the argument list, if the application
calls addHelp(). However, JavaPopt can't respond to a `--help' request by
printing a usage message automatically, as this would not be appropriate in many applications.
So the application will still need to check the `help' argument after parsing.
--hello --Helloif they match anything, both arguments will match the same entry. Short switch names can be made case insensitive, if the
ignoreCase
argument to the constructor is true. Popt does not check whether
this it is safe to do this. In general it will be unsafe if you have entries
in the switch table that are distinguished only by the case of their short
names. In other words, if you want this line
-h -Hto be treated as two separate switches you must ensure that
ignoreCase
is false.
Whether you set case sensitivity on or off, it is generally regarded to have command-line switches that are distinguished only by case. Most people find command-line arguments awkward enough at best.
getArg. This is the most general technique, and returns an
Object, or null if the argument was not supplied.
Convenience functions are supplied to make it easier to retrieve arguments of
known type. getString(), getInt() and getDouble()
return the arguments as a String, an int and a double.
Note that there are no possible int or double values that
mean `no value supplied', so these methods throw a run-time exception if the value
requested was not supplied by the command line. Therefore it is best to call
Popt.supplied() to ensure that a value exists.
getIntOrDefault
takes two arguments: the identifier of the argument, and the default value. If the
argument was not supplied on the command line, the default is returned instead.
null).
Popt correctly detects attempts to specify numbers that are out of range. E.g.,
parse() will return false if the user tries to specify
an integer argument `200000000000000', as this is too big for an integer. If you need to
process large-precision numbers, specify them as Strings, and parse them in the application.
protected String getUnmatchedSwitchMessage(); protected String getDuplicateSwitchMessage(); protected String getBadDoubleMessage(); protected String getBadIntegerMessage();Look in the javadoc comments for details of the circumstances under which these messages will be generated.
If you want `--help', etc., in a different language, simply forego the use of
addHelp and add your own arguments in the usual way.
myprog -2
Is `-2' a switch called `2', or a negative number? If there is no switch
`-2' listed in the specification, does the user mean minus-2, or is it a typing
mistake (e.g., should have been -w, for example)? JavaPopt assumes that
the minus sign followed by a digit is a number, not a numeric switch, unless
the argument numericSwitches was true in the constructor.
In the latter case, arguments cannot be negative numbers. This strategy is chosen
for its simplicity, and is unambguous, but will not work where a mixture of
negative numbers and numeric options can appear on the command line.
longName is the empty
String. This will be matched to that string during parsing.
myprog -verbose file1 file2
myprog file1 -verbose file2
While this is usually what is required, it won't suit all applications.