SourceForge Logo
clopt library
v1.7.1 Copyright © 2000,2001,2002,2003,2004 dr. Cristiano Sadun

Go here to go to the 'download' paragraph. API docs can be found at http://clopt.sourceforge.net/api/index.html.

Purpose

This library eases the ever-recurring task of parsing, interpreting and implementing command line options. It's a Java library, so it's of little use if you don't use Java. Since when I want a library to do something I don't usually like to have to grab some megabytes of stuff that's around there but has nothing to do with the something, you'll find that this library is lean, (reasonably) clean, self-contained and small.

The main feature of the library is the ability of binding automatically command line options to member variable in a single step. For example, if a class is defined as

 class MyCommandLineTool {

  private CmdLineOptions co; // The library object
  private int param; // Variable to be bound to a command-line option

 }
int its constructor it is possible to write simply
  MyCommandLineTool() {
    co = new CmdLineOptions("Example tool");
    co.setOnOption("param", this); // Do the binding
    ...
  }
to bind the option "-param" to the member variable param: when the user will run the tool, the command line argument -param 10 will automatically assing the integer value 10 to the member variable param, fail gracefully if the argument cannot be interpreted as an int, etc.

Changes from version 1.6

Changes from version 1.5.2

Changes from version 1.5

Changes from version 1.4

Changes from version 1.3

Changes from version 1.2

Changes from version 1.1

Changes from version 1.0

Usage

The approach used by the library is to allow the client code to define Handler objects which are called during parsing and handle single options, allowing whatever complex response to be placed and coded easily. Built-in handlers make things even easier, allowing common handling to be executed with a single method invocation.

The library lives in the package org.sadun.util. The main class, responsible for parsing and acting as a registry for the handlers, is CmdLineOptions. You usually want to create one instance of this class, set up your option handlers, invoke its parse() method - and voilà.

However, since what I want generally to avoid is exactly to code again and again common behaviour, the perhaps most interesting part consists in the definition of some built-in handlers which minimize as much as possible the code required to process command-line options in common ways. Some of them are so plug-and-play that you don't even see them :), expecially since a a front-end to such handlers (read: boring work) is built-in in the library main class.

Alas, the libary is not POSIX compliant. In particular the 'unparametrized options grouping' feature is missing. I'm afraid that the fact that I personally find that feature unnecessarily confusing to the average user has a lot do with it, so that's it for the moment. If you're particulary prissy about the 100% Java™-iness of your tool, then this library is not indicated (but then you shouldn't be using command line arguments at all, so there you are). And if you really want, you may reimplement the "parse()" method to deal with all the POSIX details.

Options

First of all, what the library considers command line options: in short, every cmdline argument starting with a conventional prefix, which by default is the usual '-' (dash). An option may have parameters, which are arguments immediatly after the option, which are not prefixed. For example, -v is an option, and -name foo is an option with one parameter, whose value is foo. So far, so good.

An option can be negated (or 'unset'): that is, immediatly followed by a single '-' (dash) character. For example, -v- negates the -v option. What it exactly means in the context of your program, it's entirely your business - the system will just tell you that the option has been negated by the user.

The canonical form of an option is the option, without prefix and without negation dash, if there's any. In other words, the canonical form for -v- is v. Yeah, talk about complicating easy things. :)

Handlers

A Handler is an instance of a class extending CmdLineOptions.Handler, which defines the abstract method option() method and reacts to exactly one option. The handler requires as construction parameter the canonical form of the option. So a handler VerboseHandler for the option -v is built by new VerboseHandler("v").

The common way to create a handler is to use an anonymous inner class, as in

 Handler myHandler = new CmdLineOptions.Handler("v") {
    public void option(String option, CmdLineOptions.ParamSet ps, boolean value) {
        System.out.println("verbose mode set by the user: "+value);
    }
 }

However, if necessary, there's nothing wrong for a Handler to be declared as a full-blown class.

A handler is registered with the CmdLineOptions object by using the registerHandler() method, so the code above usually looks like

 CmdLineOptions c = new CmdLineOptions();
 c.registerHandler(new CmdLineOptions.Handler("v") {
        public void option(String option, CmdLineOptions.ParamSet ps, boolean value) {
            System.out.println("verbose mode set by the user: "+value);
        }
    });

Once registered, an option can be made mandatory by using setMandatory(). If only one of a set of options happens to be mandatory, the client code can use setAlternativeMandatory(). In both cases, an exception will be raised if the user doesn't specify the mandatory option, or one in a alternative-mandatory set.

Option priorities

An handler has also a priority: an integer value which can be set at construction or by invoking setPriority(int). The priority determines the order with which the options are parsed, where options with higher priority are parsed before options with lower priority. Also, priority may affect the automatic usage description, by grouping together descriptions of options with the same priority.

