Sunday, February 28, 2010

Command Line Options in Java

A while back I cobbled together a Java library to parse command line options to a Java program. The coding is probably a bit "inartistic", and there may well be better libraries out there, but I offer it up here in case anyone has a use for it. The zip archive contains the OptionManager class, a related exception class, and a small test program. (see below) I'm releasing it under the Apache License (version 2.0), which should be liberal enough for pretty much any use.

OptionManager supports four types of options: toggles (for instance, -q to turn on "quiet mode"); key/value pairs separated by spaces (such as "-f myfile" to load myfile); key=value pairs (e.g., "user=paul" -- the separating punctuation can be any specified character); and position arguments (such as using the third argument as the target directory).  Options can be Integer, Long, Double, Boolean or String. Keys can be case-sensitive or case-insensitive.

A segment from the test program illustrates its use:

package commandLine;
//...
  public static void main(String[] args) {
    // create an option manager
    String delimiter = "~";  // instead of key=value, we'll use key~value
    boolean caseSensitive = true;  // keys will be case-sensitive
    OptionManager opt = new OptionManager(delimiter, caseSensitive);  // create the option manager

    // create some options
    try {
      opt.declareKeyvalPairOption("opt_a", "-a", String.class, "an a");
        // string-valued; typical use: "-a some_string"; default value "an a"
      opt.declareKeyvalPairOption("opt_A", "-A", Integer.class, 17);
        // integer-valued; typical use "-A some_number"; default value 17
        // using both -a and -A would not work with case-sensitivity turned off
      opt.declareKeyvalStringOption("name", "name", String.class, null);
        // string-valued; typical use "name~my_name"; default is a null string
      opt.declarePositionalOption("posOpt0", 0, Double.class, 37);
        // double-valued; assigns the first argument not attached to a key; default 37.0
      opt.declarePositionalOption("posOpt1", 1, Long.class, Long.MAX_VALUE);
        // long-valued; assigns the second argument not attached to a key; default a very big integer
      opt.declareToggleOption("toggle", "-xon", "-xoff", Boolean.class, true, false, null);
        // boolean-valued; -xon toggles the option to true, -xoff toggles it to false
    } catch (OptionManagerException ex) {
       // deal with construction problems here
    }
   
    opt.parse(args);  // parse the command line
    try {
      // fetch the option values and display the results
      System.out.println("opt_a = <" + opt.fetchString("opt_a") + ">");
      System.out.println("opt_A = <" + opt.fetchInt("opt_A") + ">");
      System.out.println("name = <" + opt.fetchString("name") + ">");
      System.out.println("posOpt0 = <" + opt.fetchDouble("posOpt0") + ">");
      System.out.println("posOpt1 = <" + opt.fetchLong("posOpt1") + ">");
      System.out.println("toggle is " + opt.fetchBool("toggle"));
      String[] excess = opt.excessArguments();
      // if the command line contained arguments in addition to those parsed
      // (perhaps attempts to use non-existent options, or misspelled keys)
      // the excessArguments method will return them as strings
      if (excess.length > 0) {
        // deal with the excess arguments
      }
    } catch (OptionManagerException ex) {
      // deal with problems parsing arguments here
    }
  }

Update: I've added some new capabilities (and spruced up the included test program a bit).

Update #2: The utility, which also includes methods to parse file specifications with wildcards and find matching files, is now available from Sourceforge under the name JCLILIB, still under the Apache 2.0 license.

No comments:

Post a Comment

Due to intermittent spamming, comments are being moderated. If this is your first time commenting on the blog, please read the Ground Rules for Comments. In particular, if you want to ask an operations research-related question not relevant to this post, consider asking it on Operations Research Stack Exchange.