Package fmpp.util

Class ArgsParser

  • All Implemented Interfaces:
    java.io.Serializable

    public class ArgsParser
    extends java.lang.Object
    implements java.io.Serializable
    Simple command-line argument parser that mimics the logic of UN*X tools as ls. It does not support the logic of tools like gcc.

    Features: short (1 character) and long option names, options with no argument, with optional argument and with mandatory argument, option groups (a.k.a. mutually exclusive options), implied options, alias options, retrieval of non-options, automatically generates formatted options help.

    For example, here it is a typical "UN*X command-line":

    $ ls -laT4 --color=auto --quote-name etc etc/mysql

    Here, we have 3 options given with short-name: "l", "a" and "T", and 2 options given with long-name: "color" and "quote-name". Two options have argument: "T" and "color". Also, we have 2 non-option arguments: "etc" and "etc/mysql". According to Java logic, the main method doesn't get the program name (here: "ls"), so we don't deal with that.

    A short example, that defines a subset of ls options:

     // 1. Create parser instance:
     ArgsParser ap = new ArgsParser();
     
     // 2. Define the options:
     ap.addOption("a", "all")
             .desc("do not hide entries starting with .");
     ap.addOption("A", "almost-all")
             .desc("do not list implied . and ..");
     ap.addOption("l", null)
             .desc("use a long list format");
     ap.addOption("T", "tabsize=COLS")
             .desc("assume tab stops at each COLS instead of 8");
     ap.addOption(null, "color=WHEN")
             .defaultArg("always")
             .desc("control whether color is used ...[too long].");
     ap.addOption("Q", "quote-name")
             .desc("enclose entry names in double-quotes");
     
     // 3. Parse args[]:
     try {
         ap.parse(args);
     } catch (ArgsParser.BadArgsException exc) {
         System.out.println(exc.getMessage());
         System.exit(-1);
     }
     
     // 4. Get the results:
     Properties ops = ap.getOptions();
     String[] nonOps = ap.getNonOptions();
    
     // 5. Print the results for the sake of testing:
     System.out.println("Options:");
     Iterator it = ops.entrySet().iterator();
     while (it.hasNext()) {
         Map.Entry e = (Map.Entry) it.next();
         System.out.println(
                 "- " + e.getKey() + " = " + e.getValue());
     }
     System.out.println("Non-options:");
     for (int i = 0; i < nonOps.length; i++) {
         System.out.println("- " + nonOps[i]);
     }
     

    This defines the following options:

    short-namelong-nameargument?
    aallno
    Aalmost-allno
    l no
    Ttabsizemandatory
     coloroptional, defaults to "always"
    Qquote-nameno

    and will parse command-line arguments like:
    -laT4 --color=auto --quote-name etc etc/mysql

    The resulting properties will be:

    namevalue
    all""
    l""
    tabsize"4"
    color"auto"
    quote-name""

    Note that the property name is always the long-name of the option if the option has a long-name, otherwise the short-name. Also note that the value of options that do not allow argument is 0 length String when the option is present, otherwise no property is made for the option (there is no "almost-all" propery).

    For options that has argument it is maybe practical to use implied values as:

     ...
     ap.addOption("T", "tabsize=COLS")
             .implied("8")
             .desc("assume tab stops at each COLS instead of 8");
     ap.addOption(null, "color=WHEN")
             .implied("none")
             .defaultArg("always")
             .desc("control whether color is used ...[too long].");
     ...
     

    If you parse this with the above modification:
    -la --quote-name etc etc/mysql
    then the "tabsize" property will be "8", and the "color" property will be "none". If you parse this:
    -laT4 --color --quote-name etc etc/mysql
    then the "tabsize" property will be "4", and the "color" property will be "always" (note that it is the default argument of "color", as there was no argument given for that in the command-line).

    You may want to use the same propery name but different value for options as "a" and "A". They should be mutually exclusive options anyway:

     ...
     ap.addOption("a", "all")
             .property("show", "all")
             .desc("do not hide entries starting with .");
     ap.addOption("A", "almost-all")
             .property("show", "almost-all")
             .desc("do not list implied . and ..");
     ...
     

    Here you say that both option sets the value of the "show" property (instead of setting "all" and "almost-all" properties) to the given values ("all" and "almost-all") if the option is present. As usually you want the option long-name (or short-name if there is no long-name) as the value of the property, there is a conveniece method for this:

     ...
     ap.addOption("a", "all")
             .group("show")
             .desc("do not hide entries starting with .");
     ap.addOption("A", "almost-all")
             .group("show")
             .desc("do not list implied . and ..");
     ...
     

    The parse method will throw exception if two options in args[] tries to set the same property, so the two options will mutually exclude each other here.

    For grouped options you may want to choose an implied option. Say, assume you have "format-normal", and a "format-terse" and a "format-verbose" options that are mutually exclusively set the value of "format" property. If the user do not use any of the "format-..." options, then you want see it as if it were a "--format-nomal" in the command-line:

     ...
     ap.addOption(null, "format-normal")
             .property("format", "normal")
             .implied();
     ap.addOption(null, "format-terse")
             .property("format", "terse");
     ap.addOption(null, "format-verbose")
             .property("format", "verbose");
     ...
     

    You can print the options help to the screen:

     System.out.println(ap.getOptionsHelp(80));
     

    For more information please read the documentation of methods.

    See Also:
    Serialized Form
    • Constructor Detail

      • ArgsParser

        public ArgsParser()
        Creates a parser.
    • Method Detail

      • parse

        public java.util.Properties parse​(java.lang.String[] args)
                                   throws ArgsParser.BadArgsException
        Parses the args[]. After this, you can get the options and non-options with getOptions and getNonOptions.
        Parameters:
        args - the array of Strings that you get as the parameter of main method.
        Returns:
        the properties object that stores the options. This is the same object as getOptions() returns.
        Throws:
        ArgsParser.BadArgsException - if the user has entered bad command-line arguments. The message in the exception (call exception.getMessage()) contains the (relatively) user-frinedly desription of the problem.
      • getOptions

        public java.util.Properties getOptions()
        Returns the options resulting from the latest parse call as Properties object. An empty Properties object will be returned if there was no parse call yet.
      • getOption

        public java.lang.String getOption​(java.lang.String name)
        Convenience funtcion to read the option Properties object.
      • getNonOptions

        public java.lang.String[] getNonOptions()
        Retruns the non-options resulting from the latest parse call. An empty array will be returned if there was no parse call yet.

        Non-options are the elements of args[] that are not not options (as "-l" or "--quote-name"), nor option arguments (as the "4" after "--tabsize 4", assuming that "tabsize" has mandatory argument). For example, in "-l etc --tabsize 8 etc/mysql" there are 2 non-options: "etc" and "etc/mysql".

      • getPropertyNames

        public java.util.Set getPropertyNames()
        Returns the property names used in the options.
      • addOption

        public ArgsParser.OptionDefinition addOption​(java.lang.String shortName,
                                                     java.lang.String longName)
        Defines an option for the parser.

        Note that if you create an option that supports argument, then the argument will be initially mandatory. To have optional argument, you have to give a default argument value by calling the defaultArg method of the returned object.

        Parameters:
        shortName - the short-name of option or null. Examples of short-names are "a" and "l" in "$ ls -la" If the option has argument, then this parameter has to be in the form "s ARGNAME" or "s=ARGNAME"; for example: "T COLS". The space or = indicates that the option supports argument. The ARGNAME is used only for showing the help, otherwise its value is unimportant. Note that if you will indicate in the longName parameter that the option has argument, you don't have to indicate it here.
        longName - the long-name of option or null. An example of long-name is "quote-name" in "$ ls --quote-name" If the option supports argument, then this parameter has to be in the form "long-name=ARGNAME" or "long-name ARGNAME"; for example: "tabsize=COLS". The = or space indicates that the option supports argument. The ARGNAME is used only for showing the help, otherwise its value is unimportant. Note that if you have already indicated in the shortName parameter that the option has argument, you don't have to indicate it agian here.
        Returns:
        the newly created OptionDefinition; this is returned to let you addjust the new option with methods like desc, property, implied or defaultArg.
        Throws:
        java.lang.IllegalArgumentException - If an option with the same long-name or short-name is already added, or if the given long- or short-name is malformed.
      • setDefaultProperties

        public void setDefaultProperties​(java.util.Properties defaultProperties)
        Sets the properies object that will be the default properties object for the properies object that parse creates for the options (See Properties(Properties defaults)). Also, parse will put the implied option values into the default properties object. By default there is no default properties object.

        This setting takes effect only when you call parse next time.

      • setMessages

        public void setMessages​(java.util.Properties messages)
        Customizes the error messages shown to the user. The Properties should contain the following keys, associated with the translation of the following sentences:
        • "OPTION_CONFLICT": "This option conflicts with a preceding option: "
        • "ARG_MISSING": "The argument is missing for this option: "
        • "OPTION_UNKNOWN": "Unknown option: "
        • "ARG_NOT_ALLOWED": "This option does not allow argument: "
        You may use the MSG_... constants for the key values.
      • getOptionDefintions

        public java.util.Iterator getOptionDefintions()
        Returns the list of ArgsParser.OptionDefinition-s, sorted as they should appear in an option help.
      • getOptionsHelp

        public java.lang.String getOptionsHelp​(int screenWidth)
        Generates options help for the defined options.
        Parameters:
        screenWidth - the (minimum) width of the console screen.