The default priority for an Handler is 0.

Aliases and descriptions

Most of the times you may want a 'long' name for an option (say, "-create") which is meaningful and descriptive to the user, but allow the user, after he's grown experienced with your tool, to use a shorter or different name (say, "-c").

An alias consists exactly in an alternative textual denotation for an option, which can be used in place of the original option name. The method addAliases() allows you to define as many aliases you want for an option - by expressing them in a String, in comma-separated format. For example, addAliases("create", "c, cr") defines c and cr as aliases for create.

Descriptions are what the word says, brief human-readable descriptions for an option which guide the user on its meaning. A description can be set by (guess what) the setDescription() method. It's done in a separate step since I'm not usually interested in writing descriptions until the tool I'm writing is somewhat mature, so I can just add 'em later. If the description hasn't been set, it defaults to "no description".

Automatic usage description

The CmdLineOptions class is also able to produce an automatic "usage" string, by gathering description and alias information from all the registered handlers. This is usually another boring task which requires attention and maintenance (I typically add some cmdline options to subtly enhance the flexibility of my tool and regularly forget to update the usage() printout), that is made easier since every non-documented options will still appear - just with a "no description" line.

If sortUsageOnPriority is enabled (as it is by default) then options are grouped by priority and ordered alphabetically therein. Otherwise, they are ordered alphabetically irrespective of the priority.

Binding options to member variables

All in all, that's what I want to do most of the times: the user specifies some options, and that, togheter with default values, sets up an initial state for my tool. Then the tool starts doing its job based on its initial state. In other words, I want the shortest path from textual option value written by the user to a valued member variable in my object, with type and value checked automatically.

This consideration leads to the availability, in the CmdLineOptions class, of the methods setObjectOnOption() and setOnOption() (with various overloads: note that one overload allows you to define the aliases within the same call).

These methods allows the client code to declare programmatically that a certain member variable of a certain object is bound to an option. The ..ObjectOnOption flavor works with Objects - (for example, arrays) of String or primitive type, or any type which can be constructed by a single String, like java.io.File for example. The ..OnOption flavor works with String or primitive type variables.

For example, if I have a verbose member, of boolean type in my FancyTool class, I probably want to set it to a default (say, false, then assign it with true or false if the user specifies -v or -v-. The following code does the trick:

 ...
 // Member of 'this'
 private boolean verbose = false; // Sets the overall default
 ...
 // Inside an intialization method of 'this'
 CmdLineOptions c = new CmdLineOptions();
 c.setOnOption("v", this, "verbose")
 ...

This associates, by name, the "verbose" member variable of the target object (this) to the option whose canonical name is "v". (actually creating a specific handler which can do the job and registering it for the option).

For boolean types, the very presence or not of the option (and if it's present, the optional negation state) are enough to determine a proper value for the associated member. Other types (String or primitive) require an explicit parameter to be set; missing that, a default value. So:

 ...
 // Member of 'this'
 private String nameMember = null; // Sets the overall default
 ...
 // Inside an intialization method of 'this'
 CmdLineOptions c = new CmdLineOptions();
 c.setOnOption("name", this, "nameMember");
 ...

can be used to set "nameMember" in this whenever the user specifies the option "-name", but expects the user to provide a parameter after -name (raising an exception otherwise).

(Note also that it's not necessary that the member variables to set up are in this - they can members of any object. The examples here use this only for simplicity.)

A default value can be provided, by specifying it right after the member variable name:

c.setOnOption("name", this, "nameMember", "cris");

In this case, the user may or may not specify an explicit parameter after -name. If he doesn't, the default is used.

Note also that such default value regards only the state of the variable when the user specifies the corresponding option on the command line. If the user does not specify the option at all, the variabile will have the "normal" value given by its initialization in the program code (i.e. null if the variabile is just declared as a member without being assigned at the same time).

Concretely, the variable is first initialized by the normal java-level initialization mechanism, then - if the user specifies the option without arguments, and a default value has been set with set..OnOption() - such value is used to re-initialize it, overwriting the java-initialized content. In the example above, the overall default is explicitly set to null to illustrate the point.

That default value can be also made the only possible value for the parameter (thus disallowing the user from specifying his own value), so that the net effect is to assign a specific value to a variable whenever the user specifies the related option. This comes handy, for example, when options are actually used to specify one of possible values for the same member, as in:

...
private String action = "showhelp"; // What to do
private String filename = null; // a file to open, if
...
c.setOnOption("h", this, "action", "showhelp", true);
c.setOnOption("open", this, "action", "openFile", true);
c.setOnOption("f", this, "filename");
c.setAlternativeMandatory(new String[] { "h", "open" });

where the same member ("action") is set by two different options with two differnt values, and arguments to the action are passed into another member ("filename") by means of specifying the option "f". "h" and "open" are mutually exclusive and mandatory.

Binding and priorities

Priorities are available also to options bound to member variables: the method setPriority(option, priority) allows to assign a priority to a bound option.

"Command" options

For "command" options - which tell the program what to do - this is actually almost always the case: what we want to do is to assign the value of a member with an internal conventional value which defines in the "what to do" part of the initial state.

-h and -open in the example above are in two such "command" options. The method setValuesOnOptions() is a shortcut that allows you to specify all the options and their relative "fixed" values in one shot. For example, setValuesOnOptions("create, open", "createSomething, openSomething", obj , jobToDo) will assign the member jobToDo of obj with the value createSomething if -create is specified is specified by the user, or with openSomething if -open.

Also, in the example above, the option "f" should become logically mandatory for the user when he specifies "-open" is specified (but not if he types "-h").

This can be achieved by using the setMandatoryOnOption() and setMandatoryOnOption() methods. Adding the line

...
c.setMandatoryOnOption("open","f")

does the job for the pseudocode above, by making '-f' mandatory only if '-open' is specified.

"Help" options

Help options are cmdline options with which the user signals to the tool he's using that he wants help on the tool itself. They usually look like -help or -h etc. Version 1.5.1 of the library supports one such option (which, however, may have many aliases) by the setHelpOption() method, that can be used to declare one single option to be an help option.

Enabling an help option impacts the behaviour of parse(), which will not complain of "mandatory options missing" if the help option is the only one specified by the user - but will silently ignore the fact.

It is then programmer's responsability to react properly to that case - by not attempting to run the tool when an help option is set. A typical example will set a boolean member and check its value as first thing after the parsing:

 public class MyTool {

   private boolean helpRequested=false;
   private CmdLineOptions co;
   ...

   public MyTool() {
    co=new CmdLineOptions();
    co.setOnOption("help", this, "helpRequested");
    co.setHelpOption("help");
    ....
   }

   public void run() {
    if (helpRequested) System.out.println(co.usage());
    else  {
      ...normal processing...
    }
   }

   public static void main(String args[]) throws Exception {
     MyTool tool = new MyTool();
     tool.co.parse(args);
     tool.run();
   }
 }

If help and "normal" options are mixed, the parsing will fail by default. However, the setFailOnMixedHelpOptionEncountered() method can be used to modify such default.

Shorter assignements

When a single option is mentioned in a set... operation (which has the option as first parameter), the CmdLineOptions object keeps track of it. This allows more compact coding of description, aliases, mandatory state, etc. For example, after

  co.setOnOption("param", this);
instead of
  co.setDescription("param", "A parameter");
  co.addAliases("param","p");
  co.setMandatory("param");
we can write (immediatly after the setOnOption instruction above)
  co.setDescription("A paramater");
  co.addAliases("p");
  co.setMandatory();
Be careful that using these methods the assignments of description, aliases, etc becomes dependent on the order of the instructions. The resulting code is less readable.

Actions on parsing

For options which are bound to variables, it is possible to set actions that occur after the binding has taken place (i.e. after the value of the variable is set with the value(s) given by the user in the command line (note that this would not make sense for options handled by user-defined handlers, where simply overriding
option() allows to program a specific reaction to an option's parsing).

The method setActionOnParse() allows to pass a Runnable object which will be executed after the binding.

Persistent configurable defaults

Most tools will hard-code default values for certain options directly in the declaration of the bound member variable: if the user does not specify a value for the option (and the option is not mandatory) the variable will not be touched by parse() - with the net effect that its initialization values will be unchanged. However, for some tools it's useful to enable the user to configure such defaults, since their values - which change rarely - are dependent on the installation and hard-coding them may not make sense. Typical options for which that is useful are the one used to declare host names, file paths, etc.

CmdLineOptions provides a mechanism for which any InputStream can be used as a source of default values; and specifically makes it simple to use Properties and property files to configure such defaults, using property names to match the command line option names/aliases:

In general, one the useXXX.. methods is invoked after constructing the CmdLineOptions object but before invoking parse().

Note that defaults are overridden by command line options: they're simply processed after the values given at command line, and if a default for an option that has already been encountered is found, it is ignored.

Putting it all togheter

That's all for the moment. To see it all at work, first of all, look at the example code (in the /examples/src directory in the downloaded package) and at the javadoc documentation. Compile the example and run/modify it - and have fun.

Downloading

Click here to download the library. It's packaged as a jar file in the 'lib' subdirectory in the zip file you download.


Copyright © 2000,2001,2002,2003,2004 dr. Cristiano Sadun