summaryrefslogtreecommitdiffstats
path: root/pki/base/silent/src/com/netscape/pkisilent/argparser
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/silent/src/com/netscape/pkisilent/argparser')
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParseException.java54
-rwxr-xr-xpki/base/silent/src/com/netscape/pkisilent/argparser/ArgParser.java3963
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParserTest.java3021
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/BooleanHolder.java54
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/CharHolder.java56
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/DoubleHolder.java55
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/FloatHolder.java56
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/IntHolder.java55
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/LongHolder.java55
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/ObjectHolder.java54
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/SimpleExample.java65
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/StringHolder.java55
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanException.java54
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanner.java1169
14 files changed, 4152 insertions, 4614 deletions
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParseException.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParseException.java
index c2b927cc..de3c58bd 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParseException.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParseException.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,37 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
import java.io.IOException;
-/**
- * Exception class used by <code>ArgParser</code> when
- * command line arguments contain an error.
- *
- * @author John E. Lloyd, Fall 2004
- * @see ArgParser
- */
-public class ArgParseException extends IOException
-{
- /**
+/**
+ * Exception class used by <code>ArgParser</code> when
+ * command line arguments contain an error.
+ *
+ * @author John E. Lloyd, Fall 2004
+ * @see ArgParser
+ */
+public class ArgParseException extends IOException {
+ /**
*
*/
private static final long serialVersionUID = -604960834535589460L;
/**
- * Creates a new ArgParseException with the given message.
- *
- * @param msg Exception message
- */
- public ArgParseException (String msg)
- { super (msg);
- }
+ * Creates a new ArgParseException with the given message.
+ *
+ * @param msg Exception message
+ */
+ public ArgParseException(String msg) {
+ super(msg);
+ }
- /**
- * Creates a new ArgParseException from the given
- * argument and message.
- *
- * @param arg Offending argument
- * @param msg Error message
- */
- public ArgParseException (String arg, String msg)
- { super (arg + ": " + msg);
- }
+ /**
+ * Creates a new ArgParseException from the given
+ * argument and message.
+ *
+ * @param arg Offending argument
+ * @param msg Error message
+ */
+ public ArgParseException(String arg, String msg) {
+ super(arg + ": " + msg);
+ }
}
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParser.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParser.java
index a205d101..f0712e38 100755
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParser.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParser.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,17 +19,17 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Copyright John E. Lloyd, 2004. All rights reserved. Permission to use,
- * copy, modify and redistribute is granted, provided that this copyright
- * notice is retained and the author is given credit whenever appropriate.
- *
- * This software is distributed "as is", without any warranty, including
- * any implied warranty of merchantability or fitness for a particular
- * use. The author assumes no responsibility for, and shall not be liable
- * for, any special, indirect, or consequential damages, or any damages
- * whatsoever, arising out of or in connection with the use of this
- * software.
- */
+ * Copyright John E. Lloyd, 2004. All rights reserved. Permission to use,
+ * copy, modify and redistribute is granted, provided that this copyright
+ * notice is retained and the author is given credit whenever appropriate.
+ *
+ * This software is distributed "as is", without any warranty, including
+ * any implied warranty of merchantability or fitness for a particular
+ * use. The author assumes no responsibility for, and shall not be liable
+ * for, any special, indirect, or consequential damages, or any damages
+ * whatsoever, arising out of or in connection with the use of this
+ * software.
+ */
import java.io.File;
import java.io.FileReader;
@@ -53,231 +54,173 @@ import java.util.Vector;
* <a href=#argsFromAFile>reading arguments from a file</a>. The
* last feature is particularly useful and makes it
* easy to create ad-hoc configuration files for an application.
- *
+ *
* <h3><a name="example">Basic Example</a></h3>
- *
- * <p>Here is a simple example in which an application has three
- * command line options:
- * <code>-theta</code> (followed by a floating point value),
- * <code>-file</code> (followed by a string value), and
- * <code>-debug</code>, which causes a boolean value to be set.
+ *
+ * <p>
+ * Here is a simple example in which an application has three command line options: <code>-theta</code> (followed by a floating point value), <code>-file</code> (followed by a string value), and <code>-debug</code>, which causes a boolean value to be set.
*
* <pre>
- *
- * static public void main (String[] args)
- * {
- * // create holder objects for storing results ...
*
- * DoubleHolder theta = new DoubleHolder();
- * StringHolder fileName = new StringHolder();
- * BooleanHolder debug = new BooleanHolder();
+ * static public void main(String[] args) {
+ * // create holder objects for storing results ...
*
- * // create the parser and specify the allowed options ...
+ * DoubleHolder theta = new DoubleHolder();
+ * StringHolder fileName = new StringHolder();
+ * BooleanHolder debug = new BooleanHolder();
*
- * ArgParser parser = new ArgParser("java argparser.SimpleExample");
- * parser.addOption ("-theta %f #theta value (in degrees)", theta);
- * parser.addOption ("-file %s #name of the operating file", fileName);
- * parser.addOption ("-debug %v #enables display of debugging info", debug);
- *
- * // match the arguments ...
+ * // create the parser and specify the allowed options ...
*
- * parser.matchAllArgs (args);
- *
- * // and print out the values
- *
- * System.out.println ("theta=" + theta.value);
- * System.out.println ("fileName=" + fileName.value);
- * System.out.println ("debug=" + debug.value);
- * }
+ * ArgParser parser = new ArgParser(&quot;java argparser.SimpleExample&quot;);
+ * parser.addOption(&quot;-theta %f #theta value (in degrees)&quot;, theta);
+ * parser.addOption(&quot;-file %s #name of the operating file&quot;, fileName);
+ * parser.addOption(&quot;-debug %v #enables display of debugging info&quot;, debug);
+ *
+ * // match the arguments ...
+ *
+ * parser.matchAllArgs(args);
+ *
+ * // and print out the values
+ *
+ * System.out.println(&quot;theta=&quot; + theta.value);
+ * System.out.println(&quot;fileName=&quot; + fileName.value);
+ * System.out.println(&quot;debug=&quot; + debug.value);
+ * }
* </pre>
- * <p>A command line specifying all three options might look like this:
+ * <p>
+ * A command line specifying all three options might look like this:
+ *
* <pre>
- * java argparser.SimpleExample -theta 7.8 -debug -file /ai/lloyd/bar
+ * java argparser.SimpleExample -theta 7.8 -debug -file /ai/lloyd/bar
* </pre>
*
- * <p>The application creates an instance of ArgParser and then adds
- * descriptions of the allowed options using {@link #addOption addOption}. The
- * method {@link #matchAllArgs(String[]) matchAllArgs} is then used to match
- * these options against the command line arguments. Values associated with
- * each option are returned in the <code>value</code> field of special
- * ``holder'' classes (e.g., {@link argparser.DoubleHolder DoubleHolder},
- * {@link argparser.StringHolder StringHolder}, etc.).
- *
- * <p> The first argument to {@link #addOption addOption} is a string that
- * specifies (1) the option's name, (2) a conversion code for its associated
- * value (e.g., <code>%f</code> for floating point, <code>%s</code> for a
- * string, <code>%v</code> for a boolean flag), and (3) an optional description
- * (following the <code>#</code> character) which is used for generating help
- * messages. The second argument is the holder object through which the value
- * is returned. This may be either a type-specific object (such as {@link
- * argparser.DoubleHolder DoubleHolder} or {@link argparser.StringHolder
- * StringHolder}), an array of the appropriate type, or
- * <a href=#multipleOptionInvocation> an instance of
- * <code>java.util.Vector</code></a>.
- *
- * <p>By default, arguments that don't match the specified options, are <a
- * href=#rangespec>out of range</a>, or are otherwise formatted incorrectly,
- * will cause <code>matchAllArgs</code> to print a message and exit the
- * program. Alternatively, an application can use {@link
- * #matchAllArgs(String[],int,int) matchAllArgs(args,idx,exitFlags)} to obtain
- * an array of unmatched arguments which can then be
- * <a href=#customArgParsing>processed separately</a>
- *
+ * <p>
+ * The application creates an instance of ArgParser and then adds descriptions of the allowed options using {@link #addOption addOption}. The method {@link #matchAllArgs(String[]) matchAllArgs} is then used to match these options against the command line arguments. Values associated with each option are returned in the <code>value</code> field of special ``holder'' classes (e.g., {@link argparser.DoubleHolder DoubleHolder}, {@link argparser.StringHolder StringHolder}, etc.).
+ *
+ * <p>
+ * The first argument to {@link #addOption addOption} is a string that specifies (1) the option's name, (2) a conversion code for its associated value (e.g., <code>%f</code> for floating point, <code>%s</code> for a string, <code>%v</code> for a boolean flag), and (3) an optional description (following the <code>#</code> character) which is used for generating help messages. The second argument is the holder object through which the value is returned. This may be either a type-specific object
+ * (such as {@link argparser.DoubleHolder DoubleHolder} or {@link argparser.StringHolder
+ * StringHolder}), an array of the appropriate type, or <a href=#multipleOptionInvocation> an instance of <code>java.util.Vector</code></a>.
+ *
+ * <p>
+ * By default, arguments that don't match the specified options, are <a href=#rangespec>out of range</a>, or are otherwise formatted incorrectly, will cause <code>matchAllArgs</code> to print a message and exit the program. Alternatively, an application can use {@link #matchAllArgs(String[],int,int) matchAllArgs(args,idx,exitFlags)} to obtain an array of unmatched arguments which can then be <a href=#customArgParsing>processed separately</a>
+ *
* <h3><a name="rangespec">Range Specification</a></h3>
- *
- * The values associated with options can also be given range specifications. A
- * range specification appears in curly braces immediately following the
- * conversion code. In the code fragment below, we show how to specify an
- * option <code>-name</code> that expects to be provided with one of three
- * string values (<code>john</code>, <code>mary</code>, or <code>jane</code>),
- * an option <code>-index</code> that expects to be supplied with a integer
- * value in the range 1 to 256, an option <code>-size</code> that expects to be
- * supplied with integer values of either 1, 2, 4, 8, or 16, and an option
- * <code>-foo</code> that expects to be supplied with floating point values in
- * the ranges -99 < foo <= -50, or 50 <= foo < 99.
- *
+ *
+ * The values associated with options can also be given range specifications. A range specification appears in curly braces immediately following the conversion code. In the code fragment below, we show how to specify an option <code>-name</code> that expects to be provided with one of three string values (<code>john</code>, <code>mary</code>, or <code>jane</code>), an option <code>-index</code> that expects to be supplied with a integer value in the range 1 to 256, an option <code>-size</code>
+ * that expects to be supplied with integer values of either 1, 2, 4, 8, or 16, and an option <code>-foo</code> that expects to be supplied with floating point values in the ranges -99 < foo <= -50, or 50 <= foo < 99.
+ *
* <pre>
- * StringHolder name = new StringHolder();
- * IntHolder index = new IntHolder();
- * IntHolder size = new IntHolder();
- * DoubleHolder foo = new DoubleHolder();
- *
- * parser.addOption ("-name %s {john,mary,jane}", name);
- * parser.addOption ("-index %d {[1,256]}", index);
- * parser.addOption ("-size %d {1,2,4,8,16}", size);
- * parser.addOption ("-foo %f {(-99,-50],[50,99)}", foo);
+ * StringHolder name = new StringHolder();
+ * IntHolder index = new IntHolder();
+ * IntHolder size = new IntHolder();
+ * DoubleHolder foo = new DoubleHolder();
+ *
+ * parser.addOption(&quot;-name %s {john,mary,jane}&quot;, name);
+ * parser.addOption(&quot;-index %d {[1,256]}&quot;, index);
+ * parser.addOption(&quot;-size %d {1,2,4,8,16}&quot;, size);
+ * parser.addOption(&quot;-foo %f {(-99,-50],[50,99)}&quot;, foo);
* </pre>
- *
- * If an argument value does not lie within a specified range, an error is
- * generated.
- *
+ *
+ * If an argument value does not lie within a specified range, an error is generated.
+ *
* <h3><a name="multipleOptionNames">Multiple Option Names</a></h3>
- *
- * An option may be given several names, or aliases, in the form of
- * a comma seperated list:
- *
+ *
+ * An option may be given several names, or aliases, in the form of a comma seperated list:
+ *
* <pre>
- * parser.addOption ("-v,--verbose %v #print lots of info");
- * parser.addOption ("-of,-outfile,-outputFile %s #output file");
+ * parser.addOption(&quot;-v,--verbose %v #print lots of info&quot;);
+ * parser.addOption(&quot;-of,-outfile,-outputFile %s #output file&quot;);
* </pre>
- *
+ *
* <h3><a name="singleWordOptions">Single Word Options</a></h3>
- *
- * Normally, options are assumed to be "multi-word", meaning
- * that any associated value must follow the option as a
- * separate argument string. For
- * example,
+ *
+ * Normally, options are assumed to be "multi-word", meaning that any associated value must follow the option as a separate argument string. For example,
+ *
* <pre>
- * parser.addOption ("-file %s #file name");
+ * parser.addOption(&quot;-file %s #file name&quot;);
* </pre>
- * will cause the parser to look for two strings in the argument list
- * of the form
+ *
+ * will cause the parser to look for two strings in the argument list of the form
+ *
* <pre>
* -file someFileName
* </pre>
- * However, if there is no white space separting the option's name from
- * it's conversion code, then values associated with that
- * option will be assumed to be part of the same argument
- * string as the option itself. For example,
+ *
+ * However, if there is no white space separting the option's name from it's conversion code, then values associated with that option will be assumed to be part of the same argument string as the option itself. For example,
+ *
* <pre>
- * parser.addOption ("-file=%s #file name");
+ * parser.addOption(&quot;-file=%s #file name&quot;);
* </pre>
- * will cause the parser to look for a single string in the argument
- * list of the form
+ *
+ * will cause the parser to look for a single string in the argument list of the form
+ *
* <pre>
* -file=someFileName
* </pre>
+ *
* Such an option is called a "single word" option.
- *
+ *
* <p>
- * In cases where an option has multiple names, then this single
- * word behavior is invoked if there is no white space between
- * the last indicated name and the conversion code. However, previous
- * names in the list will still be given multi-word behavior
- * if there is white space between the name and the
- * following comma. For example,
+ * In cases where an option has multiple names, then this single word behavior is invoked if there is no white space between the last indicated name and the conversion code. However, previous names in the list will still be given multi-word behavior if there is white space between the name and the following comma. For example,
+ *
* <pre>
- * parser.addOption ("-nb=,-number ,-n%d #number of blocks");
+ * parser.addOption(&quot;-nb=,-number ,-n%d #number of blocks&quot;);
* </pre>
- * will cause the parser to look for one, two, and one word constructions
- * of the forms
+ *
+ * will cause the parser to look for one, two, and one word constructions of the forms
+ *
* <pre>
* -nb=N
* -number N
* -nN
* </pre>
- *
+ *
* <h3><a name="multipleOptionValues">Multiple Option Values</a></h3>
- *
- * If may be useful for an option to be followed by several values.
- * For instance, we might have an option <code>-velocity</code>
- * which should be followed by three numbers denoting
- * the x, y, and z components of a velocity vector.
- * We can require multiple values for an option
- * by placing a <i>multiplier</i> specification,
- * of the form <code>X</code>N, where N is an integer,
- * after the conversion code (or range specification, if present).
- * For example,
+ *
+ * If may be useful for an option to be followed by several values. For instance, we might have an option <code>-velocity</code> which should be followed by three numbers denoting the x, y, and z components of a velocity vector. We can require multiple values for an option by placing a <i>multiplier</i> specification, of the form <code>X</code>N, where N is an integer, after the conversion code (or range specification, if present). For example,
*
* <pre>
- * double[] pos = new double[3];
- *
- * addOption ("-position %fX3 #position of the object", pos);
+ * double[] pos = new double[3];
+ *
+ * addOption(&quot;-position %fX3 #position of the object&quot;, pos);
* </pre>
+ *
* will cause the parser to look for
+ *
* <pre>
* -position xx yy zz
* </pre>
*
- * in the argument list, where <code>xx</code>, <code>yy</code>, and
- * <code>zz</code> are numbers. The values are stored in the array
- * <code>pos</code>.
- *
- * Options requiring multiple values must use arrays to
- * return their values, and cannot be used in single word format.
- *
+ * in the argument list, where <code>xx</code>, <code>yy</code>, and <code>zz</code> are numbers. The values are stored in the array <code>pos</code>.
+ *
+ * Options requiring multiple values must use arrays to return their values, and cannot be used in single word format.
+ *
* <h3><a name="multipleOptionInvocation">Multiple Option Invocation</a></h3>
- *
- * Normally, if an option appears twice in the command list, the
- * value associated with the second instance simply overwrites the
- * value associated with the first instance.
- *
- * However, the application can instead arrange for the storage of <i>all</i>
- * values associated with multiple option invocation, by supplying a instance
- * of <code>java.util.Vector</code> to serve as the value holder. Then every
- * time the option appears in the argument list, the parser will create a value
- * holder of appropriate type, set it to the current value, and store the
- * holder in the vector. For example, the construction
- *
+ *
+ * Normally, if an option appears twice in the command list, the value associated with the second instance simply overwrites the value associated with the first instance.
+ *
+ * However, the application can instead arrange for the storage of <i>all</i> values associated with multiple option invocation, by supplying a instance of <code>java.util.Vector</code> to serve as the value holder. Then every time the option appears in the argument list, the parser will create a value holder of appropriate type, set it to the current value, and store the holder in the vector. For example, the construction
+ *
* <pre>
- * Vector vec = new Vector(10);
- *
- * parser.addOption ("-foo %f", vec);
- * parser.matchAllArgs(args);
+ * Vector vec = new Vector(10);
+ *
+ * parser.addOption(&quot;-foo %f&quot;, vec);
+ * parser.matchAllArgs(args);
* </pre>
+ *
* when supplied with an argument list that contains
+ *
* <pre>
* -foo 1.2 -foo 1000 -foo -78
* </pre>
*
- * will create three instances of {@link argparser.DoubleHolder DoubleHolder},
- * initialized to <code>1.2</code>, <code>1000</code>, and <code>-78</code>,
- * and store them in <code>vec</code>.
- *
+ * will create three instances of {@link argparser.DoubleHolder DoubleHolder}, initialized to <code>1.2</code>, <code>1000</code>, and <code>-78</code>, and store them in <code>vec</code>.
+ *
* <h3><a name="helpInfo">Generating help information</a></h3>
- *
- * ArgParser automatically generates help information for the options, and this
- * information may be printed in response to a <i>help</i> option, or may be
- * queried by the application using {@link #getHelpMessage getHelpMessage}.
- * The information for each option consists of the option's name(s), it's
- * required value(s), and an application-supplied description. Value
- * information is generated automaticlly from the conversion code, range, and
- * multiplier specifications (although this can be overriden, as
- * <a href=#valueInfo>described below</a>).
- * The application-supplied description is whatever
- * appears in the specification string after the optional <code>#</code>
- * character. The string returned by {@link #getHelpMessage getHelpMessage} for
- * the <a href=#example>first example above</a> would be
+ *
+ * ArgParser automatically generates help information for the options, and this information may be printed in response to a <i>help</i> option, or may be queried by the application using {@link #getHelpMessage getHelpMessage}. The information for each option consists of the option's name(s), it's required value(s), and an application-supplied description. Value information is generated automaticlly from the conversion code, range, and multiplier specifications (although this can be overriden, as
+ * <a href=#valueInfo>described below</a>). The application-supplied description is whatever appears in the specification string after the optional <code>#</code> character. The string returned by {@link #getHelpMessage getHelpMessage} for the <a href=#example>first example above</a> would be
*
* <pre>
* Usage: java argparser.SimpleExample
@@ -289,50 +232,37 @@ import java.util.Vector;
* -debug enables display of debugging info
* </pre>
*
- * The options <code>-help</code> and <code>-?</code> are including in the
- * parser by default as help options, and they automatically cause the help
- * message to be printed. To exclude these
- * options, one should use the constructor {@link #ArgParser(String,boolean)
- * ArgParser(synopsis,false)}.
- * Help options can also be specified by the application using {@link
- * #addOption addOption} and the conversion code <code>%h</code>. Help options
- * can be disabled using {@link #setHelpOptionsEnabled
+ * The options <code>-help</code> and <code>-?</code> are including in the parser by default as help options, and they automatically cause the help message to be printed. To exclude these options, one should use the constructor {@link #ArgParser(String,boolean)
+ * ArgParser(synopsis,false)}. Help options can also be specified by the application using {@link #addOption addOption} and the conversion code <code>%h</code>. Help options can be disabled using {@link #setHelpOptionsEnabled
* setHelpOptionsEnabled(false)}.
- *
- * <p><a name=valueInfo>
- * A description of the required values for an option can be
- * specified explicitly
- * by placing a second <code>#</code> character in the specification
- * string. Everything between the first and second <code>#</code>
- * characters then becomes the value description, and everything
- * after the second <code>#</code> character becomes the option
- * description.
- * For example, if the <code>-theta</code> option
- * above was specified with
+ *
+ * <p>
+ * <a name=valueInfo> A description of the required values for an option can be specified explicitly by placing a second <code>#</code> character in the specification string. Everything between the first and second <code>#</code> characters then becomes the value description, and everything after the second <code>#</code> character becomes the option description. For example, if the <code>-theta</code> option above was specified with
+ *
* <pre>
- * parser.addOption ("-theta %f #NUMBER#theta value (in degrees)",theta);
+ * parser.addOption(&quot;-theta %f #NUMBER#theta value (in degrees)&quot;, theta);
* </pre>
+ *
* instead of
+ *
* <pre>
- * parser.addOption ("-theta %f #theta value (in degrees)", theta);
+ * parser.addOption(&quot;-theta %f #theta value (in degrees)&quot;, theta);
* </pre>
- * then the corresponding entry in the help message would look
- * like
+ *
+ * then the corresponding entry in the help message would look like
+ *
* <pre>
* -theta NUMBER theta value (in degrees)
* </pre>
- *
+ *
* <h3><a name="customArgParsing">Custom Argument Parsing</a></h3>
*
- * An application may find it necessary to handle arguments that
- * don't fit into the framework of this class. There are a couple
- * of ways to do this.
- *
+ * An application may find it necessary to handle arguments that don't fit into the framework of this class. There are a couple of ways to do this.
+ *
* <p>
* First, the method {@link #matchAllArgs(String[],int,int)
- * matchAllArgs(args,idx,exitFlags)} returns an array of
- * all unmatched arguments, which can then be handled
- * specially:
+ * matchAllArgs(args,idx,exitFlags)} returns an array of all unmatched arguments, which can then be handled specially:
+ *
* <pre>
* String[] unmatched =
* parser.matchAllArgs (args, 0, parser.EXIT_ON_ERROR);
@@ -341,13 +271,10 @@ import java.util.Vector;
* }
* </pre>
*
- * For instance, this would be useful for an applicatoon that accepts an
- * arbitrary number of input file names. The options can be parsed using
- * <code>matchAllArgs</code>, and the remaining unmatched arguments
- * give the file names.
- *
- * <p> If we need more control over the parsing, we can parse arguments one at
- * a time using {@link #matchArg matchArg}:
+ * For instance, this would be useful for an applicatoon that accepts an arbitrary number of input file names. The options can be parsed using <code>matchAllArgs</code>, and the remaining unmatched arguments give the file names.
+ *
+ * <p>
+ * If we need more control over the parsing, we can parse arguments one at a time using {@link #matchArg matchArg}:
*
* <pre>
* int idx = 0;
@@ -365,1936 +292,1694 @@ import java.util.Vector;
* }
* }
* </pre>
- *
- * {@link #matchArg matchArg(args,idx)} matches one option at location
- * <code>idx</code> in the argument list, and then returns the location value
- * that should be used for the next match. If an argument does
- * not match any option,
- * {@link #getUnmatchedArgument getUnmatchedArgument} will return a copy of the
- * unmatched argument.
- *
+ *
+ * {@link #matchArg matchArg(args,idx)} matches one option at location <code>idx</code> in the argument list, and then returns the location value that should be used for the next match. If an argument does not match any option, {@link #getUnmatchedArgument getUnmatchedArgument} will return a copy of the unmatched argument.
+ *
* <h3><a name="argsFromAFile">Reading Arguments From a File</a></h3>
- *
- * The method {@link #prependArgs prependArgs} can be used to automatically
- * read in a set of arguments from a file and prepend them onto an existing
- * argument list. Argument words correspond to white-space-delimited strings,
- * and the file may contain the comment character <code>#</code> (which
- * comments out everything to the end of the current line). A typical usage
- * looks like this:
- *
+ *
+ * The method {@link #prependArgs prependArgs} can be used to automatically read in a set of arguments from a file and prepend them onto an existing argument list. Argument words correspond to white-space-delimited strings, and the file may contain the comment character <code>#</code> (which comments out everything to the end of the current line). A typical usage looks like this:
+ *
* <pre>
* ... create parser and add options ...
*
* args = parser.prependArgs (new File(".configFile"), args);
- *
+ *
* parser.matchAllArgs (args);
* </pre>
- *
- * This makes it easy to generate simple configuration files for an
- * application.
- *
+ *
+ * This makes it easy to generate simple configuration files for an application.
+ *
* @author John E. Lloyd, Fall 2004
*/
-public class ArgParser
-{
- Vector<Record> matchList;
-// int tabSpacing = 8;
- String synopsisString;
- boolean helpOptionsEnabled = true;
- Record defaultHelpOption = null;
- Record firstHelpOption = null;
- PrintStream printStream = System.out;
- int helpIndent = 24;
- String errMsg = null;
- String unmatchedArg = null;
-
- static String validConversionCodes = "iodxcbfsvh";
-
- /**
- * Indicates that the program should exit with an appropriate message
- * in the event of an erroneous or malformed argument.*/
- public static int EXIT_ON_ERROR = 1;
-
- /**
- * Indicates that the program should exit with an appropriate message
- * in the event of an unmatched argument.*/
- public static int EXIT_ON_UNMATCHED = 2;
-
- /**
- * Returns a string containing the valid conversion codes. These
- * are the characters which may follow the <code>%</code> character in
- * the specification string of {@link #addOption addOption}.
- *
- * @return Valid conversion codes
- * @see #addOption
- */
- public static String getValidConversionCodes()
- {
- return validConversionCodes;
- }
-
- static class NameDesc
- {
- String name;
- // oneWord implies that any value associated with
- // option is concatenated onto the argument string itself
- boolean oneWord;
- NameDesc next = null;
- }
-
- static class RangePnt
- {
- double dval = 0;
- long lval = 0;
- String sval = null;
- boolean bval = true;
- boolean closed = true;
-
- RangePnt (String s, boolean closed)
- { sval = s;
- this.closed = closed;
- }
-
- RangePnt (double d, boolean closed)
- { dval = d;
- this.closed = closed;
- }
-
- RangePnt (long l, boolean closed)
- { lval = l;
- this.closed = closed;
- }
-
- RangePnt (boolean b, boolean closed)
- { bval = b;
- this.closed = closed;
- }
-
- RangePnt (StringScanner scanner, int type)
- throws IllegalArgumentException
- {
- String typeName = null;
- try
- { switch (type)
- {
- case Record.CHAR:
- { typeName = "character";
- lval = scanner.scanChar();
- break;
- }
- case Record.INT:
- case Record.LONG:
- { typeName = "integer";
- lval = scanner.scanInt();
- break;
- }
- case Record.FLOAT:
- case Record.DOUBLE:
- { typeName = "float";
- dval = scanner.scanDouble();
- break;
- }
- case Record.STRING:
- { typeName = "string";
- sval = scanner.scanString();
- break;
- }
- case Record.BOOLEAN:
- { typeName = "boolean";
- bval = scanner.scanBoolean();
- break;
- }
- }
- }
- catch (StringScanException e)
- { throw new IllegalArgumentException (
- "Malformed " + typeName + " '" +
- scanner.substring(scanner.getIndex(),
- e.getFailIndex()+1) +
- "' in range spec");
- }
-// this.closed = closed;
- }
-
- void setClosed (boolean closed)
- { this.closed = closed;
- }
-
- boolean getClosed()
- { return closed;
- }
-
- int compareTo (double d)
- { if (dval < d)
- { return -1;
- }
- else if (d == dval)
- { return 0;
- }
- else
- { return 1;
- }
- }
-
- int compareTo (long l)
- { if (lval < l)
- { return -1;
- }
- else if (l == lval)
- { return 0;
- }
- else
- { return 1;
- }
- }
-
- int compareTo (String s)
- { return sval.compareTo (s);
- }
-
- int compareTo (boolean b)
- { if (b == bval)
- { return 0;
- }
- else
- { return 1;
- }
- }
-
- public String toString()
- { return "{ dval=" + dval + ", lval=" + lval +
- ", sval=" + sval + ", bval=" + bval +
- ", closed=" + closed + "}";
- }
- }
-
- class RangeAtom
- {
- RangePnt low = null;
- RangePnt high = null;
- RangeAtom next = null;
-
- RangeAtom (RangePnt p0, RangePnt p1, int type)
- throws IllegalArgumentException
- {
- int cmp = 0;
- switch (type)
- {
- case Record.CHAR:
- case Record.INT:
- case Record.LONG:
- { cmp = p0.compareTo (p1.lval);
- break;
- }
- case Record.FLOAT:
- case Record.DOUBLE:
- { cmp = p0.compareTo (p1.dval);
- break;
- }
- case Record.STRING:
- { cmp = p0.compareTo (p1.sval);
- break;
- }
- }
- if (cmp > 0)
- { // then switch high and low
- low = p1;
- high = p0;
- }
- else
- { low = p0;
- high = p1;
- }
- }
-
- RangeAtom (RangePnt p0)
- throws IllegalArgumentException
- {
- low = p0;
- }
-
- boolean match (double d)
- { int lc = low.compareTo(d);
- if (high != null)
- { int hc = high.compareTo(d);
- return (lc*hc < 0 ||
- (low.closed && lc==0) ||
- (high.closed && hc==0));
- }
- else
- { return lc == 0;
- }
- }
-
- boolean match (long l)
- { int lc = low.compareTo(l);
- if (high != null)
- { int hc = high.compareTo(l);
- return (lc*hc < 0 ||
- (low.closed && lc==0) ||
- (high.closed && hc==0));
- }
- else
- { return lc == 0;
- }
- }
-
- boolean match (String s)
- { int lc = low.compareTo(s);
- if (high != null)
- { int hc = high.compareTo(s);
- return (lc*hc < 0 ||
- (low.closed && lc==0) ||
- (high.closed && hc==0));
- }
- else
- { return lc == 0;
- }
- }
-
- boolean match (boolean b)
- { return low.compareTo(b) == 0;
- }
-
- public String toString()
- { return "low=" + (low==null ? "null" : low.toString()) +
- ", high=" + (high==null ? "null" : high.toString());
- }
- }
-
- class Record
- {
- NameDesc nameList;
- static final int NOTYPE = 0;
- static final int BOOLEAN = 1;
- static final int CHAR = 2;
- static final int INT = 3;
- static final int LONG = 4;
- static final int FLOAT = 5;
- static final int DOUBLE = 6;
- static final int STRING = 7;
- int type;
- int numValues;
- boolean vectorResult = false;
- boolean required = true;
-
- String helpMsg = null;
- String valueDesc = null;
- String rangeDesc = null;
- Object resHolder = null;
- RangeAtom rangeList = null;
- RangeAtom rangeTail = null;
- char convertCode;
- boolean vval = true; // default value for now
-
- NameDesc firstNameDesc()
- {
- return nameList;
- }
-
- RangeAtom firstRangeAtom()
- {
- return rangeList;
- }
-
- int numRangeAtoms()
- { int cnt = 0;
- for (RangeAtom ra=rangeList; ra!=null; ra=ra.next)
- { cnt++;
- }
- return cnt;
- }
-
- void addRangeAtom (RangeAtom ra)
- { if (rangeList == null)
- { rangeList = ra;
- }
- else
- { rangeTail.next = ra;
- }
- rangeTail = ra;
- }
-
- boolean withinRange (double d)
- {
- if (rangeList == null)
- { return true;
- }
- for (RangeAtom ra=rangeList; ra!=null; ra=ra.next)
- { if (ra.match (d))
- { return true;
- }
- }
- return false;
- }
-
- boolean withinRange (long l)
- {
- if (rangeList == null)
- { return true;
- }
- for (RangeAtom ra=rangeList; ra!=null; ra=ra.next)
- { if (ra.match (l))
- { return true;
- }
- }
- return false;
- }
-
- boolean withinRange (String s)
- {
- if (rangeList == null)
- { return true;
- }
- for (RangeAtom ra=rangeList; ra!=null; ra=ra.next)
- { if (ra.match (s))
- { return true;
- }
- }
- return false;
- }
-
- boolean withinRange (boolean b)
- {
- if (rangeList == null)
- { return true;
- }
- for (RangeAtom ra=rangeList; ra!=null; ra=ra.next)
- { if (ra.match (b))
- { return true;
- }
- }
- return false;
- }
-
- String valTypeName()
- {
- switch (convertCode)
- {
- case 'i':
- { return ("integer");
- }
- case 'o':
- { return ("octal integer");
- }
- case 'd':
- { return ("decimal integer");
- }
- case 'x':
- { return ("hex integer");
- }
- case 'c':
- { return ("char");
- }
- case 'b':
- { return ("boolean");
- }
- case 'f':
- { return ("float");
- }
- case 's':
- { return ("string");
- }
- }
- return ("unknown");
- }
-
- void scanValue (Object result, String name, String s, int resultIdx)
- throws ArgParseException
- {
- double dval = 0;
- String sval = null;
- long lval = 0;
- boolean bval = false;
-
- if (s.length()==0)
- { throw new ArgParseException
- (name, "requires a contiguous value");
- }
- StringScanner scanner = new StringScanner(s);
- try
- {
- switch (convertCode)
- {
- case 'i':
- { lval = scanner.scanInt();
- break;
- }
- case 'o':
- { lval = scanner.scanInt (8, false);
- break;
- }
- case 'd':
- { lval = scanner.scanInt (10, false);
- break;
- }
- case 'x':
- { lval = scanner.scanInt (16, false);
- break;
- }
- case 'c':
- { lval = scanner.scanChar();
- break;
- }
- case 'b':
- { bval = scanner.scanBoolean();
- break;
- }
- case 'f':
- { dval = scanner.scanDouble();
- break;
- }
- case 's':
- { sval = scanner.getString();
- break;
- }
- }
- }
- catch (StringScanException e)
- { throw new ArgParseException (
- name, "malformed " + valTypeName() + " '" + s + "'");
- }
- scanner.skipWhiteSpace();
- if (!scanner.atEnd())
- { throw new ArgParseException (
- name, "malformed " + valTypeName() + " '" + s + "'");
- }
- boolean outOfRange = false;
- switch (type)
- {
- case CHAR:
- case INT:
- case LONG:
- { outOfRange = !withinRange (lval);
- break;
- }
- case FLOAT:
- case DOUBLE:
- { outOfRange = !withinRange (dval);
- break;
- }
- case STRING:
- { outOfRange = !withinRange (sval);
- break;
- }
- case BOOLEAN:
- { outOfRange = !withinRange (bval);
- break;
- }
- }
- if (outOfRange)
- { String errmsg = "value " + s + " not in range ";
- throw new ArgParseException (
- name, "value '" + s + "' not in range " + rangeDesc);
- }
- if (result.getClass().isArray())
- {
- switch (type)
- {
- case BOOLEAN:
- { ((boolean[])result)[resultIdx] = bval;
- break;
- }
- case CHAR:
- { ((char[])result)[resultIdx] = (char)lval;
- break;
- }
- case INT:
- { ((int[])result)[resultIdx] = (int)lval;
- break;
- }
- case LONG:
- { ((long[])result)[resultIdx] = lval;
- break;
- }
- case FLOAT:
- { ((float[])result)[resultIdx] = (float)dval;
- break;
- }
- case DOUBLE:
- { ((double[])result)[resultIdx] = dval;
- break;
- }
- case STRING:
- { ((String[])result)[resultIdx] = sval;
- break;
- }
- }
- }
- else
- {
- switch (type)
- {
- case BOOLEAN:
- { ((BooleanHolder)result).value = bval;
- break;
- }
- case CHAR:
- { ((CharHolder)result).value = (char)lval;
- break;
- }
- case INT:
- { ((IntHolder)result).value = (int)lval;
- break;
- }
- case LONG:
- { ((LongHolder)result).value = lval;
- break;
- }
- case FLOAT:
- { ((FloatHolder)result).value = (float)dval;
- break;
- }
- case DOUBLE:
- { ((DoubleHolder)result).value = dval;
- break;
- }
- case STRING:
- { ((StringHolder)result).value = sval;
- break;
- }
- }
- }
- }
- }
-
- private String firstHelpOptionName()
- {
- if (firstHelpOption != null)
- { return firstHelpOption.nameList.name;
- }
- else
- { return null;
- }
- }
-
- /**
- * Creates an <code>ArgParser</code> with a synopsis
- * string, and the default help options <code>-help</code> and
- * <code>-&#063;</code>.
- *
- * @param synopsisString string that briefly describes program usage,
- * for use by {@link #getHelpMessage getHelpMessage}.
- * @see ArgParser#getSynopsisString
- * @see ArgParser#getHelpMessage
- */
- public ArgParser(String synopsisString)
- {
- this (synopsisString, true);
- }
-
- /**
- * Creates an <code>ArgParser</code> with a synopsis
- * string. The help options <code>-help</code> and
- * <code>-?</code> are added if <code>defaultHelp</code>
- * is true.
- *
- * @param synopsisString string that briefly describes program usage,
- * for use by {@link #getHelpMessage getHelpMessage}.
- * @param defaultHelp if true, adds the default help options
- * @see ArgParser#getSynopsisString
- * @see ArgParser#getHelpMessage
- */
- public ArgParser(String synopsisString, boolean defaultHelp)
- {
- matchList = new Vector<Record>(128);
- this.synopsisString = synopsisString;
- if (defaultHelp)
- { addOption ("-help,-? %h #displays help information", null);
- defaultHelpOption = firstHelpOption = matchList.get(0);
- }
- }
-
- /**
- * Returns the synopsis string used by the parser.
- * The synopsis string is a short description of how to invoke
- * the program, and usually looks something like
- * <p>
- * <prec>
- * "java somepackage.SomeClass [options] files ..."
- * </prec>
- *
- * <p> It is used in help and error messages.
- *
- * @return synopsis string
- * @see ArgParser#setSynopsisString
- * @see ArgParser#getHelpMessage
- */
- public String getSynopsisString ()
- {
- return synopsisString;
- }
-
- /**
- * Sets the synopsis string used by the parser.
- *
- * @param s new synopsis string
- * @see ArgParser#getSynopsisString
- * @see ArgParser#getHelpMessage
- */
- public void setSynopsisString (String s)
- {
- synopsisString = s;
- }
-
- /**
- * Indicates whether or not help options are enabled.
- *
- * @return true if help options are enabled
- * @see ArgParser#setHelpOptionsEnabled
- * @see ArgParser#addOption
- */
- public boolean getHelpOptionsEnabled ()
- {
- return helpOptionsEnabled;
- }
-
- /**
- * Enables or disables help options. Help options are those
- * associated with a conversion code of <code>%h</code>. If
- * help options are enabled, and a help option is matched,
- * then the string produced by
- * {@link #getHelpMessage getHelpMessage}
- * is printed to the default print stream and the program
- * exits with code 0. Otherwise, arguments which match help
- * options are ignored.
- *
- * @param enable enables help options if <code>true</code>.
- * @see ArgParser#getHelpOptionsEnabled
- * @see ArgParser#addOption
- * @see ArgParser#setDefaultPrintStream */
- public void setHelpOptionsEnabled(boolean enable)
- { helpOptionsEnabled = enable;
- }
-
- /**
- * Returns the default print stream used for outputting help
- * and error information.
- *
- * @return default print stream
- * @see ArgParser#setDefaultPrintStream
- */
- public PrintStream getDefaultPrintStream()
- { return printStream;
- }
-
- /**
- * Sets the default print stream used for outputting help
- * and error information.
- *
- * @param stream new default print stream
- * @see ArgParser#getDefaultPrintStream
- */
- public void setDefaultPrintStream (PrintStream stream)
- {
- printStream = stream;
- }
-
- /**
- * Gets the indentation used by {@link #getHelpMessage
- * getHelpMessage}.
- *
- * @return number of indentation columns
- * @see ArgParser#setHelpIndentation
- * @see ArgParser#getHelpMessage
- */
- public int getHelpIndentation()
- {
- return helpIndent;
- }
-
- /**
- * Sets the indentation used by {@link #getHelpMessage
- * getHelpMessage}. This is the number of columns that an option's help
- * information is indented. If the option's name and value information
- * can fit within this number of columns, then all information about
- * the option is placed on one line. Otherwise, the indented help
- * information is placed on a separate line.
- *
- * @param indent number of indentation columns
- * @see ArgParser#getHelpIndentation
- * @see ArgParser#getHelpMessage
- */
- public void setHelpIndentation (int indent)
- { helpIndent = indent;
- }
-
-// public void setTabSpacing (int n)
-// { tabSpacing = n;
-// }
-
-// public int getTabSpacing ()
-// { return tabSpacing;
-// }
-
- private void scanRangeSpec (Record rec, String s)
- throws IllegalArgumentException
- {
- StringScanner scanner = new StringScanner (s);
- int i0, i = 1;
- char c, c0, c1;
-
- scanner.setStringDelimiters (")],}");
- c = scanner.getc(); // swallow the first '{'
- scanner.skipWhiteSpace();
- while ((c=scanner.peekc()) != '}')
- { RangePnt p0, p1;
-
- if (c == '[' || c == '(')
- {
- if (rec.convertCode == 'v' || rec.convertCode == 'b')
- { throw new IllegalArgumentException
- ("Sub ranges not supported for %b or %v");
- }
- c0 = scanner.getc(); // record & swallow character
- scanner.skipWhiteSpace();
- p0 = new RangePnt (scanner, rec.type);
- scanner.skipWhiteSpace();
- if (scanner.getc() != ',')
- { throw new IllegalArgumentException
- ("Missing ',' in subrange specification");
- }
- p1 = new RangePnt (scanner, rec.type);
- scanner.skipWhiteSpace();
- if ((c1=scanner.getc()) != ']' && c1 != ')')
- { throw new IllegalArgumentException
- ("Unterminated subrange");
- }
- if (c0 == '(')
- { p0.setClosed (false);
- }
- if (c1 == ')')
- { p1.setClosed (false);
- }
- rec.addRangeAtom (new RangeAtom (p0, p1, rec.type));
- }
- else
- { scanner.skipWhiteSpace();
- p0 = new RangePnt (scanner, rec.type);
- rec.addRangeAtom (new RangeAtom (p0));
- }
- scanner.skipWhiteSpace();
- if ((c=scanner.peekc()) == ',')
- { scanner.getc();
- scanner.skipWhiteSpace();
- }
- else if (c != '}')
- {
- throw new IllegalArgumentException
- ("Range spec: ',' or '}' expected");
- }
- }
- if (rec.numRangeAtoms()==1)
- { rec.rangeDesc = s.substring (1, s.length()-1);
- }
- else
- { rec.rangeDesc = s;
- }
- }
-
- private int defaultResultType (char convertCode)
- {
- switch (convertCode)
- {
- case 'i':
- case 'o':
- case 'd':
- case 'x':
- { return Record.LONG;
- }
- case 'c':
- { return Record.CHAR;
- }
- case 'v':
- case 'b':
- { return Record.BOOLEAN;
- }
- case 'f':
- { return Record.DOUBLE;
- }
- case 's':
- { return Record.STRING;
- }
- }
- return Record.NOTYPE;
- }
-
- /**
- * Adds a new option description to the parser. The method takes two
- * arguments: a specification string, and a result holder in which to
- * store the associated value.
- *
- * <p>The specification string has the general form
- *
- * <p> <var>optionNames</var>
- * <code>%</code><var>conversionCode</var>
- * [<code>{</code><var>rangeSpec</var><code>}</code>]
- * [<code>X</code><var>multiplier</var>]
- * [<code>#</code><var>valueDescription</var>]
- * [<code>#</code><var>optionDescription</var>] </code>
- *
- * <p>
- * where
- * <ul> <p><li><var>optionNames</var> is a
- * comma-separated list of names for the option
- * (such as <code>-f, --file</code>).
- *
- * <p><li><var>conversionCode</var> is a single letter,
- * following a <code>%</code> character, specifying
- * information about what value the option requires:
- *
- * <table>
- * <tr><td><code>%f</code></td><td>a floating point number</td>
- * <tr><td><code>%i</code></td><td>an integer, in either decimal,
- * hex (if preceeded by <code>0x</code>), or
- * octal (if preceeded by <code>0</code>)</td>
- * <tr valign=top>
- * <td><code>%d</code></td><td>a decimal integer</td>
- * <tr valign=top>
- * <td><code>%o</code></td><td>an octal integer</td>
- * <tr valign=top>
- * <td><code>%h</code></td><td>a hex integer (without the
- * preceeding <code>0x</code>)</td>
- * <tr valign=top>
- * <td><code>%c</code></td><td>a single character, including
- * escape sequences (such as <code>\n</code> or <code>\007</code>),
- * and optionally enclosed in single quotes
- * <tr valign=top>
- * <td><code>%b</code></td><td>a boolean value (<code>true</code>
- * or <code>false</code>)</td>
- * <tr valign=top>
- * <td><code>%s</code></td><td>a string. This will
- * be the argument string itself (or its remainder, in
- * the case of a single word option)</td>
- * <tr valign=top>
- * <td><code>%v</code></td><td>no explicit value is expected,
- * but a boolean value of <code>true</code> (by default)
- * will be stored into the associated result holder if this
- * option is matched. If one wishes to have a value of
- * <code>false</code> stored instead, then the <code>%v</code>
- * should be followed by a "range spec" containing
- * <code>false</code>, as in <code>%v{false}</code>.
- * </table>
- *
- * <p><li><var>rangeSpec</var> is an optional range specification,
- * placed inside curly braces, consisting of a
- * comma-separated list of range items each specifying
- * permissible values for the option. A range item may be an
- * individual value, or it may itself be a subrange,
- * consisting of two individual values, separated by a comma,
- * and enclosed in square or round brackets. Square and round
- * brackets denote closed and open endpoints of a subrange, indicating
- * that the associated endpoint value is included or excluded
- * from the subrange.
- * The values specified in the range spec need to be
- * consistent with the type of value expected by the option.
- *
- * <p><b>Examples:</b>
- *
- * <p>A range spec of <code>{2,4,8,16}</code> for an integer
- * value will allow the integers 2, 4, 8, or 16.
- *
- * <p>A range spec of <code>{[-1.0,1.0]}</code> for a floating
- * point value will allow any floating point number in the
- * range -1.0 to 1.0.
- *
- * <p>A range spec of <code>{(-88,100],1000}</code> for an integer
- * value will allow values > -88 and <= 100, as well as 1000.
- *
- * <p>A range spec of <code>{"foo", "bar", ["aaa","zzz")} </code> for a
- * string value will allow strings equal to <code>"foo"</code> or
- * <code>"bar"</code>, plus any string lexically greater than or equal
- * to <code>"aaa"</code> but less then <code>"zzz"</code>.
- *
- * <p><li><var>multiplier</var> is an optional integer,
- * following a <code>X</code> character,
- * indicating the number of values which the option expects.
- * If the multiplier is not specified, it is assumed to be
- * 1. If the multiplier value is greater than 1, then the
- * result holder should be either an array (of appropriate
- * type) with a length greater than or equal to the multiplier
- * value, or a <code>java.util.Vector</code>
- * <a href=#vectorHolder>as discussed below</a>.
- *
- * <p><li><var>valueDescription</var> is an optional
- * description of the option's value requirements,
- * and consists of all
- * characters between two <code>#</code> characters.
- * The final <code>#</code> character initiates the
- * <i>option description</i>, which may be empty.
- * The value description is used in
- * <a href=#helpInfo>generating help messages</a>.
- *
- * <p><li><var>optionDescription</var> is an optional
- * description of the option itself, consisting of all
- * characters between a <code>#</code> character
- * and the end of the specification string.
- * The option description is used in
- * <a href=#helpInfo>generating help messages</a>.
- * </ul>
- *
- * <p>The result holder must be an object capable of holding
- * a value compatible with the conversion code,
- * or it must be a <code>java.util.Vector</code>.
- * When the option is matched, its associated value is
- * placed in the result holder. If the same option is
- * matched repeatedly, the result holder value will be overwritten,
- * unless the result holder is a <code>java.util.Vector</code>,
- * in which
- * case new holder objects for each match will be allocated
- * and added to the vector. Thus if
- * multiple instances of an option are desired by the
- * program, the result holder should be a
- * <code>java.util.Vector</code>.
- *
- * <p>If the result holder is not a <code>Vector</code>, then
- * it must correspond as follows to the conversion code:
- *
- * <table>
- * <tr valign=top>
- * <td><code>%i</code>, <code>%d</code>, <code>%x</code>,
- * <code>%o</code></td>
- * <td>{@link argparser.IntHolder IntHolder},
- * {@link argparser.LongHolder LongHolder}, <code>int[]</code>, or
- * <code>long[]</code></td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%f</code></td>
- * <td>{@link argparser.FloatHolder FloatHolder},
- * {@link argparser.DoubleHolder DoubleHolder},
- * <code>float[]</code>, or
- * <code>double[]</code></td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%b</code>, <code>%v</code></td>
- * <td>{@link argparser.BooleanHolder BooleanHolder} or
- * <code>boolean[]</code></td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%s</code></td>
- * <td>{@link argparser.StringHolder StringHolder} or
- * <code>String[]</code></td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%c</code></td>
- * <td>{@link argparser.CharHolder CharHolder} or
- * <code>char[]</code></td>
- * </tr>
- * </table>
- *
- * <p>In addition, if the multiplier is greater than 1,
- * then only the array type indicated above may be used,
- * and the array must be at least as long as the multiplier.
- *
- * <p><a name=vectorHolder>If the result holder is a
- * <code>Vector</code>, then the system will create an appropriate
- * result holder object and add it to the vector. Multiple occurances
- * of the option will cause multiple results to be added to the vector.
- *
- * <p>The object allocated by the system to store the result
- * will correspond to the conversion code as follows:
- *
- * <table>
- * <tr valign=top>
- * <td><code>%i</code>, <code>%d</code>, <code>%x</code>,
- * <code>%o</code></td>
- * <td>{@link argparser.LongHolder LongHolder}, or
- * <code>long[]</code> if the multiplier value exceeds 1</td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%f</code></td>
- * <td>{@link argparser.DoubleHolder DoubleHolder}, or
- * <code>double[]</code> if the multiplier value exceeds 1</td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%b</code>, <code>%v</code></td>
- * <td>{@link argparser.BooleanHolder BooleanHolder}, or
- * <code>boolean[]</code>
- * if the multiplier value exceeds 1</td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%s</code></td>
- * <td>{@link argparser.StringHolder StringHolder}, or
- * <code>String[]</code>
- * if the multiplier value exceeds 1</td>
- * </tr>
- *
- * <tr valign=top>
- * <td><code>%c</code></td>
- * <td>{@link argparser.CharHolder CharHolder}, or <code>char[]</code>
- * if the multiplier value exceeds 1</td>
- * </tr>
- * </table>
- *
- * @param spec the specification string
- * @param resHolder object in which to store the associated
- * value
- * @throws IllegalArgumentException if there is an error in
- * the specification or if the result holder is of an invalid
- * type. */
- public void addOption (String spec, Object resHolder)
- throws IllegalArgumentException
- {
- // null terminated string is easier to parse
- StringScanner scanner = new StringScanner(spec);
- Record rec = null;
- NameDesc nameTail = null;
- NameDesc ndesc;
- int i0, i1;
- char c;
-
- do
- { ndesc = new NameDesc();
- boolean nameEndsInWhiteSpace = false;
-
- scanner.skipWhiteSpace();
- i0 = scanner.getIndex();
- while (!Character.isWhitespace(c=scanner.getc()) &&
- c != ',' && c != '%' && c != '\000')
- ;
- i1 = scanner.getIndex();
- if (c!='\000')
- { i1--;
- }
- if (i0==i1)
- { // then c is one of ',' '%' or '\000'
- throw new IllegalArgumentException
- ("Null option name given");
- }
- if (Character.isWhitespace(c))
- { nameEndsInWhiteSpace = true;
- scanner.skipWhiteSpace();
- c = scanner.getc();
- }
- if (c=='\000')
- { throw new IllegalArgumentException
- ("No conversion character given");
- }
- if (c != ',' && c != '%')
- { throw new IllegalArgumentException
- ("Names not separated by ','");
- }
- ndesc.name = scanner.substring (i0, i1);
- if (rec == null)
- { rec = new Record();
- rec.nameList = ndesc;
- }
- else
- { nameTail.next = ndesc;
- }
- nameTail = ndesc;
- ndesc.oneWord = !nameEndsInWhiteSpace;
- }
- while (c != '%');
-
- if (!nameTail.oneWord)
- { for (ndesc=rec.nameList; ndesc!=null; ndesc=ndesc.next)
- { ndesc.oneWord = false;
- }
- }
- c = scanner.getc();
- if (c=='\000')
- { throw new IllegalArgumentException
- ("No conversion character given");
- }
- if (validConversionCodes.indexOf(c) == -1)
- { throw new IllegalArgumentException
- ("Conversion code '" + c + "' not one of '" +
- validConversionCodes + "'");
- }
- rec.convertCode = c;
-
- if (resHolder instanceof Vector)
- { rec.vectorResult = true;
- rec.type = defaultResultType (rec.convertCode);
- }
- else
- {
- switch (rec.convertCode)
- {
- case 'i':
- case 'o':
- case 'd':
- case 'x':
- { if (resHolder instanceof LongHolder ||
- resHolder instanceof long[])
- { rec.type = Record.LONG;
- }
- else if (resHolder instanceof IntHolder ||
- resHolder instanceof int[])
- { rec.type = Record.INT;
- }
- else
- { throw new IllegalArgumentException (
- "Invalid result holder for %" + c);
- }
- break;
- }
- case 'c':
- { if (!(resHolder instanceof CharHolder) &&
- !(resHolder instanceof char[]))
- { throw new IllegalArgumentException (
- "Invalid result holder for %c");
- }
- rec.type = Record.CHAR;
- break;
- }
- case 'v':
- case 'b':
- { if (!(resHolder instanceof BooleanHolder) &&
- !(resHolder instanceof boolean[]))
- { throw new IllegalArgumentException (
- "Invalid result holder for %" + c);
- }
- rec.type = Record.BOOLEAN;
- break;
- }
- case 'f':
- { if (resHolder instanceof DoubleHolder ||
- resHolder instanceof double[])
- { rec.type = Record.DOUBLE;
- }
- else if (resHolder instanceof FloatHolder ||
- resHolder instanceof float[])
- { rec.type = Record.FLOAT;
- }
- else
- { throw new IllegalArgumentException (
- "Invalid result holder for %f");
- }
- break;
- }
- case 's':
- { if (!(resHolder instanceof StringHolder) &&
- !(resHolder instanceof String[]))
- { throw new IllegalArgumentException (
- "Invalid result holder for %s");
- }
- rec.type = Record.STRING;
- break;
- }
- case 'h':
- { // resHolder is ignored for this type
- break;
- }
- }
- }
- if (rec.convertCode == 'h')
- { rec.resHolder = null;
- }
- else
- { rec.resHolder = resHolder;
- }
-
- scanner.skipWhiteSpace();
- // get the range specification, if any
- if (scanner.peekc() == '{')
- {
- if (rec.convertCode == 'h')
- { throw new IllegalArgumentException
- ("Ranges not supported for %h");
- }
-// int bcnt = 0;
- i0 = scanner.getIndex(); // beginning of range spec
- do
- { c = scanner.getc();
- if (c=='\000')
- { throw new IllegalArgumentException
- ("Unterminated range specification");
- }
-// else if (c=='[' || c=='(')
-// { bcnt++;
-// }
-// else if (c==']' || c==')')
-// { bcnt--;
-// }
-// if ((rec.convertCode=='v'||rec.convertCode=='b') && bcnt>1)
-// { throw new IllegalArgumentException
-// ("Sub ranges not supported for %b or %v");
-// }
- }
- while (c != '}');
-// if (c != ']')
-// { throw new IllegalArgumentException
-// ("Range specification must end with ']'");
-// }
- i1 = scanner.getIndex(); // end of range spec
- scanRangeSpec (rec, scanner.substring (i0, i1));
- if (rec.convertCode == 'v' && rec.rangeList!=null)
- { rec.vval = rec.rangeList.low.bval;
- }
- }
- // check for value multiplicity information, if any
- if (scanner.peekc() == 'X')
- {
- if (rec.convertCode == 'h')
- { throw new IllegalArgumentException
- ("Multipliers not supported for %h");
- }
- scanner.getc();
- try
- { rec.numValues = (int)scanner.scanInt();
- }
- catch (StringScanException e)
- { throw new IllegalArgumentException
- ("Malformed value multiplier");
- }
- if (rec.numValues <= 0)
- { throw new IllegalArgumentException
- ("Value multiplier number must be > 0");
- }
- }
- else
- { rec.numValues = 1;
- }
- if (rec.numValues > 1)
- { for (ndesc=rec.nameList; ndesc!=null; ndesc=ndesc.next)
- { if (ndesc.oneWord)
- { throw new IllegalArgumentException (
-"Multiplier value incompatible with one word option " + ndesc.name);
- }
- }
- }
- if (resHolder != null && resHolder.getClass().isArray())
- { if (Array.getLength(resHolder) < rec.numValues)
- { throw new IllegalArgumentException (
-"Result holder array must have a length >= " + rec.numValues);
- }
- }
- else
- { if (rec.numValues > 1 && !(resHolder instanceof Vector))
- { throw new IllegalArgumentException (
-"Multiplier requires result holder to be an array of length >= "
-+ rec.numValues);
- }
- }
-
- // skip white space following conversion information
- scanner.skipWhiteSpace();
-
- // get the help message, if any
-
- if (!scanner.atEnd())
- { if (scanner.getc() != '#')
- { throw new IllegalArgumentException
- ("Illegal character(s), expecting '#'");
- }
- String helpInfo = scanner.substring (scanner.getIndex());
- // look for second '#'. If there is one, then info
- // between the first and second '#' is the value descriptor.
- int k = helpInfo.indexOf ("#");
- if (k != -1)
- { rec.valueDesc = helpInfo.substring (0, k);
- rec.helpMsg = helpInfo.substring (k+1);
- }
- else
- { rec.helpMsg = helpInfo;
- }
- }
- else
- { rec.helpMsg = "";
- }
-
- // parse helpMsg for required/optional information if present
- // default to required
- if (rec.helpMsg.indexOf("(optional") != -1) {
- rec.required = false;
- }
-
- // add option information to match list
- if (rec.convertCode == 'h' && firstHelpOption == defaultHelpOption)
- { matchList.remove (defaultHelpOption);
- firstHelpOption = rec;
- }
- matchList.add (rec);
- }
-
- Record lastMatchRecord ()
- { return (Record)matchList.lastElement();
- }
-
- private Record getRecord (String arg, ObjectHolder ndescHolder)
- {
- NameDesc ndesc;
- for (int i=0; i<matchList.size(); i++)
- { Record rec = (Record)matchList.get(i);
- for (ndesc=rec.nameList; ndesc!=null; ndesc=ndesc.next)
- { if (rec.convertCode != 'v' && ndesc.oneWord)
- { if (arg.startsWith (ndesc.name))
- { if (ndescHolder != null)
- { ndescHolder.value = ndesc;
- }
- return rec;
- }
- }
- else
- { if (arg.equals (ndesc.name))
- { if (ndescHolder != null)
- { ndescHolder.value = ndesc;
- }
- return rec;
- }
- }
- }
- }
- return null;
- }
-
- public void checkRequiredArgs() {
- for (int i=1; i<matchList.size(); i++) {
- Record rec = (Record)matchList.get(i);
- StringHolder myString = (StringHolder) rec.resHolder;
- if (((myString.value == null) || (myString.value.equals(""))) && (rec.required)) {
- printErrorAndExit("Required parameter " + rec.nameList.name + " is not specified.");
+public class ArgParser {
+ Vector<Record> matchList;
+ // int tabSpacing = 8;
+ String synopsisString;
+ boolean helpOptionsEnabled = true;
+ Record defaultHelpOption = null;
+ Record firstHelpOption = null;
+ PrintStream printStream = System.out;
+ int helpIndent = 24;
+ String errMsg = null;
+ String unmatchedArg = null;
+
+ static String validConversionCodes = "iodxcbfsvh";
+
+ /**
+ * Indicates that the program should exit with an appropriate message
+ * in the event of an erroneous or malformed argument.
+ */
+ public static int EXIT_ON_ERROR = 1;
+
+ /**
+ * Indicates that the program should exit with an appropriate message
+ * in the event of an unmatched argument.
+ */
+ public static int EXIT_ON_UNMATCHED = 2;
+
+ /**
+ * Returns a string containing the valid conversion codes. These
+ * are the characters which may follow the <code>%</code> character in
+ * the specification string of {@link #addOption addOption}.
+ *
+ * @return Valid conversion codes
+ * @see #addOption
+ */
+ public static String getValidConversionCodes() {
+ return validConversionCodes;
+ }
+
+ static class NameDesc {
+ String name;
+ // oneWord implies that any value associated with
+ // option is concatenated onto the argument string itself
+ boolean oneWord;
+ NameDesc next = null;
+ }
+
+ static class RangePnt {
+ double dval = 0;
+ long lval = 0;
+ String sval = null;
+ boolean bval = true;
+ boolean closed = true;
+
+ RangePnt(String s, boolean closed) {
+ sval = s;
+ this.closed = closed;
+ }
+
+ RangePnt(double d, boolean closed) {
+ dval = d;
+ this.closed = closed;
+ }
+
+ RangePnt(long l, boolean closed) {
+ lval = l;
+ this.closed = closed;
+ }
+
+ RangePnt(boolean b, boolean closed) {
+ bval = b;
+ this.closed = closed;
+ }
+
+ RangePnt(StringScanner scanner, int type)
+ throws IllegalArgumentException {
+ String typeName = null;
+ try {
+ switch (type) {
+ case Record.CHAR: {
+ typeName = "character";
+ lval = scanner.scanChar();
+ break;
}
+ case Record.INT:
+ case Record.LONG: {
+ typeName = "integer";
+ lval = scanner.scanInt();
+ break;
+ }
+ case Record.FLOAT:
+ case Record.DOUBLE: {
+ typeName = "float";
+ dval = scanner.scanDouble();
+ break;
+ }
+ case Record.STRING: {
+ typeName = "string";
+ sval = scanner.scanString();
+ break;
+ }
+ case Record.BOOLEAN: {
+ typeName = "boolean";
+ bval = scanner.scanBoolean();
+ break;
+ }
+ }
+ } catch (StringScanException e) {
+ throw new IllegalArgumentException(
+ "Malformed " + typeName + " '" +
+ scanner.substring(scanner.getIndex(),
+ e.getFailIndex() + 1) +
+ "' in range spec");
}
- }
-
-
- Object getResultHolder (String arg)
- {
- Record rec = getRecord(arg, null);
- return (rec != null) ? rec.resHolder : null;
- }
-
- String getOptionName (String arg)
- {
- ObjectHolder ndescHolder = new ObjectHolder();
- Record rec = getRecord(arg, ndescHolder);
- return (rec != null) ? ((NameDesc)ndescHolder.value).name : null;
- }
-
- String getOptionRangeDesc (String arg)
- {
- Record rec = getRecord(arg, null);
- return (rec != null) ? rec.rangeDesc : null;
- }
-
- String getOptionTypeName (String arg)
- {
- Record rec = getRecord(arg, null);
- return (rec != null) ? rec.valTypeName() : null;
- }
-
- private Object createResultHolder (Record rec)
- {
- if (rec.numValues == 1)
- { switch (rec.type)
- { case Record.LONG:
- { return new LongHolder();
- }
- case Record.CHAR:
- { return new CharHolder();
- }
- case Record.BOOLEAN:
- { return new BooleanHolder();
- }
- case Record.DOUBLE:
- { return new DoubleHolder();
- }
- case Record.STRING:
- { return new StringHolder();
- }
- }
- }
- else
- { switch (rec.type)
- { case Record.LONG:
- { return new long[rec.numValues];
- }
- case Record.CHAR:
- { return new char[rec.numValues];
- }
- case Record.BOOLEAN:
- { return new boolean[rec.numValues];
- }
- case Record.DOUBLE:
- { return new double[rec.numValues];
- }
- case Record.STRING:
- { return new String[rec.numValues];
- }
- }
- }
- return null; // can't happen
- }
-
- static void stringToArgs (Vector<String> vec, String s,
- boolean allowQuotedStrings)
- throws StringScanException
- {
- StringScanner scanner = new StringScanner(s);
- scanner.skipWhiteSpace();
- while (!scanner.atEnd())
- { if (allowQuotedStrings)
- { vec.add (scanner.scanString());
- }
- else
- { vec.add (scanner.scanNonWhiteSpaceString());
- }
- scanner.skipWhiteSpace();
- }
- }
-
- /**
- * Reads in a set of strings from a reader and prepends them to an
- * argument list. Strings are delimited by either whitespace or
- * double quotes <code>"</code>. The character <code>#</code> acts as
- * a comment character, causing input to the end of the current line to
- * be ignored.
- *
- * @param reader Reader from which to read the strings
- * @param args Initial set of argument values. Can be
- * specified as <code>null</code>.
- * @throws IOException if an error occured while reading.
- */
- public static String[] prependArgs (Reader reader, String[] args)
- throws IOException
- {
- if (args == null)
- { args = new String[0];
- }
- LineNumberReader lineReader = new LineNumberReader (reader);
- Vector<String> vec = new Vector<String>(100, 100);
- String line;
- int i, k;
-
- while ((line = lineReader.readLine()) != null)
- { int commentIdx = line.indexOf ("#");
- if (commentIdx != -1)
- { line = line.substring (0, commentIdx);
- }
- try
- { stringToArgs (vec, line, /*allowQuotedStings=*/true);
- }
- catch (StringScanException e)
- { throw new IOException (
- "malformed string, line "+lineReader.getLineNumber());
- }
- }
- String[] result = new String[vec.size()+args.length];
- for (i=0; i<vec.size(); i++)
- { result[i] = (String)vec.get(i);
- }
- for (k=0; k<args.length; k++)
- { result[i++] = args[k];
- }
- return result;
- }
-
- /**
- * Reads in a set of strings from a file and prepends them to an
- * argument list. Strings are delimited by either whitespace or double
- * quotes <code>"</code>. The character <code>#</code> acts as a
- * comment character, causing input to the end of the current line to
- * be ignored.
- *
- * @param file File to be read
- * @param args Initial set of argument values. Can be
- * specified as <code>null</code>.
- * @throws IOException if an error occured while reading the file.
- */
- public static String[] prependArgs (File file, String[] args)
- throws IOException
- {
- if (args == null)
- { args = new String[0];
- }
- if (!file.canRead())
- { return args;
- }
- try
- { return prependArgs (new FileReader (file), args);
- }
- catch (IOException e)
- { throw new IOException (
-"File " + file.getName() + ": " + e.getMessage());
- }
- }
-
- /**
- * Sets the parser's error message.
- *
- * @param s Error message
- */
- protected void setError (String msg)
- {
- errMsg = msg;
- }
-
- /**
- * Prints an error message, along with a pointer to help options,
- * if available, and causes the program to exit with code 1.
- */
- public void printErrorAndExit (String msg)
- {
- if (helpOptionsEnabled && firstHelpOptionName() != null)
- { msg += "\nUse "+firstHelpOptionName()+" for help information";
- }
- if (printStream != null)
- { printStream.println (msg);
- }
- System.exit(1);
- }
-
- /**
- * Matches arguments within an argument list.
- *
- * <p>In the event of an erroneous or unmatched argument, the method
- * prints a message and exits the program with code 1.
- *
- * <p>If help options are enabled and one of the arguments matches a
- * help option, then the result of {@link #getHelpMessage
- * getHelpMessage} is printed to the default print stream and the
- * program exits with code 0. If help options are not enabled, they
- * are ignored.
- *
- * @param args argument list
- * @see ArgParser#getDefaultPrintStream
- */
- public void matchAllArgs (String[] args)
- {
- matchAllArgs (args, 0, EXIT_ON_UNMATCHED | EXIT_ON_ERROR);
- }
-
- /**
- * Matches arguments within an argument list and returns
- * those which were not matched. The matching starts at a location
- * in <code>args</code> specified by <code>idx</code>, and
- * unmatched arguments are returned in a String array.
- *
- * <p>In the event of an erroneous argument, the method either prints a
- * message and exits the program (if {@link #EXIT_ON_ERROR} is
- * set in <code>exitFlags</code>)
- * or terminates the matching and creates a error message that
- * can be retrieved by {@link #getErrorMessage}.
- *
- * <p>In the event of an umatched argument, the method will print a
- * message and exit if {@link #EXIT_ON_UNMATCHED} is set
- * in <code>errorFlags</code>.
- * Otherwise, the unmatched argument will be appended to the returned
- * array of unmatched values, and the matching will continue at the
- * next location.
- *
- * <p>If help options are enabled and one of the arguments matches a
- * help option, then the result of {@link #getHelpMessage
- * getHelpMessage} is printed to the the default print stream and the
- * program exits with code 0. If help options are not enabled, then
- * they will not be matched.
- *
- * @param args argument list
- * @param idx starting location in list
- * @param exitFlags conditions causing the program to exit. Should be
- * an or-ed combintion of {@link #EXIT_ON_ERROR} or {@link
- * #EXIT_ON_UNMATCHED}.
- * @return array of arguments that were not matched, or
- * <code>null</code> if all arguments were successfully matched
- * @see ArgParser#getErrorMessage
- * @see ArgParser#getDefaultPrintStream
- */
- public String[] matchAllArgs (String[] args, int idx, int exitFlags)
- {
- Vector<String> unmatched = new Vector<String>(10);
-
- while (idx < args.length)
- { try
- { idx = matchArg (args, idx);
- if (unmatchedArg != null)
- { if ((exitFlags & EXIT_ON_UNMATCHED) != 0)
- { printErrorAndExit (
- "Unrecognized argument: " + unmatchedArg);
- }
- else
- { unmatched.add (unmatchedArg);
- }
- }
- }
- catch (ArgParseException e)
- { if ((exitFlags & EXIT_ON_ERROR) != 0)
- { printErrorAndExit (e.getMessage());
- }
- break;
- }
- }
- if (unmatched.size() == 0)
- { return null;
- }
- else
- { return (String[])unmatched.toArray(new String[0]);
- }
- }
-
- /**
- * Matches one option starting at a specified location in an argument
- * list. The method returns the location in the list where the next
- * match should begin.
- *
- * <p>In the event of an erroneous argument, the method throws
- * an {@link argparser.ArgParseException ArgParseException}
- * with an appropriate error message. This error
- * message can also be retrieved using
- * {@link #getErrorMessage getErrorMessage}.
- *
- * <p>In the event of an umatched argument, the method will return idx
- * + 1, and {@link #getUnmatchedArgument getUnmatchedArgument} will
- * return a copy of the unmatched argument. If an argument is matched,
- * {@link #getUnmatchedArgument getUnmatchedArgument} will return
- * <code>null</code>.
- *
- * <p>If help options are enabled and the argument matches a help
- * option, then the result of {@link #getHelpMessage getHelpMessage} is printed to
- * the the default print stream and the program exits with code 0. If
- * help options are not enabled, then they are ignored.
- *
- * @param args argument list
- * @param idx location in list where match should start
- * @return location in list where next match should start
- * @throws ArgParseException if there was an error performing
- * the match (such as improper or insufficient values).
- * @see ArgParser#setDefaultPrintStream
- * @see ArgParser#getHelpOptionsEnabled
- * @see ArgParser#getErrorMessage
- * @see ArgParser#getUnmatchedArgument
- */
- @SuppressWarnings("unchecked")
- public int matchArg (String[] args, int idx)
- throws ArgParseException
- {
- unmatchedArg = null;
- setError (null);
- try
- { ObjectHolder ndescHolder = new ObjectHolder();
- Record rec = getRecord (args[idx], ndescHolder);
- if (rec == null || (rec.convertCode=='h' && !helpOptionsEnabled))
- { // didn't match
- unmatchedArg = new String(args[idx]);
- return idx+1;
- }
- NameDesc ndesc = (NameDesc)ndescHolder.value;
- Object result;
- if (rec.resHolder instanceof Vector)
- { result = createResultHolder (rec);
- }
- else
- { result = rec.resHolder;
- }
- if (rec.convertCode == 'h')
- { if (helpOptionsEnabled)
- { printStream.println (getHelpMessage());
- System.exit (0);
- }
- else
- { return idx+1;
- }
- }
- else if (rec.convertCode != 'v')
- { if (ndesc.oneWord)
- { rec.scanValue (
- result, ndesc.name,
- args[idx].substring (ndesc.name.length()), 0);
- }
- else
- { if (idx+rec.numValues >= args.length)
- { throw new ArgParseException (
- ndesc.name, "requires " + rec.numValues + " value" +
- (rec.numValues > 1 ? "s" : ""));
- }
- for (int k=0; k<rec.numValues; k++)
- { rec.scanValue (result, ndesc.name, args[++idx], k);
- }
- }
- }
- else
- { if (rec.resHolder instanceof BooleanHolder)
- { ((BooleanHolder)result).value = rec.vval;
- }
- else
- { for (int k=0; k<rec.numValues; k++)
- { ((boolean[])result)[k] = rec.vval;
- }
- }
- }
- if (rec.resHolder instanceof Vector)
- { ((Vector<Object>)rec.resHolder).add (result);
- }
- }
- catch (ArgParseException e)
- { setError (e.getMessage());
- throw e;
- }
- return idx+1;
- }
-
- private String spaceString (int n)
- {
- StringBuffer sbuf = new StringBuffer(n);
- for (int i=0; i<n; i++)
- { sbuf.append(' ');
- }
- return sbuf.toString();
- }
-
-// public String getShortHelpMessage ()
-// {
-// String s;
-// Record rec;
-// NameDesc ndesc;
-// int initialIndent = 8;
-// int col = initialIndent;
-
-// if (maxcols <= 0)
-// { maxcols = 80;
-// }
-// if (matchList.size() > 0)
-// { ps.print (spaceString(initialIndent));
-// }
-// for (int i=0; i<matchList.size(); i++)
-// { rec = (Record)matchList.get(i);
-// s = "[";
-// for (ndesc=rec.nameList; ndesc!=null; ndesc=ndesc.next)
-// { s = s + ndesc.name;
-// if (ndesc.oneWord == false)
-// { s = s + " ";
-// }
-// if (ndesc.next != null)
-// { s = s + ",";
-// }
-// }
-// if (rec.convertCode != 'v' && rec.convertCode != 'h')
-// { if (rec.valueDesc != null)
-// { s += rec.valueDesc;
-// }
-// else
-// { s = s + "<" + rec.valTypeName() + ">";
-// if (rec.numValues > 1)
-// { s += "X" + rec.numValues;
-// }
-// }
-// }
-// s = s + "]";
-// /*
-// (col+=s.length()) > (maxcols-1) => we will spill over edge.
-// we use (maxcols-1) because if we go right to the edge
-// (maxcols), we get wrap new line inserted "for us".
-// i != 0 means we print the first entry, no matter
-// how long it is. Subsequent entries are printed
-// full length anyway. */
-
-// if ((col+=s.length()) > (maxcols-1) && i != 0)
-// { col = initialIndent+s.length();
-// ps.print ("\n" + spaceString(initialIndent));
-// }
-// ps.print (s);
-// }
-// if (matchList.size() > 0)
-// { ps.print ('\n');
-// ps.flush();
-// }
-// }
-
- /**
- * Returns a string describing the allowed options
- * in detail.
- *
- * @return help information string.
- */
- public String getHelpMessage ()
- {
- Record rec;
- NameDesc ndesc;
- boolean hasOneWordAlias = false;
- String s;
-
- s = "Usage: " + synopsisString + "\n";
- s += "Options include:\n\n";
- for (int i=0; i<matchList.size(); i++)
- { String optionInfo = "";
- rec = (Record)matchList.get(i);
- if (rec.convertCode=='h' && !helpOptionsEnabled)
- { continue;
- }
- for (ndesc=rec.nameList; ndesc!=null; ndesc=ndesc.next)
- { if (ndesc.oneWord)
- { hasOneWordAlias = true;
- break;
- }
- }
- for (ndesc=rec.nameList; ndesc!=null; ndesc=ndesc.next)
- { optionInfo += ndesc.name;
- if (hasOneWordAlias && !ndesc.oneWord)
- { optionInfo += " ";
- }
- if (ndesc.next != null)
- { optionInfo += ",";
- }
- }
- if (!hasOneWordAlias)
- { optionInfo += " ";
- }
- if (rec.convertCode != 'v' && rec.convertCode != 'h')
- { if (rec.valueDesc != null)
- { optionInfo += rec.valueDesc;
- }
- else
- { if (rec.rangeDesc != null)
- { optionInfo += "<" + rec.valTypeName() + " "
- + rec.rangeDesc + ">";
- }
- else
- { optionInfo += "<" + rec.valTypeName() + ">";
- }
- }
- }
- if (rec.numValues > 1)
- { optionInfo += "X" + rec.numValues;
- }
- s += optionInfo;
- if (rec.helpMsg.length() > 0)
- { int pad = helpIndent - optionInfo.length();
- if (pad < 2)
- { //s += '\n';
- pad = helpIndent;
- }
-// s += spaceString(pad) + rec.helpMsg;
- s += spaceString(4) + rec.helpMsg;
- }
- s += '\n';
- }
- return s;
- }
-
- /**
- * Returns the parser's error message. This is automatically
- * set whenever an error is encountered in <code>matchArg</code>
- * or <code>matchAllArgs</code>, and is automatically set to
- * <code>null</code> at the beginning of these methods.
- *
- * @return error message
- */
- public String getErrorMessage()
- {
- return errMsg;
- }
-
- /**
- * Returns the value of an unmatched argument discovered {@link
- * #matchArg matchArg} or {@link #matchAllArgs(String[],int,int)
- * matchAllArgs}. If there was no unmatched argument,
- * <code>null</code> is returned.
- *
- * @return unmatched argument
- */
- public String getUnmatchedArgument()
- {
- return unmatchedArg;
- }
-}
+ // this.closed = closed;
+ }
+
+ void setClosed(boolean closed) {
+ this.closed = closed;
+ }
+
+ boolean getClosed() {
+ return closed;
+ }
+
+ int compareTo(double d) {
+ if (dval < d) {
+ return -1;
+ } else if (d == dval) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ int compareTo(long l) {
+ if (lval < l) {
+ return -1;
+ } else if (l == lval) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ int compareTo(String s) {
+ return sval.compareTo(s);
+ }
+ int compareTo(boolean b) {
+ if (b == bval) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ public String toString() {
+ return "{ dval=" + dval + ", lval=" + lval +
+ ", sval=" + sval + ", bval=" + bval +
+ ", closed=" + closed + "}";
+ }
+ }
+
+ class RangeAtom {
+ RangePnt low = null;
+ RangePnt high = null;
+ RangeAtom next = null;
+
+ RangeAtom(RangePnt p0, RangePnt p1, int type)
+ throws IllegalArgumentException {
+ int cmp = 0;
+ switch (type) {
+ case Record.CHAR:
+ case Record.INT:
+ case Record.LONG: {
+ cmp = p0.compareTo(p1.lval);
+ break;
+ }
+ case Record.FLOAT:
+ case Record.DOUBLE: {
+ cmp = p0.compareTo(p1.dval);
+ break;
+ }
+ case Record.STRING: {
+ cmp = p0.compareTo(p1.sval);
+ break;
+ }
+ }
+ if (cmp > 0) { // then switch high and low
+ low = p1;
+ high = p0;
+ } else {
+ low = p0;
+ high = p1;
+ }
+ }
+
+ RangeAtom(RangePnt p0)
+ throws IllegalArgumentException {
+ low = p0;
+ }
+
+ boolean match(double d) {
+ int lc = low.compareTo(d);
+ if (high != null) {
+ int hc = high.compareTo(d);
+ return (lc * hc < 0 ||
+ (low.closed && lc == 0) || (high.closed && hc == 0));
+ } else {
+ return lc == 0;
+ }
+ }
+
+ boolean match(long l) {
+ int lc = low.compareTo(l);
+ if (high != null) {
+ int hc = high.compareTo(l);
+ return (lc * hc < 0 ||
+ (low.closed && lc == 0) || (high.closed && hc == 0));
+ } else {
+ return lc == 0;
+ }
+ }
+
+ boolean match(String s) {
+ int lc = low.compareTo(s);
+ if (high != null) {
+ int hc = high.compareTo(s);
+ return (lc * hc < 0 ||
+ (low.closed && lc == 0) || (high.closed && hc == 0));
+ } else {
+ return lc == 0;
+ }
+ }
+
+ boolean match(boolean b) {
+ return low.compareTo(b) == 0;
+ }
+
+ public String toString() {
+ return "low=" + (low == null ? "null" : low.toString()) +
+ ", high=" + (high == null ? "null" : high.toString());
+ }
+ }
+
+ class Record {
+ NameDesc nameList;
+ static final int NOTYPE = 0;
+ static final int BOOLEAN = 1;
+ static final int CHAR = 2;
+ static final int INT = 3;
+ static final int LONG = 4;
+ static final int FLOAT = 5;
+ static final int DOUBLE = 6;
+ static final int STRING = 7;
+ int type;
+ int numValues;
+ boolean vectorResult = false;
+ boolean required = true;
+
+ String helpMsg = null;
+ String valueDesc = null;
+ String rangeDesc = null;
+ Object resHolder = null;
+ RangeAtom rangeList = null;
+ RangeAtom rangeTail = null;
+ char convertCode;
+ boolean vval = true; // default value for now
+
+ NameDesc firstNameDesc() {
+ return nameList;
+ }
+
+ RangeAtom firstRangeAtom() {
+ return rangeList;
+ }
+
+ int numRangeAtoms() {
+ int cnt = 0;
+ for (RangeAtom ra = rangeList; ra != null; ra = ra.next) {
+ cnt++;
+ }
+ return cnt;
+ }
+
+ void addRangeAtom(RangeAtom ra) {
+ if (rangeList == null) {
+ rangeList = ra;
+ } else {
+ rangeTail.next = ra;
+ }
+ rangeTail = ra;
+ }
+
+ boolean withinRange(double d) {
+ if (rangeList == null) {
+ return true;
+ }
+ for (RangeAtom ra = rangeList; ra != null; ra = ra.next) {
+ if (ra.match(d)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean withinRange(long l) {
+ if (rangeList == null) {
+ return true;
+ }
+ for (RangeAtom ra = rangeList; ra != null; ra = ra.next) {
+ if (ra.match(l)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean withinRange(String s) {
+ if (rangeList == null) {
+ return true;
+ }
+ for (RangeAtom ra = rangeList; ra != null; ra = ra.next) {
+ if (ra.match(s)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean withinRange(boolean b) {
+ if (rangeList == null) {
+ return true;
+ }
+ for (RangeAtom ra = rangeList; ra != null; ra = ra.next) {
+ if (ra.match(b)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ String valTypeName() {
+ switch (convertCode) {
+ case 'i': {
+ return ("integer");
+ }
+ case 'o': {
+ return ("octal integer");
+ }
+ case 'd': {
+ return ("decimal integer");
+ }
+ case 'x': {
+ return ("hex integer");
+ }
+ case 'c': {
+ return ("char");
+ }
+ case 'b': {
+ return ("boolean");
+ }
+ case 'f': {
+ return ("float");
+ }
+ case 's': {
+ return ("string");
+ }
+ }
+ return ("unknown");
+ }
+
+ void scanValue(Object result, String name, String s, int resultIdx)
+ throws ArgParseException {
+ double dval = 0;
+ String sval = null;
+ long lval = 0;
+ boolean bval = false;
+
+ if (s.length() == 0) {
+ throw new ArgParseException(name, "requires a contiguous value");
+ }
+ StringScanner scanner = new StringScanner(s);
+ try {
+ switch (convertCode) {
+ case 'i': {
+ lval = scanner.scanInt();
+ break;
+ }
+ case 'o': {
+ lval = scanner.scanInt(8, false);
+ break;
+ }
+ case 'd': {
+ lval = scanner.scanInt(10, false);
+ break;
+ }
+ case 'x': {
+ lval = scanner.scanInt(16, false);
+ break;
+ }
+ case 'c': {
+ lval = scanner.scanChar();
+ break;
+ }
+ case 'b': {
+ bval = scanner.scanBoolean();
+ break;
+ }
+ case 'f': {
+ dval = scanner.scanDouble();
+ break;
+ }
+ case 's': {
+ sval = scanner.getString();
+ break;
+ }
+ }
+ } catch (StringScanException e) {
+ throw new ArgParseException(
+ name, "malformed " + valTypeName() + " '" + s + "'");
+ }
+ scanner.skipWhiteSpace();
+ if (!scanner.atEnd()) {
+ throw new ArgParseException(
+ name, "malformed " + valTypeName() + " '" + s + "'");
+ }
+ boolean outOfRange = false;
+ switch (type) {
+ case CHAR:
+ case INT:
+ case LONG: {
+ outOfRange = !withinRange(lval);
+ break;
+ }
+ case FLOAT:
+ case DOUBLE: {
+ outOfRange = !withinRange(dval);
+ break;
+ }
+ case STRING: {
+ outOfRange = !withinRange(sval);
+ break;
+ }
+ case BOOLEAN: {
+ outOfRange = !withinRange(bval);
+ break;
+ }
+ }
+ if (outOfRange) {
+ String errmsg = "value " + s + " not in range ";
+ throw new ArgParseException(
+ name, "value '" + s + "' not in range " + rangeDesc);
+ }
+ if (result.getClass().isArray()) {
+ switch (type) {
+ case BOOLEAN: {
+ ((boolean[]) result)[resultIdx] = bval;
+ break;
+ }
+ case CHAR: {
+ ((char[]) result)[resultIdx] = (char) lval;
+ break;
+ }
+ case INT: {
+ ((int[]) result)[resultIdx] = (int) lval;
+ break;
+ }
+ case LONG: {
+ ((long[]) result)[resultIdx] = lval;
+ break;
+ }
+ case FLOAT: {
+ ((float[]) result)[resultIdx] = (float) dval;
+ break;
+ }
+ case DOUBLE: {
+ ((double[]) result)[resultIdx] = dval;
+ break;
+ }
+ case STRING: {
+ ((String[]) result)[resultIdx] = sval;
+ break;
+ }
+ }
+ } else {
+ switch (type) {
+ case BOOLEAN: {
+ ((BooleanHolder) result).value = bval;
+ break;
+ }
+ case CHAR: {
+ ((CharHolder) result).value = (char) lval;
+ break;
+ }
+ case INT: {
+ ((IntHolder) result).value = (int) lval;
+ break;
+ }
+ case LONG: {
+ ((LongHolder) result).value = lval;
+ break;
+ }
+ case FLOAT: {
+ ((FloatHolder) result).value = (float) dval;
+ break;
+ }
+ case DOUBLE: {
+ ((DoubleHolder) result).value = dval;
+ break;
+ }
+ case STRING: {
+ ((StringHolder) result).value = sval;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private String firstHelpOptionName() {
+ if (firstHelpOption != null) {
+ return firstHelpOption.nameList.name;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Creates an <code>ArgParser</code> with a synopsis
+ * string, and the default help options <code>-help</code> and <code>-&#063;</code>.
+ *
+ * @param synopsisString string that briefly describes program usage,
+ * for use by {@link #getHelpMessage getHelpMessage}.
+ * @see ArgParser#getSynopsisString
+ * @see ArgParser#getHelpMessage
+ */
+ public ArgParser(String synopsisString) {
+ this(synopsisString, true);
+ }
+
+ /**
+ * Creates an <code>ArgParser</code> with a synopsis
+ * string. The help options <code>-help</code> and <code>-?</code> are added if <code>defaultHelp</code> is true.
+ *
+ * @param synopsisString string that briefly describes program usage,
+ * for use by {@link #getHelpMessage getHelpMessage}.
+ * @param defaultHelp if true, adds the default help options
+ * @see ArgParser#getSynopsisString
+ * @see ArgParser#getHelpMessage
+ */
+ public ArgParser(String synopsisString, boolean defaultHelp) {
+ matchList = new Vector<Record>(128);
+ this.synopsisString = synopsisString;
+ if (defaultHelp) {
+ addOption("-help,-? %h #displays help information", null);
+ defaultHelpOption = firstHelpOption = matchList.get(0);
+ }
+ }
+
+ /**
+ * Returns the synopsis string used by the parser.
+ * The synopsis string is a short description of how to invoke
+ * the program, and usually looks something like
+ * <p>
+ * <prec> "java somepackage.SomeClass [options] files ..." </prec>
+ *
+ * <p>
+ * It is used in help and error messages.
+ *
+ * @return synopsis string
+ * @see ArgParser#setSynopsisString
+ * @see ArgParser#getHelpMessage
+ */
+ public String getSynopsisString() {
+ return synopsisString;
+ }
+
+ /**
+ * Sets the synopsis string used by the parser.
+ *
+ * @param s new synopsis string
+ * @see ArgParser#getSynopsisString
+ * @see ArgParser#getHelpMessage
+ */
+ public void setSynopsisString(String s) {
+ synopsisString = s;
+ }
+
+ /**
+ * Indicates whether or not help options are enabled.
+ *
+ * @return true if help options are enabled
+ * @see ArgParser#setHelpOptionsEnabled
+ * @see ArgParser#addOption
+ */
+ public boolean getHelpOptionsEnabled() {
+ return helpOptionsEnabled;
+ }
+
+ /**
+ * Enables or disables help options. Help options are those
+ * associated with a conversion code of <code>%h</code>. If
+ * help options are enabled, and a help option is matched,
+ * then the string produced by {@link #getHelpMessage getHelpMessage} is printed to the default print stream and the program
+ * exits with code 0. Otherwise, arguments which match help
+ * options are ignored.
+ *
+ * @param enable enables help options if <code>true</code>.
+ * @see ArgParser#getHelpOptionsEnabled
+ * @see ArgParser#addOption
+ * @see ArgParser#setDefaultPrintStream
+ */
+ public void setHelpOptionsEnabled(boolean enable) {
+ helpOptionsEnabled = enable;
+ }
+
+ /**
+ * Returns the default print stream used for outputting help
+ * and error information.
+ *
+ * @return default print stream
+ * @see ArgParser#setDefaultPrintStream
+ */
+ public PrintStream getDefaultPrintStream() {
+ return printStream;
+ }
+
+ /**
+ * Sets the default print stream used for outputting help
+ * and error information.
+ *
+ * @param stream new default print stream
+ * @see ArgParser#getDefaultPrintStream
+ */
+ public void setDefaultPrintStream(PrintStream stream) {
+ printStream = stream;
+ }
+
+ /**
+ * Gets the indentation used by {@link #getHelpMessage
+ * getHelpMessage}.
+ *
+ * @return number of indentation columns
+ * @see ArgParser#setHelpIndentation
+ * @see ArgParser#getHelpMessage
+ */
+ public int getHelpIndentation() {
+ return helpIndent;
+ }
+
+ /**
+ * Sets the indentation used by {@link #getHelpMessage
+ * getHelpMessage}. This is the number of columns that an option's help
+ * information is indented. If the option's name and value information
+ * can fit within this number of columns, then all information about
+ * the option is placed on one line. Otherwise, the indented help
+ * information is placed on a separate line.
+ *
+ * @param indent number of indentation columns
+ * @see ArgParser#getHelpIndentation
+ * @see ArgParser#getHelpMessage
+ */
+ public void setHelpIndentation(int indent) {
+ helpIndent = indent;
+ }
+
+ // public void setTabSpacing (int n)
+ // { tabSpacing = n;
+ // }
+
+ // public int getTabSpacing ()
+ // { return tabSpacing;
+ // }
+
+ private void scanRangeSpec(Record rec, String s)
+ throws IllegalArgumentException {
+ StringScanner scanner = new StringScanner(s);
+ int i0, i = 1;
+ char c, c0, c1;
+
+ scanner.setStringDelimiters(")],}");
+ c = scanner.getc(); // swallow the first '{'
+ scanner.skipWhiteSpace();
+ while ((c = scanner.peekc()) != '}') {
+ RangePnt p0, p1;
+
+ if (c == '[' || c == '(') {
+ if (rec.convertCode == 'v' || rec.convertCode == 'b') {
+ throw new IllegalArgumentException("Sub ranges not supported for %b or %v");
+ }
+ c0 = scanner.getc(); // record & swallow character
+ scanner.skipWhiteSpace();
+ p0 = new RangePnt(scanner, rec.type);
+ scanner.skipWhiteSpace();
+ if (scanner.getc() != ',') {
+ throw new IllegalArgumentException("Missing ',' in subrange specification");
+ }
+ p1 = new RangePnt(scanner, rec.type);
+ scanner.skipWhiteSpace();
+ if ((c1 = scanner.getc()) != ']' && c1 != ')') {
+ throw new IllegalArgumentException("Unterminated subrange");
+ }
+ if (c0 == '(') {
+ p0.setClosed(false);
+ }
+ if (c1 == ')') {
+ p1.setClosed(false);
+ }
+ rec.addRangeAtom(new RangeAtom(p0, p1, rec.type));
+ } else {
+ scanner.skipWhiteSpace();
+ p0 = new RangePnt(scanner, rec.type);
+ rec.addRangeAtom(new RangeAtom(p0));
+ }
+ scanner.skipWhiteSpace();
+ if ((c = scanner.peekc()) == ',') {
+ scanner.getc();
+ scanner.skipWhiteSpace();
+ } else if (c != '}') {
+ throw new IllegalArgumentException("Range spec: ',' or '}' expected");
+ }
+ }
+ if (rec.numRangeAtoms() == 1) {
+ rec.rangeDesc = s.substring(1, s.length() - 1);
+ } else {
+ rec.rangeDesc = s;
+ }
+ }
+
+ private int defaultResultType(char convertCode) {
+ switch (convertCode) {
+ case 'i':
+ case 'o':
+ case 'd':
+ case 'x': {
+ return Record.LONG;
+ }
+ case 'c': {
+ return Record.CHAR;
+ }
+ case 'v':
+ case 'b': {
+ return Record.BOOLEAN;
+ }
+ case 'f': {
+ return Record.DOUBLE;
+ }
+ case 's': {
+ return Record.STRING;
+ }
+ }
+ return Record.NOTYPE;
+ }
+
+ /**
+ * Adds a new option description to the parser. The method takes two
+ * arguments: a specification string, and a result holder in which to
+ * store the associated value.
+ *
+ * <p>
+ * The specification string has the general form
+ *
+ * <p>
+ * <var>optionNames</var> <code>%</code><var>conversionCode</var> [<code>{</code><var>rangeSpec</var><code>}</code>] [<code>X</code><var>multiplier</var>] [<code>#</code><var>valueDescription</var>] [<code>#</code><var>optionDescription</var>] </code>
+ *
+ * <p>
+ * where
+ * <ul>
+ * <p>
+ * <li><var>optionNames</var> is a comma-separated list of names for the option (such as <code>-f, --file</code>).
+ *
+ * <p>
+ * <li><var>conversionCode</var> is a single letter, following a <code>%</code> character, specifying information about what value the option requires:
+ *
+ * <table>
+ * <tr>
+ * <td><code>%f</code></td>
+ * <td>a floating point number</td>
+ * <tr>
+ * <td><code>%i</code></td>
+ * <td>an integer, in either decimal, hex (if preceeded by <code>0x</code>), or octal (if preceeded by <code>0</code>)</td>
+ * <tr valign=top>
+ * <td><code>%d</code></td>
+ * <td>a decimal integer</td>
+ * <tr valign=top>
+ * <td><code>%o</code></td>
+ * <td>an octal integer</td>
+ * <tr valign=top>
+ * <td><code>%h</code></td>
+ * <td>a hex integer (without the preceeding <code>0x</code>)</td>
+ * <tr valign=top>
+ * <td><code>%c</code></td>
+ * <td>a single character, including escape sequences (such as <code>\n</code> or <code>\007</code>), and optionally enclosed in single quotes
+ * <tr valign=top>
+ * <td><code>%b</code></td>
+ * <td>a boolean value (<code>true</code> or <code>false</code>)</td>
+ * <tr valign=top>
+ * <td><code>%s</code></td>
+ * <td>a string. This will be the argument string itself (or its remainder, in the case of a single word option)</td>
+ * <tr valign=top>
+ * <td><code>%v</code></td>
+ * <td>no explicit value is expected, but a boolean value of <code>true</code> (by default) will be stored into the associated result holder if this option is matched. If one wishes to have a value of <code>false</code> stored instead, then the <code>%v</code> should be followed by a "range spec" containing <code>false</code>, as in <code>%v{false}</code>.
+ * </table>
+ *
+ * <p>
+ * <li><var>rangeSpec</var> is an optional range specification, placed inside curly braces, consisting of a comma-separated list of range items each specifying permissible values for the option. A range item may be an individual value, or it may itself be a subrange, consisting of two individual values, separated by a comma, and enclosed in square or round brackets. Square and round brackets denote closed and open endpoints of a subrange, indicating that the associated endpoint value is
+ * included or excluded from the subrange. The values specified in the range spec need to be consistent with the type of value expected by the option.
+ *
+ * <p>
+ * <b>Examples:</b>
+ *
+ * <p>
+ * A range spec of <code>{2,4,8,16}</code> for an integer value will allow the integers 2, 4, 8, or 16.
+ *
+ * <p>
+ * A range spec of <code>{[-1.0,1.0]}</code> for a floating point value will allow any floating point number in the range -1.0 to 1.0.
+ *
+ * <p>
+ * A range spec of <code>{(-88,100],1000}</code> for an integer value will allow values > -88 and <= 100, as well as 1000.
+ *
+ * <p>
+ * A range spec of <code>{"foo", "bar", ["aaa","zzz")} </code> for a string value will allow strings equal to <code>"foo"</code> or <code>"bar"</code>, plus any string lexically greater than or equal to <code>"aaa"</code> but less then <code>"zzz"</code>.
+ *
+ * <p>
+ * <li><var>multiplier</var> is an optional integer, following a <code>X</code> character, indicating the number of values which the option expects. If the multiplier is not specified, it is assumed to be 1. If the multiplier value is greater than 1, then the result holder should be either an array (of appropriate type) with a length greater than or equal to the multiplier value, or a <code>java.util.Vector</code> <a href=#vectorHolder>as discussed below</a>.
+ *
+ * <p>
+ * <li><var>valueDescription</var> is an optional description of the option's value requirements, and consists of all characters between two <code>#</code> characters. The final <code>#</code> character initiates the <i>option description</i>, which may be empty. The value description is used in <a href=#helpInfo>generating help messages</a>.
+ *
+ * <p>
+ * <li><var>optionDescription</var> is an optional description of the option itself, consisting of all characters between a <code>#</code> character and the end of the specification string. The option description is used in <a href=#helpInfo>generating help messages</a>.
+ * </ul>
+ *
+ * <p>
+ * The result holder must be an object capable of holding a value compatible with the conversion code, or it must be a <code>java.util.Vector</code>. When the option is matched, its associated value is placed in the result holder. If the same option is matched repeatedly, the result holder value will be overwritten, unless the result holder is a <code>java.util.Vector</code>, in which case new holder objects for each match will be allocated and added to the vector. Thus if multiple instances
+ * of an option are desired by the program, the result holder should be a <code>java.util.Vector</code>.
+ *
+ * <p>
+ * If the result holder is not a <code>Vector</code>, then it must correspond as follows to the conversion code:
+ *
+ * <table>
+ * <tr valign=top>
+ * <td><code>%i</code>, <code>%d</code>, <code>%x</code>, <code>%o</code></td>
+ * <td>{@link argparser.IntHolder IntHolder}, {@link argparser.LongHolder LongHolder}, <code>int[]</code>, or <code>long[]</code></td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%f</code></td>
+ * <td>{@link argparser.FloatHolder FloatHolder}, {@link argparser.DoubleHolder DoubleHolder}, <code>float[]</code>, or <code>double[]</code></td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%b</code>, <code>%v</code></td>
+ * <td>{@link argparser.BooleanHolder BooleanHolder} or <code>boolean[]</code></td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%s</code></td>
+ * <td>{@link argparser.StringHolder StringHolder} or <code>String[]</code></td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%c</code></td>
+ * <td>{@link argparser.CharHolder CharHolder} or <code>char[]</code></td>
+ * </tr>
+ * </table>
+ *
+ * <p>
+ * In addition, if the multiplier is greater than 1, then only the array type indicated above may be used, and the array must be at least as long as the multiplier.
+ *
+ * <p>
+ * <a name=vectorHolder>If the result holder is a <code>Vector</code>, then the system will create an appropriate result holder object and add it to the vector. Multiple occurances of the option will cause multiple results to be added to the vector.
+ *
+ * <p>
+ * The object allocated by the system to store the result will correspond to the conversion code as follows:
+ *
+ * <table>
+ * <tr valign=top>
+ * <td><code>%i</code>, <code>%d</code>, <code>%x</code>, <code>%o</code></td>
+ * <td>{@link argparser.LongHolder LongHolder}, or <code>long[]</code> if the multiplier value exceeds 1</td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%f</code></td>
+ * <td>{@link argparser.DoubleHolder DoubleHolder}, or <code>double[]</code> if the multiplier value exceeds 1</td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%b</code>, <code>%v</code></td>
+ * <td>{@link argparser.BooleanHolder BooleanHolder}, or <code>boolean[]</code> if the multiplier value exceeds 1</td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%s</code></td>
+ * <td>{@link argparser.StringHolder StringHolder}, or <code>String[]</code> if the multiplier value exceeds 1</td>
+ * </tr>
+ *
+ * <tr valign=top>
+ * <td><code>%c</code></td>
+ * <td>{@link argparser.CharHolder CharHolder}, or <code>char[]</code> if the multiplier value exceeds 1</td>
+ * </tr>
+ * </table>
+ *
+ * @param spec the specification string
+ * @param resHolder object in which to store the associated
+ * value
+ * @throws IllegalArgumentException if there is an error in
+ * the specification or if the result holder is of an invalid
+ * type.
+ */
+ public void addOption(String spec, Object resHolder)
+ throws IllegalArgumentException {
+ // null terminated string is easier to parse
+ StringScanner scanner = new StringScanner(spec);
+ Record rec = null;
+ NameDesc nameTail = null;
+ NameDesc ndesc;
+ int i0, i1;
+ char c;
+
+ do {
+ ndesc = new NameDesc();
+ boolean nameEndsInWhiteSpace = false;
+
+ scanner.skipWhiteSpace();
+ i0 = scanner.getIndex();
+ while (!Character.isWhitespace(c = scanner.getc()) &&
+ c != ',' && c != '%' && c != '\000')
+ ;
+ i1 = scanner.getIndex();
+ if (c != '\000') {
+ i1--;
+ }
+ if (i0 == i1) { // then c is one of ',' '%' or '\000'
+ throw new IllegalArgumentException("Null option name given");
+ }
+ if (Character.isWhitespace(c)) {
+ nameEndsInWhiteSpace = true;
+ scanner.skipWhiteSpace();
+ c = scanner.getc();
+ }
+ if (c == '\000') {
+ throw new IllegalArgumentException("No conversion character given");
+ }
+ if (c != ',' && c != '%') {
+ throw new IllegalArgumentException("Names not separated by ','");
+ }
+ ndesc.name = scanner.substring(i0, i1);
+ if (rec == null) {
+ rec = new Record();
+ rec.nameList = ndesc;
+ } else {
+ nameTail.next = ndesc;
+ }
+ nameTail = ndesc;
+ ndesc.oneWord = !nameEndsInWhiteSpace;
+ } while (c != '%');
+
+ if (!nameTail.oneWord) {
+ for (ndesc = rec.nameList; ndesc != null; ndesc = ndesc.next) {
+ ndesc.oneWord = false;
+ }
+ }
+ c = scanner.getc();
+ if (c == '\000') {
+ throw new IllegalArgumentException("No conversion character given");
+ }
+ if (validConversionCodes.indexOf(c) == -1) {
+ throw new IllegalArgumentException("Conversion code '" + c + "' not one of '" +
+ validConversionCodes + "'");
+ }
+ rec.convertCode = c;
+
+ if (resHolder instanceof Vector) {
+ rec.vectorResult = true;
+ rec.type = defaultResultType(rec.convertCode);
+ } else {
+ switch (rec.convertCode) {
+ case 'i':
+ case 'o':
+ case 'd':
+ case 'x': {
+ if (resHolder instanceof LongHolder ||
+ resHolder instanceof long[]) {
+ rec.type = Record.LONG;
+ } else if (resHolder instanceof IntHolder ||
+ resHolder instanceof int[]) {
+ rec.type = Record.INT;
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid result holder for %" + c);
+ }
+ break;
+ }
+ case 'c': {
+ if (!(resHolder instanceof CharHolder) &&
+ !(resHolder instanceof char[])) {
+ throw new IllegalArgumentException(
+ "Invalid result holder for %c");
+ }
+ rec.type = Record.CHAR;
+ break;
+ }
+ case 'v':
+ case 'b': {
+ if (!(resHolder instanceof BooleanHolder) &&
+ !(resHolder instanceof boolean[])) {
+ throw new IllegalArgumentException(
+ "Invalid result holder for %" + c);
+ }
+ rec.type = Record.BOOLEAN;
+ break;
+ }
+ case 'f': {
+ if (resHolder instanceof DoubleHolder ||
+ resHolder instanceof double[]) {
+ rec.type = Record.DOUBLE;
+ } else if (resHolder instanceof FloatHolder ||
+ resHolder instanceof float[]) {
+ rec.type = Record.FLOAT;
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid result holder for %f");
+ }
+ break;
+ }
+ case 's': {
+ if (!(resHolder instanceof StringHolder) &&
+ !(resHolder instanceof String[])) {
+ throw new IllegalArgumentException(
+ "Invalid result holder for %s");
+ }
+ rec.type = Record.STRING;
+ break;
+ }
+ case 'h': { // resHolder is ignored for this type
+ break;
+ }
+ }
+ }
+ if (rec.convertCode == 'h') {
+ rec.resHolder = null;
+ } else {
+ rec.resHolder = resHolder;
+ }
+
+ scanner.skipWhiteSpace();
+ // get the range specification, if any
+ if (scanner.peekc() == '{') {
+ if (rec.convertCode == 'h') {
+ throw new IllegalArgumentException("Ranges not supported for %h");
+ }
+ // int bcnt = 0;
+ i0 = scanner.getIndex(); // beginning of range spec
+ do {
+ c = scanner.getc();
+ if (c == '\000') {
+ throw new IllegalArgumentException("Unterminated range specification");
+ }
+ // else if (c=='[' || c=='(')
+ // { bcnt++;
+ // }
+ // else if (c==']' || c==')')
+ // { bcnt--;
+ // }
+ // if ((rec.convertCode=='v'||rec.convertCode=='b') && bcnt>1)
+ // { throw new IllegalArgumentException
+ // ("Sub ranges not supported for %b or %v");
+ // }
+ } while (c != '}');
+ // if (c != ']')
+ // { throw new IllegalArgumentException
+ // ("Range specification must end with ']'");
+ // }
+ i1 = scanner.getIndex(); // end of range spec
+ scanRangeSpec(rec, scanner.substring(i0, i1));
+ if (rec.convertCode == 'v' && rec.rangeList != null) {
+ rec.vval = rec.rangeList.low.bval;
+ }
+ }
+ // check for value multiplicity information, if any
+ if (scanner.peekc() == 'X') {
+ if (rec.convertCode == 'h') {
+ throw new IllegalArgumentException("Multipliers not supported for %h");
+ }
+ scanner.getc();
+ try {
+ rec.numValues = (int) scanner.scanInt();
+ } catch (StringScanException e) {
+ throw new IllegalArgumentException("Malformed value multiplier");
+ }
+ if (rec.numValues <= 0) {
+ throw new IllegalArgumentException("Value multiplier number must be > 0");
+ }
+ } else {
+ rec.numValues = 1;
+ }
+ if (rec.numValues > 1) {
+ for (ndesc = rec.nameList; ndesc != null; ndesc = ndesc.next) {
+ if (ndesc.oneWord) {
+ throw new IllegalArgumentException(
+ "Multiplier value incompatible with one word option " + ndesc.name);
+ }
+ }
+ }
+ if (resHolder != null && resHolder.getClass().isArray()) {
+ if (Array.getLength(resHolder) < rec.numValues) {
+ throw new IllegalArgumentException(
+ "Result holder array must have a length >= " + rec.numValues);
+ }
+ } else {
+ if (rec.numValues > 1 && !(resHolder instanceof Vector)) {
+ throw new IllegalArgumentException(
+ "Multiplier requires result holder to be an array of length >= "
+ + rec.numValues);
+ }
+ }
+
+ // skip white space following conversion information
+ scanner.skipWhiteSpace();
+
+ // get the help message, if any
+
+ if (!scanner.atEnd()) {
+ if (scanner.getc() != '#') {
+ throw new IllegalArgumentException("Illegal character(s), expecting '#'");
+ }
+ String helpInfo = scanner.substring(scanner.getIndex());
+ // look for second '#'. If there is one, then info
+ // between the first and second '#' is the value descriptor.
+ int k = helpInfo.indexOf("#");
+ if (k != -1) {
+ rec.valueDesc = helpInfo.substring(0, k);
+ rec.helpMsg = helpInfo.substring(k + 1);
+ } else {
+ rec.helpMsg = helpInfo;
+ }
+ } else {
+ rec.helpMsg = "";
+ }
+
+ // parse helpMsg for required/optional information if present
+ // default to required
+ if (rec.helpMsg.indexOf("(optional") != -1) {
+ rec.required = false;
+ }
+
+ // add option information to match list
+ if (rec.convertCode == 'h' && firstHelpOption == defaultHelpOption) {
+ matchList.remove(defaultHelpOption);
+ firstHelpOption = rec;
+ }
+ matchList.add(rec);
+ }
+
+ Record lastMatchRecord() {
+ return (Record) matchList.lastElement();
+ }
+
+ private Record getRecord(String arg, ObjectHolder ndescHolder) {
+ NameDesc ndesc;
+ for (int i = 0; i < matchList.size(); i++) {
+ Record rec = (Record) matchList.get(i);
+ for (ndesc = rec.nameList; ndesc != null; ndesc = ndesc.next) {
+ if (rec.convertCode != 'v' && ndesc.oneWord) {
+ if (arg.startsWith(ndesc.name)) {
+ if (ndescHolder != null) {
+ ndescHolder.value = ndesc;
+ }
+ return rec;
+ }
+ } else {
+ if (arg.equals(ndesc.name)) {
+ if (ndescHolder != null) {
+ ndescHolder.value = ndesc;
+ }
+ return rec;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public void checkRequiredArgs() {
+ for (int i = 1; i < matchList.size(); i++) {
+ Record rec = (Record) matchList.get(i);
+ StringHolder myString = (StringHolder) rec.resHolder;
+ if (((myString.value == null) || (myString.value.equals(""))) && (rec.required)) {
+ printErrorAndExit("Required parameter " + rec.nameList.name + " is not specified.");
+ }
+ }
+ }
+
+ Object getResultHolder(String arg) {
+ Record rec = getRecord(arg, null);
+ return (rec != null) ? rec.resHolder : null;
+ }
+
+ String getOptionName(String arg) {
+ ObjectHolder ndescHolder = new ObjectHolder();
+ Record rec = getRecord(arg, ndescHolder);
+ return (rec != null) ? ((NameDesc) ndescHolder.value).name : null;
+ }
+
+ String getOptionRangeDesc(String arg) {
+ Record rec = getRecord(arg, null);
+ return (rec != null) ? rec.rangeDesc : null;
+ }
+
+ String getOptionTypeName(String arg) {
+ Record rec = getRecord(arg, null);
+ return (rec != null) ? rec.valTypeName() : null;
+ }
+
+ private Object createResultHolder(Record rec) {
+ if (rec.numValues == 1) {
+ switch (rec.type) {
+ case Record.LONG: {
+ return new LongHolder();
+ }
+ case Record.CHAR: {
+ return new CharHolder();
+ }
+ case Record.BOOLEAN: {
+ return new BooleanHolder();
+ }
+ case Record.DOUBLE: {
+ return new DoubleHolder();
+ }
+ case Record.STRING: {
+ return new StringHolder();
+ }
+ }
+ } else {
+ switch (rec.type) {
+ case Record.LONG: {
+ return new long[rec.numValues];
+ }
+ case Record.CHAR: {
+ return new char[rec.numValues];
+ }
+ case Record.BOOLEAN: {
+ return new boolean[rec.numValues];
+ }
+ case Record.DOUBLE: {
+ return new double[rec.numValues];
+ }
+ case Record.STRING: {
+ return new String[rec.numValues];
+ }
+ }
+ }
+ return null; // can't happen
+ }
+
+ static void stringToArgs(Vector<String> vec, String s,
+ boolean allowQuotedStrings)
+ throws StringScanException {
+ StringScanner scanner = new StringScanner(s);
+ scanner.skipWhiteSpace();
+ while (!scanner.atEnd()) {
+ if (allowQuotedStrings) {
+ vec.add(scanner.scanString());
+ } else {
+ vec.add(scanner.scanNonWhiteSpaceString());
+ }
+ scanner.skipWhiteSpace();
+ }
+ }
+
+ /**
+ * Reads in a set of strings from a reader and prepends them to an
+ * argument list. Strings are delimited by either whitespace or
+ * double quotes <code>"</code>. The character <code>#</code> acts as
+ * a comment character, causing input to the end of the current line to
+ * be ignored.
+ *
+ * @param reader Reader from which to read the strings
+ * @param args Initial set of argument values. Can be
+ * specified as <code>null</code>.
+ * @throws IOException if an error occured while reading.
+ */
+ public static String[] prependArgs(Reader reader, String[] args)
+ throws IOException {
+ if (args == null) {
+ args = new String[0];
+ }
+ LineNumberReader lineReader = new LineNumberReader(reader);
+ Vector<String> vec = new Vector<String>(100, 100);
+ String line;
+ int i, k;
+
+ while ((line = lineReader.readLine()) != null) {
+ int commentIdx = line.indexOf("#");
+ if (commentIdx != -1) {
+ line = line.substring(0, commentIdx);
+ }
+ try {
+ stringToArgs(vec, line, /*allowQuotedStings=*/true);
+ } catch (StringScanException e) {
+ throw new IOException(
+ "malformed string, line " + lineReader.getLineNumber());
+ }
+ }
+ String[] result = new String[vec.size() + args.length];
+ for (i = 0; i < vec.size(); i++) {
+ result[i] = (String) vec.get(i);
+ }
+ for (k = 0; k < args.length; k++) {
+ result[i++] = args[k];
+ }
+ return result;
+ }
+
+ /**
+ * Reads in a set of strings from a file and prepends them to an
+ * argument list. Strings are delimited by either whitespace or double
+ * quotes <code>"</code>. The character <code>#</code> acts as a
+ * comment character, causing input to the end of the current line to
+ * be ignored.
+ *
+ * @param file File to be read
+ * @param args Initial set of argument values. Can be
+ * specified as <code>null</code>.
+ * @throws IOException if an error occured while reading the file.
+ */
+ public static String[] prependArgs(File file, String[] args)
+ throws IOException {
+ if (args == null) {
+ args = new String[0];
+ }
+ if (!file.canRead()) {
+ return args;
+ }
+ try {
+ return prependArgs(new FileReader(file), args);
+ } catch (IOException e) {
+ throw new IOException(
+ "File " + file.getName() + ": " + e.getMessage());
+ }
+ }
+
+ /**
+ * Sets the parser's error message.
+ *
+ * @param s Error message
+ */
+ protected void setError(String msg) {
+ errMsg = msg;
+ }
+
+ /**
+ * Prints an error message, along with a pointer to help options,
+ * if available, and causes the program to exit with code 1.
+ */
+ public void printErrorAndExit(String msg) {
+ if (helpOptionsEnabled && firstHelpOptionName() != null) {
+ msg += "\nUse " + firstHelpOptionName() + " for help information";
+ }
+ if (printStream != null) {
+ printStream.println(msg);
+ }
+ System.exit(1);
+ }
+
+ /**
+ * Matches arguments within an argument list.
+ *
+ * <p>
+ * In the event of an erroneous or unmatched argument, the method prints a message and exits the program with code 1.
+ *
+ * <p>
+ * If help options are enabled and one of the arguments matches a help option, then the result of {@link #getHelpMessage
+ * getHelpMessage} is printed to the default print stream and the program exits with code 0. If help options are not enabled, they are ignored.
+ *
+ * @param args argument list
+ * @see ArgParser#getDefaultPrintStream
+ */
+ public void matchAllArgs(String[] args) {
+ matchAllArgs(args, 0, EXIT_ON_UNMATCHED | EXIT_ON_ERROR);
+ }
+
+ /**
+ * Matches arguments within an argument list and returns
+ * those which were not matched. The matching starts at a location
+ * in <code>args</code> specified by <code>idx</code>, and
+ * unmatched arguments are returned in a String array.
+ *
+ * <p>
+ * In the event of an erroneous argument, the method either prints a message and exits the program (if {@link #EXIT_ON_ERROR} is set in <code>exitFlags</code>) or terminates the matching and creates a error message that can be retrieved by {@link #getErrorMessage}.
+ *
+ * <p>
+ * In the event of an umatched argument, the method will print a message and exit if {@link #EXIT_ON_UNMATCHED} is set in <code>errorFlags</code>. Otherwise, the unmatched argument will be appended to the returned array of unmatched values, and the matching will continue at the next location.
+ *
+ * <p>
+ * If help options are enabled and one of the arguments matches a help option, then the result of {@link #getHelpMessage
+ * getHelpMessage} is printed to the the default print stream and the program exits with code 0. If help options are not enabled, then they will not be matched.
+ *
+ * @param args argument list
+ * @param idx starting location in list
+ * @param exitFlags conditions causing the program to exit. Should be
+ * an or-ed combintion of {@link #EXIT_ON_ERROR} or {@link #EXIT_ON_UNMATCHED}.
+ * @return array of arguments that were not matched, or <code>null</code> if all arguments were successfully matched
+ * @see ArgParser#getErrorMessage
+ * @see ArgParser#getDefaultPrintStream
+ */
+ public String[] matchAllArgs(String[] args, int idx, int exitFlags) {
+ Vector<String> unmatched = new Vector<String>(10);
+
+ while (idx < args.length) {
+ try {
+ idx = matchArg(args, idx);
+ if (unmatchedArg != null) {
+ if ((exitFlags & EXIT_ON_UNMATCHED) != 0) {
+ printErrorAndExit("Unrecognized argument: " + unmatchedArg);
+ } else {
+ unmatched.add(unmatchedArg);
+ }
+ }
+ } catch (ArgParseException e) {
+ if ((exitFlags & EXIT_ON_ERROR) != 0) {
+ printErrorAndExit(e.getMessage());
+ }
+ break;
+ }
+ }
+ if (unmatched.size() == 0) {
+ return null;
+ } else {
+ return (String[]) unmatched.toArray(new String[0]);
+ }
+ }
+
+ /**
+ * Matches one option starting at a specified location in an argument
+ * list. The method returns the location in the list where the next
+ * match should begin.
+ *
+ * <p>
+ * In the event of an erroneous argument, the method throws an {@link argparser.ArgParseException ArgParseException} with an appropriate error message. This error message can also be retrieved using {@link #getErrorMessage getErrorMessage}.
+ *
+ * <p>
+ * In the event of an umatched argument, the method will return idx + 1, and {@link #getUnmatchedArgument getUnmatchedArgument} will return a copy of the unmatched argument. If an argument is matched, {@link #getUnmatchedArgument getUnmatchedArgument} will return <code>null</code>.
+ *
+ * <p>
+ * If help options are enabled and the argument matches a help option, then the result of {@link #getHelpMessage getHelpMessage} is printed to the the default print stream and the program exits with code 0. If help options are not enabled, then they are ignored.
+ *
+ * @param args argument list
+ * @param idx location in list where match should start
+ * @return location in list where next match should start
+ * @throws ArgParseException if there was an error performing
+ * the match (such as improper or insufficient values).
+ * @see ArgParser#setDefaultPrintStream
+ * @see ArgParser#getHelpOptionsEnabled
+ * @see ArgParser#getErrorMessage
+ * @see ArgParser#getUnmatchedArgument
+ */
+ @SuppressWarnings("unchecked")
+ public int matchArg(String[] args, int idx)
+ throws ArgParseException {
+ unmatchedArg = null;
+ setError(null);
+ try {
+ ObjectHolder ndescHolder = new ObjectHolder();
+ Record rec = getRecord(args[idx], ndescHolder);
+ if (rec == null || (rec.convertCode == 'h' && !helpOptionsEnabled)) { // didn't match
+ unmatchedArg = new String(args[idx]);
+ return idx + 1;
+ }
+ NameDesc ndesc = (NameDesc) ndescHolder.value;
+ Object result;
+ if (rec.resHolder instanceof Vector) {
+ result = createResultHolder(rec);
+ } else {
+ result = rec.resHolder;
+ }
+ if (rec.convertCode == 'h') {
+ if (helpOptionsEnabled) {
+ printStream.println(getHelpMessage());
+ System.exit(0);
+ } else {
+ return idx + 1;
+ }
+ } else if (rec.convertCode != 'v') {
+ if (ndesc.oneWord) {
+ rec.scanValue(
+ result, ndesc.name,
+ args[idx].substring(ndesc.name.length()), 0);
+ } else {
+ if (idx + rec.numValues >= args.length) {
+ throw new ArgParseException(
+ ndesc.name, "requires " + rec.numValues + " value" +
+ (rec.numValues > 1 ? "s" : ""));
+ }
+ for (int k = 0; k < rec.numValues; k++) {
+ rec.scanValue(result, ndesc.name, args[++idx], k);
+ }
+ }
+ } else {
+ if (rec.resHolder instanceof BooleanHolder) {
+ ((BooleanHolder) result).value = rec.vval;
+ } else {
+ for (int k = 0; k < rec.numValues; k++) {
+ ((boolean[]) result)[k] = rec.vval;
+ }
+ }
+ }
+ if (rec.resHolder instanceof Vector) {
+ ((Vector<Object>) rec.resHolder).add(result);
+ }
+ } catch (ArgParseException e) {
+ setError(e.getMessage());
+ throw e;
+ }
+ return idx + 1;
+ }
+
+ private String spaceString(int n) {
+ StringBuffer sbuf = new StringBuffer(n);
+ for (int i = 0; i < n; i++) {
+ sbuf.append(' ');
+ }
+ return sbuf.toString();
+ }
+
+ // public String getShortHelpMessage ()
+ // {
+ // String s;
+ // Record rec;
+ // NameDesc ndesc;
+ // int initialIndent = 8;
+ // int col = initialIndent;
+
+ // if (maxcols <= 0)
+ // { maxcols = 80;
+ // }
+ // if (matchList.size() > 0)
+ // { ps.print (spaceString(initialIndent));
+ // }
+ // for (int i=0; i<matchList.size(); i++)
+ // { rec = (Record)matchList.get(i);
+ // s = "[";
+ // for (ndesc=rec.nameList; ndesc!=null; ndesc=ndesc.next)
+ // { s = s + ndesc.name;
+ // if (ndesc.oneWord == false)
+ // { s = s + " ";
+ // }
+ // if (ndesc.next != null)
+ // { s = s + ",";
+ // }
+ // }
+ // if (rec.convertCode != 'v' && rec.convertCode != 'h')
+ // { if (rec.valueDesc != null)
+ // { s += rec.valueDesc;
+ // }
+ // else
+ // { s = s + "<" + rec.valTypeName() + ">";
+ // if (rec.numValues > 1)
+ // { s += "X" + rec.numValues;
+ // }
+ // }
+ // }
+ // s = s + "]";
+ // /*
+ // (col+=s.length()) > (maxcols-1) => we will spill over edge.
+ // we use (maxcols-1) because if we go right to the edge
+ // (maxcols), we get wrap new line inserted "for us".
+ // i != 0 means we print the first entry, no matter
+ // how long it is. Subsequent entries are printed
+ // full length anyway. */
+
+ // if ((col+=s.length()) > (maxcols-1) && i != 0)
+ // { col = initialIndent+s.length();
+ // ps.print ("\n" + spaceString(initialIndent));
+ // }
+ // ps.print (s);
+ // }
+ // if (matchList.size() > 0)
+ // { ps.print ('\n');
+ // ps.flush();
+ // }
+ // }
+
+ /**
+ * Returns a string describing the allowed options
+ * in detail.
+ *
+ * @return help information string.
+ */
+ public String getHelpMessage() {
+ Record rec;
+ NameDesc ndesc;
+ boolean hasOneWordAlias = false;
+ String s;
+
+ s = "Usage: " + synopsisString + "\n";
+ s += "Options include:\n\n";
+ for (int i = 0; i < matchList.size(); i++) {
+ String optionInfo = "";
+ rec = (Record) matchList.get(i);
+ if (rec.convertCode == 'h' && !helpOptionsEnabled) {
+ continue;
+ }
+ for (ndesc = rec.nameList; ndesc != null; ndesc = ndesc.next) {
+ if (ndesc.oneWord) {
+ hasOneWordAlias = true;
+ break;
+ }
+ }
+ for (ndesc = rec.nameList; ndesc != null; ndesc = ndesc.next) {
+ optionInfo += ndesc.name;
+ if (hasOneWordAlias && !ndesc.oneWord) {
+ optionInfo += " ";
+ }
+ if (ndesc.next != null) {
+ optionInfo += ",";
+ }
+ }
+ if (!hasOneWordAlias) {
+ optionInfo += " ";
+ }
+ if (rec.convertCode != 'v' && rec.convertCode != 'h') {
+ if (rec.valueDesc != null) {
+ optionInfo += rec.valueDesc;
+ } else {
+ if (rec.rangeDesc != null) {
+ optionInfo += "<" + rec.valTypeName() + " "
+ + rec.rangeDesc + ">";
+ } else {
+ optionInfo += "<" + rec.valTypeName() + ">";
+ }
+ }
+ }
+ if (rec.numValues > 1) {
+ optionInfo += "X" + rec.numValues;
+ }
+ s += optionInfo;
+ if (rec.helpMsg.length() > 0) {
+ int pad = helpIndent - optionInfo.length();
+ if (pad < 2) { //s += '\n';
+ pad = helpIndent;
+ }
+ // s += spaceString(pad) + rec.helpMsg;
+ s += spaceString(4) + rec.helpMsg;
+ }
+ s += '\n';
+ }
+ return s;
+ }
+
+ /**
+ * Returns the parser's error message. This is automatically
+ * set whenever an error is encountered in <code>matchArg</code> or <code>matchAllArgs</code>, and is automatically set to <code>null</code> at the beginning of these methods.
+ *
+ * @return error message
+ */
+ public String getErrorMessage() {
+ return errMsg;
+ }
+
+ /**
+ * Returns the value of an unmatched argument discovered {@link #matchArg matchArg} or {@link #matchAllArgs(String[],int,int)
+ * matchAllArgs}. If there was no unmatched argument, <code>null</code> is returned.
+ *
+ * @return unmatched argument
+ */
+ public String getUnmatchedArgument() {
+ return unmatchedArg;
+ }
+}
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParserTest.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParserTest.java
index 579f0f59..4a7b20e4 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParserTest.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParserTest.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,17 +19,17 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Copyright John E. Lloyd, 2004. All rights reserved. Permission to use,
- * copy, modify and redistribute is granted, provided that this copyright
- * notice is retained and the author is given credit whenever appropriate.
- *
- * This software is distributed "as is", without any warranty, including
- * any implied warranty of merchantability or fitness for a particular
- * use. The author assumes no responsibility for, and shall not be liable
- * for, any special, indirect, or consequential damages, or any damages
- * whatsoever, arising out of or in connection with the use of this
- * software.
- */
+ * Copyright John E. Lloyd, 2004. All rights reserved. Permission to use,
+ * copy, modify and redistribute is granted, provided that this copyright
+ * notice is retained and the author is given credit whenever appropriate.
+ *
+ * This software is distributed "as is", without any warranty, including
+ * any implied warranty of merchantability or fitness for a particular
+ * use. The author assumes no responsibility for, and shall not be liable
+ * for, any special, indirect, or consequential damages, or any damages
+ * whatsoever, arising out of or in connection with the use of this
+ * software.
+ */
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
@@ -36,1537 +37,1477 @@ import java.lang.reflect.Array;
import java.util.Vector;
/**
- * Testing class for the class ArgParser. Executing the <code>main</code>
- * method of this class will perform a suite of tests to help verify correct
+ * Testing class for the class ArgParser. Executing the <code>main</code> method of this class will perform a suite of tests to help verify correct
* operation of the parser class.
- *
+ *
* @author John E. Lloyd, Fall 2004
* @see ArgParser
*/
-public class ArgParserTest
-{
- ArgParser parser;
-
- static final boolean CLOSED = true;
- static final boolean OPEN = false;
-
- static final boolean ONE_WORD = true;
- static final boolean MULTI_WORD = false;
-
- private static void verify (boolean ok, String msg)
- { if (!ok)
- { Throwable e = new Throwable();
- System.out.println ("Verification failed:" + msg);
- e.printStackTrace();
- System.exit(1);
- }
- }
-
- private static String[] argsFromString (String s)
- {
- Vector<String> vec = new Vector<String>(100);
- try
- { ArgParser.stringToArgs (vec, s, /*allowQuotedStings=*/false);
- }
- catch (StringScanException e)
- { e.printStackTrace();
- System.exit (1);
- }
- String[] result = new String[vec.size()];
- for (int i=0; i<vec.size(); i++)
- { result[i] = (String)vec.get(i);
- }
- return result;
- }
-
- static class RngCheck
- {
- ArgParser.RangePnt low = null;
- ArgParser.RangePnt high = null;
- int type;
-
- RngCheck (String s)
- { low = new ArgParser.RangePnt (s, CLOSED);
- type = 's';
- }
-
- RngCheck (double d)
- { low = new ArgParser.RangePnt (d, CLOSED);
- type = 'd';
- }
-
- RngCheck (long l)
- { low = new ArgParser.RangePnt (l, CLOSED);
- type = 'l';
- }
-
- RngCheck (boolean b)
- { low = new ArgParser.RangePnt (b, CLOSED);
- type = 'b';
- }
-
- RngCheck (String s1, boolean c1, String s2, boolean c2)
- { low = new ArgParser.RangePnt (s1, c1);
- high = new ArgParser.RangePnt (s2, c2);
- type = 's';
- }
-
- RngCheck (double d1, boolean c1, double d2, boolean c2)
- { low = new ArgParser.RangePnt (d1, c1);
- high = new ArgParser.RangePnt (d2, c2);
- type = 'd';
- }
-
- RngCheck (long l1, boolean c1, long l2, boolean c2)
- { low = new ArgParser.RangePnt (l1, c1);
- high = new ArgParser.RangePnt (l2, c2);
- type = 'l';
- }
-
- void check (ArgParser.RangeAtom ra)
- {
- verify ((ra.low==null) == (low==null),
- "(ra.low==null)=" + (ra.low==null) +
- "(low==null)=" + (low==null));
- verify ((ra.high==null) == (high==null),
- "(ra.high==null)=" + (ra.high==null) +
- "(high==null)=" + (high==null));
-
- if (ra.low != null)
- { switch (type)
- { case 'l':
- { verify (ra.low.lval==low.lval,
- "ra.low=" + ra.low + " low=" + low);
- break;
- }
- case 'd':
- { verify (ra.low.dval==low.dval,
- "ra.low=" + ra.low + " low=" + low);
- break;
- }
- case 's':
- { verify (ra.low.sval.equals (low.sval),
- "ra.low=" + ra.low + " low=" + low);
- break;
- }
- case 'b':
- { verify (ra.low.bval==low.bval,
- "ra.low=" + ra.low + " low=" + low);
- break;
- }
- }
- verify (ra.low.closed==low.closed,
- "ra.low=" + ra.low + " low=" + low);
- }
- if (ra.high != null)
- { switch (type)
- { case 'l':
- { verify (ra.high.lval==high.lval,
- "ra.high=" + ra.high + " high=" + high);
- break;
- }
- case 'd':
- { verify (ra.high.dval==high.dval,
- "ra.high=" + ra.high + " high=" + high);
- break;
- }
- case 's':
- { verify (ra.high.sval.equals (high.sval),
- "ra.high=" + ra.high + " high=" + high);
- break;
- }
- case 'b':
- { verify (ra.high.bval==high.bval,
- "ra.high=" + ra.high + " high=" + high);
- break;
- }
- }
- verify (ra.high.closed==high.closed,
- "ra.high=" + ra.high + " high=" + high);
- }
- }
- }
-
- ArgParserTest ()
- { parser = new ArgParser("fubar");
- }
-
- static void checkException (Exception e, String errmsg)
- { if (errmsg != null)
- { if (!e.getMessage().equals(errmsg))
- { System.out.println (
-"Expecting exception '" + errmsg + "' but got '" +
- e.getMessage() + "'");
- e.printStackTrace();
- (new Throwable()).printStackTrace();
- System.exit(1);
- }
- }
- else
- { System.out.println (
-"Unexpected exception '" + e.getMessage() + "'");
- e.printStackTrace();
- (new Throwable()).printStackTrace();
- System.exit(1);
- }
- }
-
- void checkPrintHelp (String msg)
- {
- ByteArrayOutputStream buf = new ByteArrayOutputStream(0x10000);
- PrintStream ps = new PrintStream(buf);
- ps.println (parser.getHelpMessage());
- System.out.print (buf.toString());
- }
-
-// void checkGetSynopsis (String msg)
-// {
-// ByteArrayOutputStream buf = new ByteArrayOutputStream(0x10000);
-// PrintStream ps = new PrintStream(buf);
-// parser.printSynopsis (ps, 80);
-// System.out.print (buf.toString());
-// }
-
- void checkAdd (String s, Object resHolder, String errmsg)
- {
- checkAdd (s, resHolder, 0, 0, null, null, null, errmsg);
- }
-
- void add (String s, Object resHolder)
- { try
- { parser.addOption (s, resHolder);
- }
- catch (Exception e)
- { e.printStackTrace();
- System.exit (1);
- }
- }
-
- void checkStringArray (String msg, String[] strs, String[] check)
- {
- boolean dontMatch = false;
- if (strs.length != check.length)
- { dontMatch = true;
- }
- else
- { for (int i=0; i<strs.length; i++)
- { if (!strs[i].equals (check[i]))
- { dontMatch = true;
- break;
- }
- }
- }
- if (dontMatch)
- { System.out.println (msg);
- System.out.print ("Expected: ");
- for (int i=0; i<check.length; i++)
- { System.out.print ("'" + check[i] + "'");
- if (i<check.length-1)
- { System.out.print (" ");
- }
- }
- System.out.println ("");
- System.out.print ("Got: ");
- for (int i=0; i<strs.length; i++)
- { System.out.print ("'" + strs[i] + "'");
- if (i<strs.length-1)
- { System.out.print (" ");
- }
- }
- System.out.println ("");
- System.exit(1);
- }
- }
-
- void checkAdd (String s, Object resHolder, int code, int numValues,
- Object names, RngCheck[] rngCheck,
- String helpMsg, String errmsg)
- {
- boolean exceptionThrown = false;
- String[] namelist = null;
- try
- { parser.addOption (s, resHolder);
- }
- catch (Exception e)
- { exceptionThrown = true;
- checkException (e, errmsg);
- }
- if (names instanceof String)
- { namelist = new String[] { (String)names };
- }
- else
- { namelist = (String[])names;
- }
- if (!exceptionThrown)
- { verify (errmsg == null,
- "Expecting exception " + errmsg);
- ArgParser.Record rec = parser.lastMatchRecord();
- verify (rec.convertCode==code,
- "code=" + rec.convertCode + ", expecting " + code);
- ArgParser.NameDesc nd;
- int i=0;
- for (nd=rec.firstNameDesc(); nd!=null; nd=nd.next)
- { i++;
- }
- verify (i==namelist.length,
- "numNames=" + i + ", expecting " +namelist.length);
- i=0;
- for (nd=rec.firstNameDesc(); nd!=null; nd=nd.next)
- { String ss;
- if (!nd.oneWord)
- { ss = new String(nd.name) + ' ';
- }
- else
- { ss = nd.name;
- }
- verify (ss.equals(namelist[i]),
- "have name '"+ss+"', expecting '"+namelist[i]+"'");
- i++;
- }
- ArgParser.RangeAtom ra;
- i=0;
- for (ra=rec.firstRangeAtom(); ra!=null; ra=ra.next)
- { i++;
- }
- int expectedRangeNum = 0;
- if (rngCheck!=null)
- { expectedRangeNum = rngCheck.length;
- }
- verify (i==expectedRangeNum,
- "numRangeAtoms="+i+", expecting "+expectedRangeNum);
- i=0;
- for (ra=rec.firstRangeAtom(); ra!=null; ra=ra.next)
- { rngCheck[i++].check(ra);
- }
- verify (rec.helpMsg.equals(helpMsg),
- "helpMsg="+rec.helpMsg+", expecting "+helpMsg);
- verify (rec.numValues==numValues,
- "numValues="+rec.numValues+", expecting "+numValues);
- }
- }
-
- double getDoubleValue (Object obj, int k)
- {
- if (obj instanceof DoubleHolder)
- { return ((DoubleHolder)obj).value;
- }
- else if (obj instanceof FloatHolder)
- { return ((FloatHolder)obj).value;
- }
- else if (obj instanceof double[])
- { return ((double[])obj)[k];
- }
- else if (obj instanceof float[])
- { return ((float[])obj)[k];
- }
- else
- { verify (false, "object doesn't contain double values");
- return 0;
- }
- }
-
- long getLongValue (Object obj, int k)
- {
- if (obj instanceof LongHolder)
- { return ((LongHolder)obj).value;
- }
- else if (obj instanceof IntHolder)
- { return ((IntHolder)obj).value;
- }
- else if (obj instanceof long[])
- { return ((long[])obj)[k];
- }
- else if (obj instanceof int[])
- { return ((int[])obj)[k];
- }
- else
- { verify (false, "object doesn't contain long values");
- return 0;
- }
- }
-
- String getStringValue (Object obj, int k)
- {
- if (obj instanceof StringHolder)
- { return ((StringHolder)obj).value;
- }
- else if (obj instanceof String[])
- { return ((String[])obj)[k];
- }
- else
- { verify (false, "object doesn't contain String values");
- return null;
- }
- }
-
- boolean getBooleanValue (Object obj, int k)
- {
- if (obj instanceof BooleanHolder)
- { return ((BooleanHolder)obj).value;
- }
- else if (obj instanceof boolean[])
- { return ((boolean[])obj)[k];
- }
- else
- { verify (false, "object doesn't contain boolean values");
- return false;
- }
- }
-
- char getCharValue (Object obj, int k)
- {
- if (obj instanceof CharHolder)
- { return ((CharHolder)obj).value;
- }
- else if (obj instanceof char[])
- { return ((char[])obj)[k];
- }
- else
- { verify (false, "object doesn't contain char values");
- return 0;
- }
- }
-
- static class MErr
- {
- int code;
- String valStr;
-
- MErr (int code, String valStr)
- { this.code = code;
- this.valStr = valStr;
- }
- }
-
- static class MTest
- {
- String args;
- Object result;
- int resultIdx;
-
- MTest (String args, Object result)
- { this (args, result, -1);
- }
-
- MTest (String args, Object result, int resultIdx)
- { this.args = args;
- this.result = result;
- this.resultIdx = resultIdx;
- }
- };
-
- void checkMatch (String args[], int idx, String errMsg)
- { getMatchResult (args, idx, -1, errMsg, -1);
- }
-
- void checkMatch (String args[], int idx, int cnt,
- long check, int resultIdx)
- { Object rholder = getMatchResult (args, idx, cnt, null, resultIdx);
- long result = getLongValue(rholder,0);
- verify (result==check, "result " + result + " vs. " + check);
- }
-
- void checkMatch (String args[], int idx, int cnt,
- double check, int resultIdx)
- { Object rholder = getMatchResult (args, idx, cnt, null, resultIdx);
- double result = getDoubleValue(rholder,0);
- verify (result==check, "result " + result + " vs. " + check);
- }
-
- void checkMatch (String args[], int idx, int cnt,
- String check, int resultIdx)
- { Object rholder = getMatchResult (args, idx, cnt, null, resultIdx);
- String result = getStringValue(rholder,0);
- verify (result.equals(check), "result " + result + " vs. " + check);
- }
-
- void checkMatch (String args[], int idx, int cnt,
- boolean check, int resultIdx)
- { Object rholder = getMatchResult (args, idx, cnt, null, resultIdx);
- boolean result = getBooleanValue(rholder,0);
- verify (result==check, "result " + result + " vs. " + check);
- }
-
- void checkMatch (String args[], int idx, int cnt,
- char check, int resultIdx)
- { Object rholder = getMatchResult (args, idx, cnt, null, resultIdx);
- char result = getCharValue(rholder,0);
- verify (result==check, "result " + result + " vs. " + check);
- }
-
- void checkMatch (String args[], int idx, int cnt,
- Object checkArray, int resultIdx)
- { Object rholder = getMatchResult (args, idx, cnt, null, resultIdx);
- if (!checkArray.getClass().isArray())
- { verify (false, "check is not an array");
- }
- for (int i=0; i<Array.getLength(checkArray); i++)
- { if (checkArray instanceof long[])
- { long result = getLongValue(rholder,i);
- long check = ((long[])checkArray)[i];
- verify (result==check,
- "result ["+i+"] " + result + " vs. " + check);
- }
- else if (checkArray instanceof double[])
- { double result = getDoubleValue(rholder,i);
- double check = ((double[])checkArray)[i];
- verify (result==check,
- "result ["+i+"] " + result + " vs. " + check);
- }
- else if (checkArray instanceof String[])
- { String result = getStringValue(rholder,i);
- String check = ((String[])checkArray)[i];
- verify (result.equals(check),
- "result ["+i+"] " + result + " vs. " + check);
- }
- else if (checkArray instanceof boolean[])
- { boolean result = getBooleanValue(rholder,i);
- boolean check = ((boolean[])checkArray)[i];
- verify (result==check,
- "result ["+i+"] " + result + " vs. " + check);
- }
- else if (checkArray instanceof char[])
- { char result = getCharValue(rholder,i);
- char check = ((char[])checkArray)[i];
- verify (result==check,
- "result ["+i+"] " + result + " vs. " + check);
- }
- else
- { verify (false, "unknown type for checkArray");
- }
- }
- }
-
- void checkMatch (MTest test, boolean oneWord)
- { String[] argv;
- if (oneWord)
- { argv = new String[1];
- argv[0] = test.args;
- }
- else
- { argv = argsFromString(test.args);
- }
- if (test.result instanceof Long)
- { checkMatch (argv, 0, argv.length,
- ((Long)test.result).longValue(),
- test.resultIdx);
- }
- else if (test.result instanceof Double)
- { checkMatch (argv, 0, argv.length,
- ((Double)test.result).doubleValue(),
- test.resultIdx);
- }
- else if (test.result instanceof String)
- { checkMatch (argv, 0, argv.length,
- (String)test.result,
- test.resultIdx);
- }
- else if (test.result instanceof Boolean)
- { checkMatch (argv, 0, argv.length,
- ((Boolean)test.result).booleanValue(),
- test.resultIdx);
- }
- else if (test.result instanceof Character)
- { checkMatch (argv, 0, argv.length,
- ((Character)test.result).charValue(),
- test.resultIdx);
- }
- else if (test.result.getClass().isArray())
- { checkMatch (argv, 0, argv.length, test.result,
- test.resultIdx);
- }
- else if (test.result instanceof MErr)
- { MErr err = (MErr)test.result;
- String argname = parser.getOptionName (argv[0]);
- String msg = "";
-
- switch (err.code)
- { case 'c':
- { msg = "requires a contiguous value";
- break;
- }
- case 'm':
- { msg = "malformed " + parser.getOptionTypeName(argv[0]) +
- " '" + err.valStr + "'";
- break;
- }
- case 'r':
- { msg = "value '" + err.valStr + "' not in range " +
- parser.getOptionRangeDesc(argv[0]);
- break;
- }
- case 'v':
- { msg = "requires " + err.valStr + " values";
- break;
- }
- }
- checkMatch (argv, 0, argname + ": " + msg);
- }
- else
- { verify (false, "Unknown result type");
- }
- }
-
- void checkMatches (MTest[] tests, boolean oneWord)
- { for (int i=0; i<tests.length; i++)
- { checkMatch (tests[i], oneWord);
- }
- }
-
- Object getMatchResult (String args[], int idx, int cnt,
- String errMsg, int resultIdx)
- {
- boolean exceptionThrown = false;
- int k = 0;
- try
- { k = parser.matchArg (args, idx);
- }
- catch (Exception e)
- { exceptionThrown = true;
- checkException (e, errMsg);
- }
- if (!exceptionThrown)
- { verify (k==idx+cnt,
- "Expecting result index " + (idx+cnt) + ", got " + k);
- Object result = parser.getResultHolder(args[0]);
- if (resultIdx >= 0)
- { verify (result instanceof Vector,
- "Expecting result to be stored in a vector");
- Vector<?> vec = (Vector<?>)result;
- verify (vec.size()==resultIdx+1,
- "Expecting result vector size " + (resultIdx+1));
- return vec.get(resultIdx);
- }
- else
- { return result;
- }
- }
- else
- { return null;
- }
- }
-
- /**
- * Runs a set of tests to verify correct operation of the
- * ArgParser class. If all the tests run correctly, the
- * program prints the message <code>Passed</code> and terminates.
- * Otherwise, diagnostic information is printed at the first
- * point of failure.
- */
- public static void main (String[] args)
- {
- ArgParserTest test = new ArgParserTest();
-
- BooleanHolder bh = new BooleanHolder();
- boolean[] b3 = new boolean[3];
- CharHolder ch = new CharHolder();
- char[] c3 = new char[3];
- IntHolder ih = new IntHolder();
- int[] i3 = new int[3];
- LongHolder lh = new LongHolder();
- long[] l3 = new long[3];
- FloatHolder fh = new FloatHolder();
- float[] f3 = new float[3];
- DoubleHolder dh = new DoubleHolder();
- double[] d3 = new double[3];
- StringHolder sh = new StringHolder();
- String[] s3 = new String[3];
-
- test.checkAdd ("-foo %i{[0,10)}X3 #sets the value of foo",
-// 0123456789012345
- i3, 'i', 3, new String[] { "-foo " },
- new RngCheck[] {
- new RngCheck(0, CLOSED, 10, OPEN) },
- "sets the value of foo", null);
-
- test.checkAdd ("-arg1,,", null, "Null option name given");
- test.checkAdd ("-arg1,,goo %f ", null, "Null option name given");
- test.checkAdd (" ", null, "Null option name given");
- test.checkAdd ("", null, "Null option name given");
- test.checkAdd (" %v", null, "Null option name given");
- test.checkAdd ("-foo ", null, "No conversion character given");
- test.checkAdd ("-foo %", null, "No conversion character given");
- test.checkAdd ("foo, aaa bbb ",null,"Names not separated by ','");
- test.checkAdd (" foo aaa %d", null, "Names not separated by ','");
- test.checkAdd ("-arg1,-b,", null, "Null option name given");
- test.checkAdd ("-arg1,-b", null, "No conversion character given");
- test.checkAdd ("-arg1 ", null, "No conversion character given");
- test.checkAdd ("-arg1, %v", null, "Null option name given");
- test.checkAdd ("-arg1,%v", null, "Null option name given");
- test.checkAdd ("-foo %V", null,
- "Conversion code 'V' not one of 'iodxcbfsvh'");
- test.checkAdd ("-h %hX5",null,"Multipliers not supported for %h");
- test.checkAdd ("-h %h{}",null,"Ranges not supported for %h");
- test.checkAdd ("-help, -h %h #here is how we help you",
- null, 'h', 1, new String[] {"-help ", "-h " },
- null, "here is how we help you", null);
-
- test.checkAdd (
- "-arg1 ,-arg2=%d{0,3,(7,16]}X1 #x3 test",
- l3, 'd', 1, new String[] { "-arg1 ", "-arg2=" },
- new RngCheck[]
- { new RngCheck(0),
- new RngCheck(3),
- new RngCheck(7, OPEN, 16, CLOSED),
- },
- "x3 test", null);
-
- test.checkAdd (
- "bbb,ccc%x{[1,2]} #X3 x3 test",
- l3, 'x', 1, new String[] { "bbb", "ccc" },
- new RngCheck[]
- { new RngCheck(1, CLOSED, 2, CLOSED),
- },
- "X3 x3 test", null);
-
- test.checkAdd (
- " bbb ,ccc, ddd ,e , f=%bX1 #x3 test",
- b3, 'b', 1, new String[] { "bbb ", "ccc", "ddd ", "e ", "f=" },
- null,
- "x3 test", null);
-
- test.checkAdd (
- " bbb ,ccc, ddd ,e , f= %bX3 #x3 test",
- b3, 'b', 3, new String[] { "bbb ", "ccc ", "ddd ", "e ","f= " },
- null,
- "x3 test", null);
-
- test.checkAdd (
- "-b,--bar %s{[\"john\",\"jerry\"),fred,\"harry\"} #sets bar",
- sh, 's', 1, new String[] { "-b ", "--bar " },
- new RngCheck[] {
- new RngCheck("jerry",OPEN,"john",CLOSED),
- new RngCheck("fred"),
- new RngCheck("harry") },
- "sets bar", null);
-
- test.checkAdd (
- "-c ,coven%f{0.0,9.0,(6,5],[-9.1,10.2]} ",
- dh, 'f', 1, new String[] { "-c ", "coven" },
- new RngCheck[] {
- new RngCheck(0.0),
- new RngCheck(9.0),
- new RngCheck(5.0,CLOSED,6.0,OPEN),
- new RngCheck(-9.1,CLOSED,10.2,CLOSED) },
- "", null);
-
- test.checkAdd (
- "-b %b #a boolean value ",
- bh, 'b', 1, new String[] { "-b "},
- new RngCheck[] { },
- "a boolean value ", null);
-
- test.checkAdd ("-a %i", ih, 'i', 1, "-a ", null, "", null);
- test.checkAdd ("-a %o", lh, 'o', 1, "-a ", null, "", null);
- test.checkAdd ("-a %d", i3, 'd', 1, "-a ", null, "", null);
- test.checkAdd ("-a %x", l3, 'x', 1, "-a ", null, "", null);
- test.checkAdd ("-a %c", ch, 'c', 1, "-a ", null, "", null);
- test.checkAdd ("-a %c", c3, 'c', 1, "-a ", null, "", null);
- test.checkAdd ("-a %v", bh, 'v', 1, "-a ", null, "", null);
- test.checkAdd ("-a %b", b3, 'b', 1, "-a ", null, "", null);
- test.checkAdd ("-a %f", fh, 'f', 1, "-a ", null, "", null);
- test.checkAdd ("-a %f", f3, 'f', 1, "-a ", null, "", null);
- test.checkAdd ("-a %f", dh, 'f', 1, "-a ", null, "", null);
- test.checkAdd ("-a %f", d3, 'f', 1, "-a ", null, "", null);
-
- test.checkAdd ("-a %i", fh, 'i', 1, "-a ", null, "",
- "Invalid result holder for %i");
- test.checkAdd ("-a %c", i3, 'c', 1, "-a ", null, "",
- "Invalid result holder for %c");
- test.checkAdd ("-a %v", d3, 'v', 1, "-a ", null, "",
- "Invalid result holder for %v");
- test.checkAdd ("-a %f", sh, 'f', 1, "-a ", null, "",
- "Invalid result holder for %f");
- test.checkAdd ("-a %s", l3, 's', 1, "-a ", null, "",
- "Invalid result holder for %s");
-
- test.checkAdd ("-foo %i{} ", ih, 'i', 1, "-foo ", null, "", null);
- test.checkAdd ("-foo%i{}", ih, 'i', 1, "-foo", null, "", null);
- test.checkAdd ("-foo%i{ }", ih, 'i', 1, "-foo", null, "", null);
- test.checkAdd ("-foo%i{ }}", ih,
- "Illegal character(s), expecting '#'");
- test.checkAdd ("-foo%i{ ", ih,"Unterminated range specification");
- test.checkAdd ("-foo%i{", ih, "Unterminated range specification");
- test.checkAdd ("-foo%i{0,9", ih, "Unterminated range specification");
- test.checkAdd ("-foo%i{1,2,3)", ih,
- "Unterminated range specification");
-
- test.checkAdd ("-b %f{0.9}", fh, 'f', 1, "-b ",
- new RngCheck[] { new RngCheck(0.9) },
- "", null);
- test.checkAdd ("-b %f{ 0.9 ,7, -0.5,-4 ,6 }", fh, 'f', 1, "-b ",
- new RngCheck[] { new RngCheck(0.9),
- new RngCheck(7.0),
- new RngCheck(-0.5),
- new RngCheck(-4.0),
- new RngCheck(6.0) },
- "", null);
- test.checkAdd ("-b %f{ [0.9,7), (-0.5,-4),[9,6] , (10,13.4] }",
- fh, 'f', 1, "-b ",
- new RngCheck[] { new RngCheck(0.9,CLOSED,7.0,OPEN),
- new RngCheck(-4.0,OPEN,-.5,OPEN),
- new RngCheck(6.0,CLOSED,9.0,CLOSED),
- new RngCheck(10.0,OPEN,13.4,CLOSED),
- },
- "", null);
- test.checkAdd ("-b %f{(8 9]}", fh,
- "Missing ',' in subrange specification");
- test.checkAdd ("-b %f{(8,9,]}", fh,
- "Unterminated subrange");
- test.checkAdd ("-b %f{(8,9 ,]}", fh,
- "Unterminated subrange");
- test.checkAdd ("-b %f{(8,9 8]}", fh,
- "Unterminated subrange");
- test.checkAdd ("-b %f{8 9}", fh,
- "Range spec: ',' or '}' expected");
- test.checkAdd ("-b %f{8 *}", fh,
- "Range spec: ',' or '}' expected");
-
- test.checkAdd ("-b %f{8y}", fh,
- "Range spec: ',' or '}' expected");
- test.checkAdd ("-b %f{.}", fh,
- "Malformed float '.}' in range spec");
- test.checkAdd ("-b %f{1.0e}", fh,
- "Malformed float '1.0e}' in range spec");
- test.checkAdd ("-b %f{[*]}", fh,
- "Malformed float '*' in range spec");
- test.checkAdd ("-b %f{1.2e5t}", fh,
- "Range spec: ',' or '}' expected");
-
-
- test.checkAdd ("-b %i{8}", ih, 'i', 1, "-b ",
- new RngCheck[] { new RngCheck(8) },
- "", null);
- test.checkAdd ("-b %i{8, 9,10 }", ih, 'i', 1, "-b ",
- new RngCheck[] { new RngCheck(8),
- new RngCheck(9),
- new RngCheck(10) },
- "", null);
- test.checkAdd ("-b %i{8, [-9,10),[-17,15],(2,-33),(8,9] }",
- ih, 'i', 1, "-b ",
- new RngCheck[] { new RngCheck(8),
- new RngCheck(-9,CLOSED,10,OPEN),
- new RngCheck(-17,CLOSED,15,CLOSED),
- new RngCheck(-33,OPEN,2,OPEN),
- new RngCheck(8,OPEN,9,CLOSED),
- },
- "", null);
- test.checkAdd ("-b %i{8.7}", ih,
- "Range spec: ',' or '}' expected");
- test.checkAdd ("-b %i{6,[*]}", ih,
- "Malformed integer '*' in range spec");
- test.checkAdd ("-b %i{g76}", ih,
- "Malformed integer 'g' in range spec");
-
- test.checkAdd ("-b %s{foobar}", sh, 's', 1, "-b ",
- new RngCheck[] { new RngCheck("foobar") },
- "", null);
- test.checkAdd ("-b %s{foobar, 0x233,\" \"}", sh, 's', 1, "-b ",
- new RngCheck[] { new RngCheck("foobar"),
- new RngCheck("0x233"),
- new RngCheck(" ") },
- "", null);
- test.checkAdd ("-b %s{foobar,(bb,aa], [\"01\",02]}",
- sh, 's', 1, "-b ",
- new RngCheck[]
- { new RngCheck("foobar"),
- new RngCheck("aa",CLOSED,"bb",OPEN),
- new RngCheck("01",CLOSED,"02",CLOSED),
- },
- "", null);
-
- test.checkAdd ("-b %c{'a'}", ch, 'c', 1, "-b ",
- new RngCheck[] { new RngCheck('a') },
- "", null);
- test.checkAdd ("-b %c{'\\n', '\\002', 'B'}", ch, 'c', 1, "-b ",
- new RngCheck[] { new RngCheck('\n'),
- new RngCheck('\002'),
- new RngCheck('B') },
- "", null);
- test.checkAdd ("-b %c{'q',('g','a'], ['\t','\\003']}",
- ch, 'c', 1, "-b ",
- new RngCheck[]
- { new RngCheck('q'),
- new RngCheck('a',CLOSED,'g',OPEN),
- new RngCheck('\003',CLOSED,'\t',CLOSED),
- },
- "", null);
-
- test.checkAdd ("-b %b{true}X2", b3, 'b', 2, "-b ",
- new RngCheck[] { new RngCheck(true) },
- "", null);
- test.checkAdd ("-b %b{ true , false, true }", bh, 'b', 1, "-b ",
- new RngCheck[] { new RngCheck(true),
- new RngCheck(false),
- new RngCheck(true) },
- "", null);
- test.checkAdd ("-b %v{true,[true,false)}", bh,
- "Sub ranges not supported for %b or %v");
- test.checkAdd ("-b %v{true,[]}", bh,
- "Sub ranges not supported for %b or %v");
- test.checkAdd ("-b %b{tru}", bh,
- "Malformed boolean 'tru}' in range spec");
-
- test.checkAdd ("-b %iX2", i3, 'i', 2, "-b ", null, "", null);
- test.checkAdd ("-b %vX3", b3, 'v', 3, "-b ", null, "", null);
- test.checkAdd ("-b %v{ }X3", b3, 'v', 3, "-b ", null, "", null);
-
- test.checkAdd ("-b=%iX2", i3, 'i', 2, "-b", null, "",
-"Multiplier value incompatible with one word option -b=");
- test.checkAdd ("-b %iX0", i3, 'i', 0, "-b ", null, "",
- "Value multiplier number must be > 0");
- test.checkAdd ("-b %iX-6", i3, 'i', 0, "-b ", null, "",
- "Value multiplier number must be > 0");
- test.checkAdd ("-b %iXy", i3, 'i', 0, "-b ", null, "",
- "Malformed value multiplier");
- test.checkAdd ("-b %iX4", i3, 'i', 4, "-b ", null, "",
- "Result holder array must have a length >= 4");
- test.checkAdd ("-b %iX4", ih, 'i', 4, "-b ", null, "",
-"Multiplier requires result holder to be an array of length >= 4");
-
- test.checkAdd ("-b %i #X4", ih, 'i', 1, "-b ", null, "X4", null);
- test.checkAdd ("-b %i #[}X4",ih, 'i', 1, "-b ", null, "[}X4", null);
-
-// test.checkPrintHelp("");
-// test.checkPrintUsage("");
-
- test = new ArgParserTest();
-
- test.checkAdd (
- "-intarg %i{1,2,(9,18],[22,27],[33,38),(45,48)} #test int arg",
- ih, 'i', 1, "-intarg ",
- new RngCheck[]
- { new RngCheck (1),
- new RngCheck (2),
- new RngCheck (9,OPEN,18,CLOSED),
- new RngCheck (22,CLOSED,27,CLOSED),
- new RngCheck (33,CLOSED,38,OPEN),
- new RngCheck (45,OPEN,48,OPEN),
- },
- "test int arg", null);
-
- MTest[] tests;
-
- tests = new MTest[]
- {
- new MTest("-intarg 1", new Long(1) ),
- new MTest("-intarg 3", new MErr ('r', "3") ),
- new MTest("-intarg 9", new MErr ('r', "9") ),
- new MTest("-intarg 11", new Long(11) ),
- new MTest("-intarg 18", new Long(18)),
- new MTest("-intarg 22", new Long(22)),
- new MTest("-intarg 25", new Long(25)),
- new MTest("-intarg 27", new Long(27)),
- new MTest("-intarg 33", new Long(33)),
- new MTest("-intarg 35", new Long(35)),
- new MTest("-intarg 38", new MErr ('r', "38") ),
- new MTest("-intarg 45", new MErr ('r', "45")),
- new MTest("-intarg 46", new Long(46)),
- new MTest("-intarg 48", new MErr ('r', "48")),
- new MTest("-intarg 100", new MErr ('r', "100")),
- new MTest("-intarg 0xbeef", new MErr ('r', "0xbeef")),
- new MTest("-intarg 0x2f", new Long (0x2f)),
- new MTest("-intarg 041", new Long(041) ),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd (
- "-farg %f{1,2,(9,18],[22,27],[33,38),(45,48)} #test float arg",
- dh, 'f', 1, "-farg ",
- new RngCheck[]
- {
- new RngCheck (1.0),
- new RngCheck (2.0),
- new RngCheck (9.0,OPEN,18.0,CLOSED),
- new RngCheck (22.0,CLOSED,27.0,CLOSED),
- new RngCheck (33.0,CLOSED,38.0,OPEN),
- new RngCheck (45.0,OPEN,48.0,OPEN),
- },
- "test float arg", null);
-
- tests = new MTest[]
- {
- new MTest("-farg 1", new Double(1)),
- new MTest("-farg 3", new MErr('r', "3")),
- new MTest("-farg 9", new MErr('r', "9")),
- new MTest("-farg 9.0001", new Double(9.0001)),
- new MTest("-farg 11", new Double(11)),
- new MTest("-farg 18", new Double(18)),
- new MTest("-farg 22", new Double(22)),
- new MTest("-farg 25", new Double(25)),
- new MTest("-farg 27", new Double(27)),
- new MTest("-farg 33", new Double(33)),
- new MTest("-farg 35", new Double(35)),
- new MTest("-farg 37.9999",new Double(37.9999)),
- new MTest("-farg 38", new MErr('r', "38")),
- new MTest("-farg 45", new MErr('r', "45")),
- new MTest("-farg 45.0001", new Double(45.0001)),
- new MTest("-farg 46",new Double(46)),
- new MTest("-farg 47.9999",new Double(47.9999)),
- new MTest("-farg 48", new MErr('r', "48")),
- new MTest("-farg 100", new MErr('r', "100")),
- new MTest("-farg 0", new MErr('r', "0")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd (
- "-sarg %s{1,2,(AA,AZ],[BB,BX],[C3,C8),(d5,d8)} #test string arg",
- s3, 's', 1, "-sarg ",
- new RngCheck[]
- { new RngCheck ("1"),
- new RngCheck ("2"),
- new RngCheck ("AA",OPEN,"AZ",CLOSED),
- new RngCheck ("BB",CLOSED,"BX",CLOSED),
- new RngCheck ("C3",CLOSED,"C8",OPEN),
- new RngCheck ("d5",OPEN,"d8",OPEN),
- },
- "test string arg", null);
-
- tests = new MTest[]
- {
- new MTest ("-sarg 1", "1"),
- new MTest ("-sarg 3", new MErr('r',"3")),
- new MTest ("-sarg AA", new MErr('r',"AA")),
- new MTest ("-sarg AM", "AM"),
- new MTest ("-sarg AZ", "AZ"),
- new MTest ("-sarg BB", "BB"),
- new MTest ("-sarg BL", "BL"),
- new MTest ("-sarg BX", "BX"),
- new MTest ("-sarg C3", "C3"),
- new MTest ("-sarg C6", "C6"),
- new MTest ("-sarg C8", new MErr('r',"C8")),
- new MTest ("-sarg d5", new MErr('r',"d5")),
- new MTest ("-sarg d6", "d6"),
- new MTest ("-sarg d8", new MErr('r',"d8")),
- new MTest ("-sarg zzz", new MErr('r',"zzz")),
- new MTest ("-sarg 0", new MErr('r',"0")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test = new ArgParserTest();
-
- test.checkAdd (
- "-carg %c{1,2,(a,z],['A','Z'],['\\001',\\007),(4,8)}",
- c3, 'c', 1, "-carg ",
- new RngCheck[]
- { new RngCheck ('1'),
- new RngCheck ('2'),
- new RngCheck ('a',OPEN,'z',CLOSED),
- new RngCheck ('A',CLOSED,'Z',CLOSED),
- new RngCheck ('\001',CLOSED,'\007',OPEN),
- new RngCheck ('4',OPEN,'8',OPEN),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-carg 1", new Character('1')),
- new MTest ("-carg 3", new MErr('r',"3")),
- new MTest ("-carg a", new MErr('r',"a")),
- new MTest ("-carg m", new Character('m')),
- new MTest ("-carg z", new Character('z')),
- new MTest ("-carg A", new Character('A')),
- new MTest ("-carg 'L'", new Character('L')),
- new MTest ("-carg 'Z'", new Character('Z')),
- new MTest ("-carg \\001", new Character('\001')),
- new MTest ("-carg \\005", new Character('\005')),
- new MTest ("-carg '\\007'", new MErr('r',"'\\007'")),
- new MTest ("-carg '4'", new MErr('r',"'4'")),
- new MTest ("-carg 6", new Character('6')),
- new MTest ("-carg 8", new MErr('r',"8")),
- new MTest ("-carg '\\012'", new MErr('r',"'\\012'")),
- new MTest ("-carg 0", new MErr('r',"0")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd (
- "-foo=%i{[-50,100]}", ih, 'i', 1, "-foo=",
- new RngCheck[]
- { new RngCheck (-50,CLOSED,100,CLOSED),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-foo=-51", new MErr('r',"-51")),
- new MTest ("-foo=-0x32", new Long(-0x32)),
- new MTest ("-foo=-0x33", new MErr('r',"-0x33")),
- new MTest ("-foo=-0777", new MErr('r',"-0777")),
- new MTest ("-foo=-07", new Long(-07)),
- new MTest ("-foo=0", new Long(0)),
- new MTest ("-foo=100", new Long(100)),
- new MTest ("-foo=0x5e", new Long(0x5e)),
- new MTest ("-foo=066", new Long(066)),
- new MTest ("-foo=06677", new MErr('r',"06677")),
- new MTest ("-foo=0xbeef", new MErr('r',"0xbeef")),
- new MTest ("-foo=foo", new MErr('m',"foo")),
- new MTest ("-foo=-51d", new MErr('m',"-51d")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-foo2=%i", ih, 'i', 1, "-foo2=", null, "", null);
- tests = new MTest[]
- {
- new MTest ("-foo2=-51", new Long(-51)),
- new MTest ("-foo2=-0x33", new Long(-0x33)),
- new MTest ("-foo2=-0777", new Long(-0777)),
- new MTest ("-foo2=06677", new Long(06677)),
- new MTest ("-foo2=0xbeef", new Long(0xbeef)),
- new MTest ("-foo2=foo", new MErr('m',"foo")),
- new MTest ("-foo2=-51d", new MErr('m',"-51d")),
- new MTest ("-foo2=-51", new Long(-51)),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-foo3 %iX3", i3, 'i', 3, "-foo3 ", null, "", null);
- tests = new MTest[]
- {
- new MTest ("-foo3 -51 678 0x45",
- new long[] { -51, 678, 0x45 }),
- new MTest ("-foo3 55 16f 55", new MErr ('m', "16f")),
- new MTest ("-foo3 55 16", new MErr ('v', "3")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- Vector<String> vec = new Vector<String>(100);
-
- test.checkAdd ("-foov3 %iX3", vec,'i',3,"-foov3 ",null,"",null);
- tests = new MTest[]
- { new MTest ("-foov3 -1 2 4", new long[] {-1, 2, 4}, 0),
- new MTest ("-foov3 10 3 9", new long[] {10, 3, 9}, 1),
- new MTest ("-foov3 123 1 0", new long[] {123, 1, 0}, 2),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
- test.checkAdd ("-foov %i", vec,'i',1,"-foov ",null,"",null);
- tests = new MTest[]
- { new MTest ("-foov 11", new Long(11), 0),
- new MTest ("-foov 12", new Long(12), 1),
- new MTest ("-foov 13", new Long(13), 2),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd (
- "-foo4 %i{[-50,100]}X2", i3, 'i', 2, "-foo4 ",
- new RngCheck[]
- { new RngCheck (-50,CLOSED,100,CLOSED),
- },
- "", null);
- tests = new MTest[]
- {
- new MTest ("-foo4 -49 78",
- new long[] { -49, 78 }),
- new MTest ("-foo4 -48 102", new MErr ('r', "102")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd (
- "-oct=%o{[-062,0144]}", ih, 'o', 1, "-oct=",
- new RngCheck[]
- { new RngCheck (-50,CLOSED,100,CLOSED),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-oct=-063", new MErr('r',"-063")),
- new MTest ("-oct=-0x32", new MErr('m',"-0x32")),
- new MTest ("-oct=-0777", new MErr('r',"-0777")),
- new MTest ("-oct=-07", new Long(-07)),
- new MTest ("-oct=0", new Long(0)),
- new MTest ("-oct=100", new Long(64)),
- new MTest ("-oct=0xae", new MErr('m',"0xae")),
- new MTest ("-oct=66", new Long(066)),
- new MTest ("-oct=06677", new MErr('r',"06677")),
- new MTest ("-oct=0xbeef", new MErr('m',"0xbeef")),
- new MTest ("-oct=foo", new MErr('m',"foo")),
- new MTest ("-oct=-51d", new MErr('m',"-51d")),
- new MTest ("-oct=78", new MErr('m',"78")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-oct2=%o", ih, 'o', 1, "-oct2=", null, "", null);
- tests = new MTest[]
- {
- new MTest ("-oct2=-063", new Long(-063)),
- new MTest ("-oct2=-0777", new Long(-0777)),
- new MTest ("-oct2=06677", new Long(06677)),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd (
- "-dec=%d{[-0x32,0x64]}", ih, 'd', 1, "-dec=",
- new RngCheck[]
- { new RngCheck (-50,CLOSED,100,CLOSED),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-dec=-063", new MErr('r',"-063")),
- new MTest ("-dec=-0x32", new MErr('m',"-0x32")),
- new MTest ("-dec=-0777", new MErr('r',"-0777")),
- new MTest ("-dec=-07", new Long(-07)),
- new MTest ("-dec=0", new Long(0)),
- new MTest ("-dec=100", new Long(100)),
- new MTest ("-dec=0xae", new MErr('m',"0xae")),
- new MTest ("-dec=66", new Long(66)),
- new MTest ("-dec=06677", new MErr('r',"06677")),
- new MTest ("-dec=0xbeef", new MErr('m',"0xbeef")),
- new MTest ("-dec=foo", new MErr('m',"foo")),
- new MTest ("-dec=-51d", new MErr('m',"-51d")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-dec2=%d", ih, 'd', 1, "-dec2=", null, "", null);
- tests = new MTest[]
- {
- new MTest ("-dec2=-063", new Long(-63)),
- new MTest ("-dec2=-0777", new Long(-777)),
- new MTest ("-dec2=06677", new Long(6677)),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd (
- "-hex=%x{[-0x32,0x64]}", ih, 'x', 1, "-hex=",
- new RngCheck[]
- { new RngCheck (-50,CLOSED,100,CLOSED),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-hex=-06", new Long(-0x6)),
- new MTest ("-hex=-0x3g2", new MErr('m',"-0x3g2")),
- new MTest ("-hex=-0777", new MErr('r',"-0777")),
- new MTest ("-hex=-017", new Long(-0x17)),
- new MTest ("-hex=0", new Long(0)),
- new MTest ("-hex=64", new Long(0x64)),
- new MTest ("-hex=5e", new Long(0x5e)),
- new MTest ("-hex=66", new MErr('r',"66")),
- new MTest ("-hex=06677", new MErr('r',"06677")),
- new MTest ("-hex=0xbeef", new MErr('m',"0xbeef")),
- new MTest ("-hex=foo", new MErr('m',"foo")),
- new MTest ("-hex=-51d", new MErr('r',"-51d")),
- new MTest ("-hex=-51g", new MErr('m',"-51g")),
- new MTest ("-hex=", new MErr('c',"")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-hex2=%x", ih, 'x', 1, "-hex2=", null, "", null);
- tests = new MTest[]
- {
- new MTest ("-hex2=-0777", new Long(-0x777)),
- new MTest ("-hex2=66", new Long(0x66)),
- new MTest ("-hex2=06677", new Long(0x6677)),
- new MTest ("-hex2=-51d", new Long(-0x51d)),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd (
- "-char=%c{['b','m']}", ch, 'c', 1, "-char=",
- new RngCheck[]
- { new RngCheck ('b',CLOSED,'m',CLOSED),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-char=a", new MErr('r',"a")),
- new MTest ("-char=b", new Character('b')),
- new MTest ("-char='b'", new Character('b')),
- new MTest ("-char='\142'", new Character('b')),
- new MTest ("-char='\141'", new MErr('r',"'\141'")),
- new MTest ("-char=\142", new Character('b')),
- new MTest ("-char=\141", new MErr('r',"\141")),
- new MTest ("-char=m", new Character('m')),
- new MTest ("-char=z", new MErr('r', "z")),
- new MTest ("-char=bb", new MErr('m', "bb")),
- new MTest ("-char='b", new MErr('m', "'b")),
- new MTest ("-char='", new MErr('m', "'")),
- new MTest ("-char=a'", new MErr('m', "a'")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-char2=%c", ch, 'c', 1, "-char2=",null,"",null);
- tests = new MTest[]
- {
- new MTest ("-char2=a", new Character('a')),
- new MTest ("-char2='\141'", new Character('\141')),
- new MTest ("-char2=\141", new Character('\141')),
- new MTest ("-char2=z", new Character('z')),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-charv3 %cX3", vec,'c',3,"-charv3 ",null,"",null);
- tests = new MTest[]
- { new MTest ("-charv3 a b c", new char[] {'a', 'b', 'c'}, 0),
- new MTest ("-charv3 'g' f '\\n'", new char[]{'g','f','\n'}, 1),
- new MTest ("-charv3 1 \001 3", new char[] {'1', '\001', '3'}, 2),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
- test.checkAdd ("-charv=%c", vec,'c',1,"-charv=",null,"",null);
- tests = new MTest[]
- { new MTest ("-charv=d", new Character('d'), 0),
- new MTest ("-charv='g'", new Character('g'), 1),
- new MTest ("-charv=\111", new Character('\111'), 2),
- };
- vec.clear();
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd (
- "-bool=%b{true}", bh, 'b', 1, "-bool=",
- new RngCheck[]
- { new RngCheck (true),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-bool=true", new Boolean(true)),
- new MTest ("-bool=false", new MErr('r', "false")),
- new MTest ("-bool=fals", new MErr('m', "fals")),
- new MTest ("-bool=falsem", new MErr('m', "falsem")),
- new MTest ("-bool=truex", new MErr('m', "truex")),
- new MTest ("-bool=foo", new MErr('m', "foo")),
- new MTest ("-bool=1", new MErr('m', "1")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd (
- "-boo2=%b{true,false}", bh, 'b', 1, "-boo2=",
- new RngCheck[]
- { new RngCheck (true),
- new RngCheck (false),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-boo2=true", new Boolean(true)),
- new MTest ("-boo2=false", new Boolean(false)),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-boo3=%b", bh, 'b', 1, "-boo3=", null, "", null);
- tests = new MTest[]
- {
- new MTest ("-boo3=true", new Boolean(true)),
- new MTest ("-boo3=false", new Boolean(false)),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-boo3 %bX3", b3, 'b', 3, "-boo3 ", null, "", null);
- tests = new MTest[]
- {
- new MTest ("-boo3 true false true",
- new boolean[] { true, false, true }),
- new MTest ("-boo3 true fals true", new MErr ('m', "fals")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd ("-boov3 %bX3", vec,'b',3,"-boov3 ",null,"",null);
- tests = new MTest[]
- { new MTest ("-boov3 true true false",
- new boolean [] { true, true, false }, 0),
- new MTest ("-boov3 false false true",
- new boolean [] { false, false, true }, 1),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
- test.checkAdd ("-boov %b", vec,'b',1,"-boov ",null,"",null);
- tests = new MTest[]
- { new MTest ("-boov true", new Boolean (true), 0),
- new MTest ("-boov false", new Boolean (false), 1),
- new MTest ("-boov true", new Boolean (true), 2),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
-
-
- test.checkAdd ("-v3 %vX2", b3, 'v', 2, "-v3 ", null, "", null);
- tests = new MTest[]
- { new MTest ("-v3", new boolean[] { true, true }),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd (
- "-vf %v{false,true}X2", b3, 'v', 2, "-vf ",
- new RngCheck[]
- { new RngCheck(false),
- new RngCheck(true),
- },
- "", null);
- tests = new MTest[]
- { new MTest ("-vf", new boolean[] { false, false }),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd (
- "-str=%s{(john,zzzz]}", sh, 's', 1, "-str=",
- new RngCheck[]
- { new RngCheck ("john", OPEN, "zzzz", CLOSED),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-str=john", new MErr ('r', "john")),
- new MTest ("-str=joho ", "joho "),
- new MTest ("-str=joho ", "joho "),
- new MTest ("-str=zzzz", "zzzz"),
- new MTest ("-str= joho", new MErr ('r', " joho")),
- new MTest ("-str=jnhn ", new MErr ('r', "jnhn ")),
- new MTest ("-str=zzzzz", new MErr ('r', "zzzzz")),
- new MTest ("-str=\"joho\"", new MErr ('r', "\"joho\"")),
- new MTest ("-str=\"joho", new MErr('r', "\"joho")),
- new MTest ("-str=joho j", "joho j"), // new MErr('m', "joho j")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-str2=%s", sh,'s',1,"-str2=",null,"",null);
- tests = new MTest[]
- {
- new MTest ("-str2= jnhn", " jnhn"),
- new MTest ("-str2=zzzzz", "zzzzz"),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-str3 %sX3",s3,'s',3,"-str3 ",null,"",null);
- tests = new MTest[]
- {
- new MTest ("-str3 foo bar johnny",
- new String[] { "foo", "bar", "johnny" }),
- new MTest ("-str3 zzzzz \"bad foo",
- new String[] { "zzzzz", "\"bad", "foo"
- }), // new MErr('m', "\"bad")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd ("-strv3 %sX3", vec,'s',3,"-strv3 ",null,"",null);
- tests = new MTest[]
- { new MTest ("-strv3 foo bar \"hihi\"",
- new String[] {"foo", "bar", "\"hihi\""}, 0),
- new MTest ("-strv3 a 123 gg",
- new String[]{"a", "123", "gg"}, 1),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
- test.checkAdd ("-strv=%s", vec,'s',1,"-strv=",null,"",null);
- tests = new MTest[]
- { new MTest ("-strv=d", "d", 0),
- new MTest ("-strv='g'", "'g'", 1),
- new MTest ("-strv=\\111", "\\111", 2),
- };
- vec.clear();
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd (
- "-float=%f{(-0.001,1000.0]}", dh, 'f', 1, "-float=",
- new RngCheck[]
- { new RngCheck (-0.001, OPEN, 1000.0, CLOSED),
- },
- "", null);
-
- tests = new MTest[]
- {
- new MTest ("-float=-0.000999", new Double(-0.000999)),
- new MTest ("-float=1e-3", new Double(0.001)),
- new MTest ("-float=12.33e1", new Double(123.3)),
- new MTest ("-float=1e3", new Double(1e3)),
- new MTest ("-float=1000.000", new Double(1000.0)),
- new MTest ("-float=-0.001", new MErr('r', "-0.001")),
- new MTest ("-float=-1e-3", new MErr('r', "-1e-3")),
- new MTest ("-float=1000.001", new MErr('r', "1000.001")),
- new MTest ("-float=.", new MErr('m', ".")),
- new MTest ("-float= 124.5 ", new Double (124.5)),
- new MTest ("-float=124.5x", new MErr('m', "124.5x")),
- new MTest ("-float= foo ", new MErr('m', " foo ")),
- new MTest ("-float=1e1", new Double(10)),
- new MTest ("-float=1e ", new MErr('m', "1e ")),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-float2=%f", dh,'f',1,"-float2=",null,"",null);
- tests = new MTest[]
- {
- new MTest ("-float2=-0.001", new Double(-0.001)),
- new MTest ("-float2=-1e-3", new Double(-1e-3)),
- new MTest ("-float2=1000.001", new Double(1000.001)),
- };
- test.checkMatches (tests, ONE_WORD);
-
- test.checkAdd ("-f3 %fX3", d3,'f',3,"-f3 ",null,"",null);
- tests = new MTest[]
- {
- new MTest ("-f3 -0.001 1.23e5 -9.88e-4",
- new double[] { -0.001, 1.23e5, -9.88e-4 }),
- new MTest ("-f3 7.88 foo 9.0", new MErr ('m', "foo")),
- new MTest ("-f3 7.88 . 9.0", new MErr ('m', ".")),
- new MTest ("-f3 7.88 3.0 9.0x", new MErr ('m', "9.0x")),
- };
- test.checkMatches (tests, MULTI_WORD);
-
- test.checkAdd ("-fv3 %fX3", vec,'f',3,"-fv3 ",null,"",null);
- tests = new MTest[]
- { new MTest ("-fv3 1.0 3.444 6.7",
- new double[] {1.0, 3.444, 6.7}, 0),
- new MTest ("-fv3 13e-5 145.678 0.0001e45",
- new double[]{13e-5, 145.678, 0.0001e45}, 1),
- new MTest ("-fv3 11.11 3.1245 -1e-4",
- new double[] {11.11, 3.1245, -1e-4}, 2),
- new MTest ("-fv3 1.0 2 3",
- new double[] { 1.0, 2.0, 3.0 }, 3),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
- test.checkAdd ("-fv %f", vec,'f',1,"-fv ",null,"",null);
- tests = new MTest[]
- { new MTest ("-fv -15.1234", new Double(-15.1234), 0),
- new MTest ("-fv -1.234e-7", new Double(-1.234e-7), 1),
- new MTest ("-fv 0.001111", new Double(0.001111), 2),
- };
- vec.clear();
- test.checkMatches (tests, MULTI_WORD);
-
-
- IntHolder intHolder = new IntHolder();
- StringHolder strHolder = new StringHolder();
-
- ArgParser parser = new ArgParser ("test");
- parser.addOption ("-foo %d #an int", intHolder);
- parser.addOption ("-bar %s #a string", strHolder);
- args = new String[]
- { "zzz", "-cat", "-foo", "123", "yyy", "-bar", "xxxx", "xxx"
- };
-
- String[] unmatchedCheck = new String[]
- { "zzz", "-cat", "yyy", "xxx"
- };
-
- String[] unmatched = parser.matchAllArgs (args, 0, 0);
- test.checkStringArray (
- "Unmatched args:", unmatched, unmatchedCheck);
-
- vec.clear();
- for (int i=0; i<args.length; )
- { try
- { i = parser.matchArg (args, i);
- if (parser.getUnmatchedArgument() != null)
- { vec.add (parser.getUnmatchedArgument());
- }
- }
- catch (Exception e)
- {
- }
- }
- unmatched = (String[])vec.toArray(new String[0]);
- test.checkStringArray (
- "My unmatched args:", unmatched, unmatchedCheck);
-
- System.out.println ("\nPassed\n");
-
- }
+public class ArgParserTest {
+ ArgParser parser;
+
+ static final boolean CLOSED = true;
+ static final boolean OPEN = false;
+
+ static final boolean ONE_WORD = true;
+ static final boolean MULTI_WORD = false;
+
+ private static void verify(boolean ok, String msg) {
+ if (!ok) {
+ Throwable e = new Throwable();
+ System.out.println("Verification failed:" + msg);
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static String[] argsFromString(String s) {
+ Vector<String> vec = new Vector<String>(100);
+ try {
+ ArgParser.stringToArgs(vec, s, /*allowQuotedStings=*/false);
+ } catch (StringScanException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ String[] result = new String[vec.size()];
+ for (int i = 0; i < vec.size(); i++) {
+ result[i] = (String) vec.get(i);
+ }
+ return result;
+ }
+
+ static class RngCheck {
+ ArgParser.RangePnt low = null;
+ ArgParser.RangePnt high = null;
+ int type;
+
+ RngCheck(String s) {
+ low = new ArgParser.RangePnt(s, CLOSED);
+ type = 's';
+ }
+
+ RngCheck(double d) {
+ low = new ArgParser.RangePnt(d, CLOSED);
+ type = 'd';
+ }
+
+ RngCheck(long l) {
+ low = new ArgParser.RangePnt(l, CLOSED);
+ type = 'l';
+ }
+
+ RngCheck(boolean b) {
+ low = new ArgParser.RangePnt(b, CLOSED);
+ type = 'b';
+ }
+
+ RngCheck(String s1, boolean c1, String s2, boolean c2) {
+ low = new ArgParser.RangePnt(s1, c1);
+ high = new ArgParser.RangePnt(s2, c2);
+ type = 's';
+ }
+
+ RngCheck(double d1, boolean c1, double d2, boolean c2) {
+ low = new ArgParser.RangePnt(d1, c1);
+ high = new ArgParser.RangePnt(d2, c2);
+ type = 'd';
+ }
+
+ RngCheck(long l1, boolean c1, long l2, boolean c2) {
+ low = new ArgParser.RangePnt(l1, c1);
+ high = new ArgParser.RangePnt(l2, c2);
+ type = 'l';
+ }
+
+ void check(ArgParser.RangeAtom ra) {
+ verify((ra.low == null) == (low == null),
+ "(ra.low==null)=" + (ra.low == null) +
+ "(low==null)=" + (low == null));
+ verify((ra.high == null) == (high == null),
+ "(ra.high==null)=" + (ra.high == null) +
+ "(high==null)=" + (high == null));
+
+ if (ra.low != null) {
+ switch (type) {
+ case 'l': {
+ verify(ra.low.lval == low.lval,
+ "ra.low=" + ra.low + " low=" + low);
+ break;
+ }
+ case 'd': {
+ verify(ra.low.dval == low.dval,
+ "ra.low=" + ra.low + " low=" + low);
+ break;
+ }
+ case 's': {
+ verify(ra.low.sval.equals(low.sval),
+ "ra.low=" + ra.low + " low=" + low);
+ break;
+ }
+ case 'b': {
+ verify(ra.low.bval == low.bval,
+ "ra.low=" + ra.low + " low=" + low);
+ break;
+ }
+ }
+ verify(ra.low.closed == low.closed,
+ "ra.low=" + ra.low + " low=" + low);
+ }
+ if (ra.high != null) {
+ switch (type) {
+ case 'l': {
+ verify(ra.high.lval == high.lval,
+ "ra.high=" + ra.high + " high=" + high);
+ break;
+ }
+ case 'd': {
+ verify(ra.high.dval == high.dval,
+ "ra.high=" + ra.high + " high=" + high);
+ break;
+ }
+ case 's': {
+ verify(ra.high.sval.equals(high.sval),
+ "ra.high=" + ra.high + " high=" + high);
+ break;
+ }
+ case 'b': {
+ verify(ra.high.bval == high.bval,
+ "ra.high=" + ra.high + " high=" + high);
+ break;
+ }
+ }
+ verify(ra.high.closed == high.closed,
+ "ra.high=" + ra.high + " high=" + high);
+ }
+ }
+ }
+
+ ArgParserTest() {
+ parser = new ArgParser("fubar");
+ }
+
+ static void checkException(Exception e, String errmsg) {
+ if (errmsg != null) {
+ if (!e.getMessage().equals(errmsg)) {
+ System.out.println(
+ "Expecting exception '" + errmsg + "' but got '" +
+ e.getMessage() + "'");
+ e.printStackTrace();
+ (new Throwable()).printStackTrace();
+ System.exit(1);
+ }
+ } else {
+ System.out.println(
+ "Unexpected exception '" + e.getMessage() + "'");
+ e.printStackTrace();
+ (new Throwable()).printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ void checkPrintHelp(String msg) {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(0x10000);
+ PrintStream ps = new PrintStream(buf);
+ ps.println(parser.getHelpMessage());
+ System.out.print(buf.toString());
+ }
+
+ // void checkGetSynopsis (String msg)
+ // {
+ // ByteArrayOutputStream buf = new ByteArrayOutputStream(0x10000);
+ // PrintStream ps = new PrintStream(buf);
+ // parser.printSynopsis (ps, 80);
+ // System.out.print (buf.toString());
+ // }
+
+ void checkAdd(String s, Object resHolder, String errmsg) {
+ checkAdd(s, resHolder, 0, 0, null, null, null, errmsg);
+ }
+
+ void add(String s, Object resHolder) {
+ try {
+ parser.addOption(s, resHolder);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ void checkStringArray(String msg, String[] strs, String[] check) {
+ boolean dontMatch = false;
+ if (strs.length != check.length) {
+ dontMatch = true;
+ } else {
+ for (int i = 0; i < strs.length; i++) {
+ if (!strs[i].equals(check[i])) {
+ dontMatch = true;
+ break;
+ }
+ }
+ }
+ if (dontMatch) {
+ System.out.println(msg);
+ System.out.print("Expected: ");
+ for (int i = 0; i < check.length; i++) {
+ System.out.print("'" + check[i] + "'");
+ if (i < check.length - 1) {
+ System.out.print(" ");
+ }
+ }
+ System.out.println("");
+ System.out.print("Got: ");
+ for (int i = 0; i < strs.length; i++) {
+ System.out.print("'" + strs[i] + "'");
+ if (i < strs.length - 1) {
+ System.out.print(" ");
+ }
+ }
+ System.out.println("");
+ System.exit(1);
+ }
+ }
+
+ void checkAdd(String s, Object resHolder, int code, int numValues,
+ Object names, RngCheck[] rngCheck,
+ String helpMsg, String errmsg) {
+ boolean exceptionThrown = false;
+ String[] namelist = null;
+ try {
+ parser.addOption(s, resHolder);
+ } catch (Exception e) {
+ exceptionThrown = true;
+ checkException(e, errmsg);
+ }
+ if (names instanceof String) {
+ namelist = new String[] { (String) names };
+ } else {
+ namelist = (String[]) names;
+ }
+ if (!exceptionThrown) {
+ verify(errmsg == null,
+ "Expecting exception " + errmsg);
+ ArgParser.Record rec = parser.lastMatchRecord();
+ verify(rec.convertCode == code,
+ "code=" + rec.convertCode + ", expecting " + code);
+ ArgParser.NameDesc nd;
+ int i = 0;
+ for (nd = rec.firstNameDesc(); nd != null; nd = nd.next) {
+ i++;
+ }
+ verify(i == namelist.length,
+ "numNames=" + i + ", expecting " + namelist.length);
+ i = 0;
+ for (nd = rec.firstNameDesc(); nd != null; nd = nd.next) {
+ String ss;
+ if (!nd.oneWord) {
+ ss = new String(nd.name) + ' ';
+ } else {
+ ss = nd.name;
+ }
+ verify(ss.equals(namelist[i]),
+ "have name '" + ss + "', expecting '" + namelist[i] + "'");
+ i++;
+ }
+ ArgParser.RangeAtom ra;
+ i = 0;
+ for (ra = rec.firstRangeAtom(); ra != null; ra = ra.next) {
+ i++;
+ }
+ int expectedRangeNum = 0;
+ if (rngCheck != null) {
+ expectedRangeNum = rngCheck.length;
+ }
+ verify(i == expectedRangeNum,
+ "numRangeAtoms=" + i + ", expecting " + expectedRangeNum);
+ i = 0;
+ for (ra = rec.firstRangeAtom(); ra != null; ra = ra.next) {
+ rngCheck[i++].check(ra);
+ }
+ verify(rec.helpMsg.equals(helpMsg),
+ "helpMsg=" + rec.helpMsg + ", expecting " + helpMsg);
+ verify(rec.numValues == numValues,
+ "numValues=" + rec.numValues + ", expecting " + numValues);
+ }
+ }
+
+ double getDoubleValue(Object obj, int k) {
+ if (obj instanceof DoubleHolder) {
+ return ((DoubleHolder) obj).value;
+ } else if (obj instanceof FloatHolder) {
+ return ((FloatHolder) obj).value;
+ } else if (obj instanceof double[]) {
+ return ((double[]) obj)[k];
+ } else if (obj instanceof float[]) {
+ return ((float[]) obj)[k];
+ } else {
+ verify(false, "object doesn't contain double values");
+ return 0;
+ }
+ }
+
+ long getLongValue(Object obj, int k) {
+ if (obj instanceof LongHolder) {
+ return ((LongHolder) obj).value;
+ } else if (obj instanceof IntHolder) {
+ return ((IntHolder) obj).value;
+ } else if (obj instanceof long[]) {
+ return ((long[]) obj)[k];
+ } else if (obj instanceof int[]) {
+ return ((int[]) obj)[k];
+ } else {
+ verify(false, "object doesn't contain long values");
+ return 0;
+ }
+ }
+
+ String getStringValue(Object obj, int k) {
+ if (obj instanceof StringHolder) {
+ return ((StringHolder) obj).value;
+ } else if (obj instanceof String[]) {
+ return ((String[]) obj)[k];
+ } else {
+ verify(false, "object doesn't contain String values");
+ return null;
+ }
+ }
+
+ boolean getBooleanValue(Object obj, int k) {
+ if (obj instanceof BooleanHolder) {
+ return ((BooleanHolder) obj).value;
+ } else if (obj instanceof boolean[]) {
+ return ((boolean[]) obj)[k];
+ } else {
+ verify(false, "object doesn't contain boolean values");
+ return false;
+ }
+ }
+
+ char getCharValue(Object obj, int k) {
+ if (obj instanceof CharHolder) {
+ return ((CharHolder) obj).value;
+ } else if (obj instanceof char[]) {
+ return ((char[]) obj)[k];
+ } else {
+ verify(false, "object doesn't contain char values");
+ return 0;
+ }
+ }
+
+ static class MErr {
+ int code;
+ String valStr;
+
+ MErr(int code, String valStr) {
+ this.code = code;
+ this.valStr = valStr;
+ }
+ }
+
+ static class MTest {
+ String args;
+ Object result;
+ int resultIdx;
+
+ MTest(String args, Object result) {
+ this(args, result, -1);
+ }
+
+ MTest(String args, Object result, int resultIdx) {
+ this.args = args;
+ this.result = result;
+ this.resultIdx = resultIdx;
+ }
+ };
+
+ void checkMatch(String args[], int idx, String errMsg) {
+ getMatchResult(args, idx, -1, errMsg, -1);
+ }
+
+ void checkMatch(String args[], int idx, int cnt,
+ long check, int resultIdx) {
+ Object rholder = getMatchResult(args, idx, cnt, null, resultIdx);
+ long result = getLongValue(rholder, 0);
+ verify(result == check, "result " + result + " vs. " + check);
+ }
+
+ void checkMatch(String args[], int idx, int cnt,
+ double check, int resultIdx) {
+ Object rholder = getMatchResult(args, idx, cnt, null, resultIdx);
+ double result = getDoubleValue(rholder, 0);
+ verify(result == check, "result " + result + " vs. " + check);
+ }
+
+ void checkMatch(String args[], int idx, int cnt,
+ String check, int resultIdx) {
+ Object rholder = getMatchResult(args, idx, cnt, null, resultIdx);
+ String result = getStringValue(rholder, 0);
+ verify(result.equals(check), "result " + result + " vs. " + check);
+ }
+
+ void checkMatch(String args[], int idx, int cnt,
+ boolean check, int resultIdx) {
+ Object rholder = getMatchResult(args, idx, cnt, null, resultIdx);
+ boolean result = getBooleanValue(rholder, 0);
+ verify(result == check, "result " + result + " vs. " + check);
+ }
+
+ void checkMatch(String args[], int idx, int cnt,
+ char check, int resultIdx) {
+ Object rholder = getMatchResult(args, idx, cnt, null, resultIdx);
+ char result = getCharValue(rholder, 0);
+ verify(result == check, "result " + result + " vs. " + check);
+ }
+
+ void checkMatch(String args[], int idx, int cnt,
+ Object checkArray, int resultIdx) {
+ Object rholder = getMatchResult(args, idx, cnt, null, resultIdx);
+ if (!checkArray.getClass().isArray()) {
+ verify(false, "check is not an array");
+ }
+ for (int i = 0; i < Array.getLength(checkArray); i++) {
+ if (checkArray instanceof long[]) {
+ long result = getLongValue(rholder, i);
+ long check = ((long[]) checkArray)[i];
+ verify(result == check,
+ "result [" + i + "] " + result + " vs. " + check);
+ } else if (checkArray instanceof double[]) {
+ double result = getDoubleValue(rholder, i);
+ double check = ((double[]) checkArray)[i];
+ verify(result == check,
+ "result [" + i + "] " + result + " vs. " + check);
+ } else if (checkArray instanceof String[]) {
+ String result = getStringValue(rholder, i);
+ String check = ((String[]) checkArray)[i];
+ verify(result.equals(check),
+ "result [" + i + "] " + result + " vs. " + check);
+ } else if (checkArray instanceof boolean[]) {
+ boolean result = getBooleanValue(rholder, i);
+ boolean check = ((boolean[]) checkArray)[i];
+ verify(result == check,
+ "result [" + i + "] " + result + " vs. " + check);
+ } else if (checkArray instanceof char[]) {
+ char result = getCharValue(rholder, i);
+ char check = ((char[]) checkArray)[i];
+ verify(result == check,
+ "result [" + i + "] " + result + " vs. " + check);
+ } else {
+ verify(false, "unknown type for checkArray");
+ }
+ }
+ }
+
+ void checkMatch(MTest test, boolean oneWord) {
+ String[] argv;
+ if (oneWord) {
+ argv = new String[1];
+ argv[0] = test.args;
+ } else {
+ argv = argsFromString(test.args);
+ }
+ if (test.result instanceof Long) {
+ checkMatch(argv, 0, argv.length,
+ ((Long) test.result).longValue(),
+ test.resultIdx);
+ } else if (test.result instanceof Double) {
+ checkMatch(argv, 0, argv.length,
+ ((Double) test.result).doubleValue(),
+ test.resultIdx);
+ } else if (test.result instanceof String) {
+ checkMatch(argv, 0, argv.length,
+ (String) test.result,
+ test.resultIdx);
+ } else if (test.result instanceof Boolean) {
+ checkMatch(argv, 0, argv.length,
+ ((Boolean) test.result).booleanValue(),
+ test.resultIdx);
+ } else if (test.result instanceof Character) {
+ checkMatch(argv, 0, argv.length,
+ ((Character) test.result).charValue(),
+ test.resultIdx);
+ } else if (test.result.getClass().isArray()) {
+ checkMatch(argv, 0, argv.length, test.result,
+ test.resultIdx);
+ } else if (test.result instanceof MErr) {
+ MErr err = (MErr) test.result;
+ String argname = parser.getOptionName(argv[0]);
+ String msg = "";
+
+ switch (err.code) {
+ case 'c': {
+ msg = "requires a contiguous value";
+ break;
+ }
+ case 'm': {
+ msg = "malformed " + parser.getOptionTypeName(argv[0]) +
+ " '" + err.valStr + "'";
+ break;
+ }
+ case 'r': {
+ msg = "value '" + err.valStr + "' not in range " +
+ parser.getOptionRangeDesc(argv[0]);
+ break;
+ }
+ case 'v': {
+ msg = "requires " + err.valStr + " values";
+ break;
+ }
+ }
+ checkMatch(argv, 0, argname + ": " + msg);
+ } else {
+ verify(false, "Unknown result type");
+ }
+ }
+
+ void checkMatches(MTest[] tests, boolean oneWord) {
+ for (int i = 0; i < tests.length; i++) {
+ checkMatch(tests[i], oneWord);
+ }
+ }
+
+ Object getMatchResult(String args[], int idx, int cnt,
+ String errMsg, int resultIdx) {
+ boolean exceptionThrown = false;
+ int k = 0;
+ try {
+ k = parser.matchArg(args, idx);
+ } catch (Exception e) {
+ exceptionThrown = true;
+ checkException(e, errMsg);
+ }
+ if (!exceptionThrown) {
+ verify(k == idx + cnt,
+ "Expecting result index " + (idx + cnt) + ", got " + k);
+ Object result = parser.getResultHolder(args[0]);
+ if (resultIdx >= 0) {
+ verify(result instanceof Vector,
+ "Expecting result to be stored in a vector");
+ Vector<?> vec = (Vector<?>) result;
+ verify(vec.size() == resultIdx + 1,
+ "Expecting result vector size " + (resultIdx + 1));
+ return vec.get(resultIdx);
+ } else {
+ return result;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Runs a set of tests to verify correct operation of the
+ * ArgParser class. If all the tests run correctly, the
+ * program prints the message <code>Passed</code> and terminates.
+ * Otherwise, diagnostic information is printed at the first
+ * point of failure.
+ */
+ public static void main(String[] args) {
+ ArgParserTest test = new ArgParserTest();
+
+ BooleanHolder bh = new BooleanHolder();
+ boolean[] b3 = new boolean[3];
+ CharHolder ch = new CharHolder();
+ char[] c3 = new char[3];
+ IntHolder ih = new IntHolder();
+ int[] i3 = new int[3];
+ LongHolder lh = new LongHolder();
+ long[] l3 = new long[3];
+ FloatHolder fh = new FloatHolder();
+ float[] f3 = new float[3];
+ DoubleHolder dh = new DoubleHolder();
+ double[] d3 = new double[3];
+ StringHolder sh = new StringHolder();
+ String[] s3 = new String[3];
+
+ test.checkAdd("-foo %i{[0,10)}X3 #sets the value of foo",
+ // 0123456789012345
+ i3, 'i', 3, new String[] { "-foo " },
+ new RngCheck[] {
+ new RngCheck(0, CLOSED, 10, OPEN) },
+ "sets the value of foo", null);
+
+ test.checkAdd("-arg1,,", null, "Null option name given");
+ test.checkAdd("-arg1,,goo %f ", null, "Null option name given");
+ test.checkAdd(" ", null, "Null option name given");
+ test.checkAdd("", null, "Null option name given");
+ test.checkAdd(" %v", null, "Null option name given");
+ test.checkAdd("-foo ", null, "No conversion character given");
+ test.checkAdd("-foo %", null, "No conversion character given");
+ test.checkAdd("foo, aaa bbb ", null, "Names not separated by ','");
+ test.checkAdd(" foo aaa %d", null, "Names not separated by ','");
+ test.checkAdd("-arg1,-b,", null, "Null option name given");
+ test.checkAdd("-arg1,-b", null, "No conversion character given");
+ test.checkAdd("-arg1 ", null, "No conversion character given");
+ test.checkAdd("-arg1, %v", null, "Null option name given");
+ test.checkAdd("-arg1,%v", null, "Null option name given");
+ test.checkAdd("-foo %V", null,
+ "Conversion code 'V' not one of 'iodxcbfsvh'");
+ test.checkAdd("-h %hX5", null, "Multipliers not supported for %h");
+ test.checkAdd("-h %h{}", null, "Ranges not supported for %h");
+ test.checkAdd("-help, -h %h #here is how we help you",
+ null, 'h', 1, new String[] { "-help ", "-h " },
+ null, "here is how we help you", null);
+
+ test.checkAdd(
+ "-arg1 ,-arg2=%d{0,3,(7,16]}X1 #x3 test",
+ l3, 'd', 1, new String[] { "-arg1 ", "-arg2=" },
+ new RngCheck[]
+ { new RngCheck(0),
+ new RngCheck(3),
+ new RngCheck(7, OPEN, 16, CLOSED),
+ },
+ "x3 test", null);
+
+ test.checkAdd(
+ "bbb,ccc%x{[1,2]} #X3 x3 test",
+ l3, 'x', 1, new String[] { "bbb", "ccc" },
+ new RngCheck[]
+ { new RngCheck(1, CLOSED, 2, CLOSED),
+ },
+ "X3 x3 test", null);
+
+ test.checkAdd(
+ " bbb ,ccc, ddd ,e , f=%bX1 #x3 test",
+ b3, 'b', 1, new String[] { "bbb ", "ccc", "ddd ", "e ", "f=" },
+ null,
+ "x3 test", null);
+
+ test.checkAdd(
+ " bbb ,ccc, ddd ,e , f= %bX3 #x3 test",
+ b3, 'b', 3, new String[] { "bbb ", "ccc ", "ddd ", "e ", "f= " },
+ null,
+ "x3 test", null);
+
+ test.checkAdd(
+ "-b,--bar %s{[\"john\",\"jerry\"),fred,\"harry\"} #sets bar",
+ sh, 's', 1, new String[] { "-b ", "--bar " },
+ new RngCheck[] {
+ new RngCheck("jerry", OPEN, "john", CLOSED),
+ new RngCheck("fred"),
+ new RngCheck("harry") },
+ "sets bar", null);
+
+ test.checkAdd(
+ "-c ,coven%f{0.0,9.0,(6,5],[-9.1,10.2]} ",
+ dh, 'f', 1, new String[] { "-c ", "coven" },
+ new RngCheck[] {
+ new RngCheck(0.0),
+ new RngCheck(9.0),
+ new RngCheck(5.0, CLOSED, 6.0, OPEN),
+ new RngCheck(-9.1, CLOSED, 10.2, CLOSED) },
+ "", null);
+
+ test.checkAdd(
+ "-b %b #a boolean value ",
+ bh, 'b', 1, new String[] { "-b " },
+ new RngCheck[] {},
+ "a boolean value ", null);
+
+ test.checkAdd("-a %i", ih, 'i', 1, "-a ", null, "", null);
+ test.checkAdd("-a %o", lh, 'o', 1, "-a ", null, "", null);
+ test.checkAdd("-a %d", i3, 'd', 1, "-a ", null, "", null);
+ test.checkAdd("-a %x", l3, 'x', 1, "-a ", null, "", null);
+ test.checkAdd("-a %c", ch, 'c', 1, "-a ", null, "", null);
+ test.checkAdd("-a %c", c3, 'c', 1, "-a ", null, "", null);
+ test.checkAdd("-a %v", bh, 'v', 1, "-a ", null, "", null);
+ test.checkAdd("-a %b", b3, 'b', 1, "-a ", null, "", null);
+ test.checkAdd("-a %f", fh, 'f', 1, "-a ", null, "", null);
+ test.checkAdd("-a %f", f3, 'f', 1, "-a ", null, "", null);
+ test.checkAdd("-a %f", dh, 'f', 1, "-a ", null, "", null);
+ test.checkAdd("-a %f", d3, 'f', 1, "-a ", null, "", null);
+
+ test.checkAdd("-a %i", fh, 'i', 1, "-a ", null, "",
+ "Invalid result holder for %i");
+ test.checkAdd("-a %c", i3, 'c', 1, "-a ", null, "",
+ "Invalid result holder for %c");
+ test.checkAdd("-a %v", d3, 'v', 1, "-a ", null, "",
+ "Invalid result holder for %v");
+ test.checkAdd("-a %f", sh, 'f', 1, "-a ", null, "",
+ "Invalid result holder for %f");
+ test.checkAdd("-a %s", l3, 's', 1, "-a ", null, "",
+ "Invalid result holder for %s");
+
+ test.checkAdd("-foo %i{} ", ih, 'i', 1, "-foo ", null, "", null);
+ test.checkAdd("-foo%i{}", ih, 'i', 1, "-foo", null, "", null);
+ test.checkAdd("-foo%i{ }", ih, 'i', 1, "-foo", null, "", null);
+ test.checkAdd("-foo%i{ }}", ih,
+ "Illegal character(s), expecting '#'");
+ test.checkAdd("-foo%i{ ", ih, "Unterminated range specification");
+ test.checkAdd("-foo%i{", ih, "Unterminated range specification");
+ test.checkAdd("-foo%i{0,9", ih, "Unterminated range specification");
+ test.checkAdd("-foo%i{1,2,3)", ih,
+ "Unterminated range specification");
+
+ test.checkAdd("-b %f{0.9}", fh, 'f', 1, "-b ",
+ new RngCheck[] { new RngCheck(0.9) },
+ "", null);
+ test.checkAdd("-b %f{ 0.9 ,7, -0.5,-4 ,6 }", fh, 'f', 1, "-b ",
+ new RngCheck[] { new RngCheck(0.9),
+ new RngCheck(7.0),
+ new RngCheck(-0.5),
+ new RngCheck(-4.0),
+ new RngCheck(6.0) },
+ "", null);
+ test.checkAdd("-b %f{ [0.9,7), (-0.5,-4),[9,6] , (10,13.4] }",
+ fh, 'f', 1, "-b ",
+ new RngCheck[] { new RngCheck(0.9, CLOSED, 7.0, OPEN),
+ new RngCheck(-4.0, OPEN, -.5, OPEN),
+ new RngCheck(6.0, CLOSED, 9.0, CLOSED),
+ new RngCheck(10.0, OPEN, 13.4, CLOSED),
+ },
+ "", null);
+ test.checkAdd("-b %f{(8 9]}", fh,
+ "Missing ',' in subrange specification");
+ test.checkAdd("-b %f{(8,9,]}", fh,
+ "Unterminated subrange");
+ test.checkAdd("-b %f{(8,9 ,]}", fh,
+ "Unterminated subrange");
+ test.checkAdd("-b %f{(8,9 8]}", fh,
+ "Unterminated subrange");
+ test.checkAdd("-b %f{8 9}", fh,
+ "Range spec: ',' or '}' expected");
+ test.checkAdd("-b %f{8 *}", fh,
+ "Range spec: ',' or '}' expected");
+
+ test.checkAdd("-b %f{8y}", fh,
+ "Range spec: ',' or '}' expected");
+ test.checkAdd("-b %f{.}", fh,
+ "Malformed float '.}' in range spec");
+ test.checkAdd("-b %f{1.0e}", fh,
+ "Malformed float '1.0e}' in range spec");
+ test.checkAdd("-b %f{[*]}", fh,
+ "Malformed float '*' in range spec");
+ test.checkAdd("-b %f{1.2e5t}", fh,
+ "Range spec: ',' or '}' expected");
+
+ test.checkAdd("-b %i{8}", ih, 'i', 1, "-b ",
+ new RngCheck[] { new RngCheck(8) },
+ "", null);
+ test.checkAdd("-b %i{8, 9,10 }", ih, 'i', 1, "-b ",
+ new RngCheck[] { new RngCheck(8),
+ new RngCheck(9),
+ new RngCheck(10) },
+ "", null);
+ test.checkAdd("-b %i{8, [-9,10),[-17,15],(2,-33),(8,9] }",
+ ih, 'i', 1, "-b ",
+ new RngCheck[] { new RngCheck(8),
+ new RngCheck(-9, CLOSED, 10, OPEN),
+ new RngCheck(-17, CLOSED, 15, CLOSED),
+ new RngCheck(-33, OPEN, 2, OPEN),
+ new RngCheck(8, OPEN, 9, CLOSED),
+ },
+ "", null);
+ test.checkAdd("-b %i{8.7}", ih,
+ "Range spec: ',' or '}' expected");
+ test.checkAdd("-b %i{6,[*]}", ih,
+ "Malformed integer '*' in range spec");
+ test.checkAdd("-b %i{g76}", ih,
+ "Malformed integer 'g' in range spec");
+
+ test.checkAdd("-b %s{foobar}", sh, 's', 1, "-b ",
+ new RngCheck[] { new RngCheck("foobar") },
+ "", null);
+ test.checkAdd("-b %s{foobar, 0x233,\" \"}", sh, 's', 1, "-b ",
+ new RngCheck[] { new RngCheck("foobar"),
+ new RngCheck("0x233"),
+ new RngCheck(" ") },
+ "", null);
+ test.checkAdd("-b %s{foobar,(bb,aa], [\"01\",02]}",
+ sh, 's', 1, "-b ",
+ new RngCheck[]
+ { new RngCheck("foobar"),
+ new RngCheck("aa", CLOSED, "bb", OPEN),
+ new RngCheck("01", CLOSED, "02", CLOSED),
+ },
+ "", null);
+
+ test.checkAdd("-b %c{'a'}", ch, 'c', 1, "-b ",
+ new RngCheck[] { new RngCheck('a') },
+ "", null);
+ test.checkAdd("-b %c{'\\n', '\\002', 'B'}", ch, 'c', 1, "-b ",
+ new RngCheck[] { new RngCheck('\n'),
+ new RngCheck('\002'),
+ new RngCheck('B') },
+ "", null);
+ test.checkAdd("-b %c{'q',('g','a'], ['\t','\\003']}",
+ ch, 'c', 1, "-b ",
+ new RngCheck[]
+ { new RngCheck('q'),
+ new RngCheck('a', CLOSED, 'g', OPEN),
+ new RngCheck('\003', CLOSED, '\t', CLOSED),
+ },
+ "", null);
+
+ test.checkAdd("-b %b{true}X2", b3, 'b', 2, "-b ",
+ new RngCheck[] { new RngCheck(true) },
+ "", null);
+ test.checkAdd("-b %b{ true , false, true }", bh, 'b', 1, "-b ",
+ new RngCheck[] { new RngCheck(true),
+ new RngCheck(false),
+ new RngCheck(true) },
+ "", null);
+ test.checkAdd("-b %v{true,[true,false)}", bh,
+ "Sub ranges not supported for %b or %v");
+ test.checkAdd("-b %v{true,[]}", bh,
+ "Sub ranges not supported for %b or %v");
+ test.checkAdd("-b %b{tru}", bh,
+ "Malformed boolean 'tru}' in range spec");
+
+ test.checkAdd("-b %iX2", i3, 'i', 2, "-b ", null, "", null);
+ test.checkAdd("-b %vX3", b3, 'v', 3, "-b ", null, "", null);
+ test.checkAdd("-b %v{ }X3", b3, 'v', 3, "-b ", null, "", null);
+
+ test.checkAdd("-b=%iX2", i3, 'i', 2, "-b", null, "",
+ "Multiplier value incompatible with one word option -b=");
+ test.checkAdd("-b %iX0", i3, 'i', 0, "-b ", null, "",
+ "Value multiplier number must be > 0");
+ test.checkAdd("-b %iX-6", i3, 'i', 0, "-b ", null, "",
+ "Value multiplier number must be > 0");
+ test.checkAdd("-b %iXy", i3, 'i', 0, "-b ", null, "",
+ "Malformed value multiplier");
+ test.checkAdd("-b %iX4", i3, 'i', 4, "-b ", null, "",
+ "Result holder array must have a length >= 4");
+ test.checkAdd("-b %iX4", ih, 'i', 4, "-b ", null, "",
+ "Multiplier requires result holder to be an array of length >= 4");
+
+ test.checkAdd("-b %i #X4", ih, 'i', 1, "-b ", null, "X4", null);
+ test.checkAdd("-b %i #[}X4", ih, 'i', 1, "-b ", null, "[}X4", null);
+
+ // test.checkPrintHelp("");
+ // test.checkPrintUsage("");
+
+ test = new ArgParserTest();
+
+ test.checkAdd(
+ "-intarg %i{1,2,(9,18],[22,27],[33,38),(45,48)} #test int arg",
+ ih, 'i', 1, "-intarg ",
+ new RngCheck[]
+ { new RngCheck(1),
+ new RngCheck(2),
+ new RngCheck(9, OPEN, 18, CLOSED),
+ new RngCheck(22, CLOSED, 27, CLOSED),
+ new RngCheck(33, CLOSED, 38, OPEN),
+ new RngCheck(45, OPEN, 48, OPEN),
+ },
+ "test int arg", null);
+
+ MTest[] tests;
+
+ tests = new MTest[]
+ {
+ new MTest("-intarg 1", new Long(1)),
+ new MTest("-intarg 3", new MErr('r', "3")),
+ new MTest("-intarg 9", new MErr('r', "9")),
+ new MTest("-intarg 11", new Long(11)),
+ new MTest("-intarg 18", new Long(18)),
+ new MTest("-intarg 22", new Long(22)),
+ new MTest("-intarg 25", new Long(25)),
+ new MTest("-intarg 27", new Long(27)),
+ new MTest("-intarg 33", new Long(33)),
+ new MTest("-intarg 35", new Long(35)),
+ new MTest("-intarg 38", new MErr('r', "38")),
+ new MTest("-intarg 45", new MErr('r', "45")),
+ new MTest("-intarg 46", new Long(46)),
+ new MTest("-intarg 48", new MErr('r', "48")),
+ new MTest("-intarg 100", new MErr('r', "100")),
+ new MTest("-intarg 0xbeef", new MErr('r', "0xbeef")),
+ new MTest("-intarg 0x2f", new Long(0x2f)),
+ new MTest("-intarg 041", new Long(041)),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd(
+ "-farg %f{1,2,(9,18],[22,27],[33,38),(45,48)} #test float arg",
+ dh, 'f', 1, "-farg ",
+ new RngCheck[]
+ {
+ new RngCheck(1.0),
+ new RngCheck(2.0),
+ new RngCheck(9.0, OPEN, 18.0, CLOSED),
+ new RngCheck(22.0, CLOSED, 27.0, CLOSED),
+ new RngCheck(33.0, CLOSED, 38.0, OPEN),
+ new RngCheck(45.0, OPEN, 48.0, OPEN),
+ },
+ "test float arg", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-farg 1", new Double(1)),
+ new MTest("-farg 3", new MErr('r', "3")),
+ new MTest("-farg 9", new MErr('r', "9")),
+ new MTest("-farg 9.0001", new Double(9.0001)),
+ new MTest("-farg 11", new Double(11)),
+ new MTest("-farg 18", new Double(18)),
+ new MTest("-farg 22", new Double(22)),
+ new MTest("-farg 25", new Double(25)),
+ new MTest("-farg 27", new Double(27)),
+ new MTest("-farg 33", new Double(33)),
+ new MTest("-farg 35", new Double(35)),
+ new MTest("-farg 37.9999", new Double(37.9999)),
+ new MTest("-farg 38", new MErr('r', "38")),
+ new MTest("-farg 45", new MErr('r', "45")),
+ new MTest("-farg 45.0001", new Double(45.0001)),
+ new MTest("-farg 46", new Double(46)),
+ new MTest("-farg 47.9999", new Double(47.9999)),
+ new MTest("-farg 48", new MErr('r', "48")),
+ new MTest("-farg 100", new MErr('r', "100")),
+ new MTest("-farg 0", new MErr('r', "0")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd(
+ "-sarg %s{1,2,(AA,AZ],[BB,BX],[C3,C8),(d5,d8)} #test string arg",
+ s3, 's', 1, "-sarg ",
+ new RngCheck[]
+ { new RngCheck("1"),
+ new RngCheck("2"),
+ new RngCheck("AA", OPEN, "AZ", CLOSED),
+ new RngCheck("BB", CLOSED, "BX", CLOSED),
+ new RngCheck("C3", CLOSED, "C8", OPEN),
+ new RngCheck("d5", OPEN, "d8", OPEN),
+ },
+ "test string arg", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-sarg 1", "1"),
+ new MTest("-sarg 3", new MErr('r', "3")),
+ new MTest("-sarg AA", new MErr('r', "AA")),
+ new MTest("-sarg AM", "AM"),
+ new MTest("-sarg AZ", "AZ"),
+ new MTest("-sarg BB", "BB"),
+ new MTest("-sarg BL", "BL"),
+ new MTest("-sarg BX", "BX"),
+ new MTest("-sarg C3", "C3"),
+ new MTest("-sarg C6", "C6"),
+ new MTest("-sarg C8", new MErr('r', "C8")),
+ new MTest("-sarg d5", new MErr('r', "d5")),
+ new MTest("-sarg d6", "d6"),
+ new MTest("-sarg d8", new MErr('r', "d8")),
+ new MTest("-sarg zzz", new MErr('r', "zzz")),
+ new MTest("-sarg 0", new MErr('r', "0")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test = new ArgParserTest();
+
+ test.checkAdd(
+ "-carg %c{1,2,(a,z],['A','Z'],['\\001',\\007),(4,8)}",
+ c3, 'c', 1, "-carg ",
+ new RngCheck[]
+ { new RngCheck('1'),
+ new RngCheck('2'),
+ new RngCheck('a', OPEN, 'z', CLOSED),
+ new RngCheck('A', CLOSED, 'Z', CLOSED),
+ new RngCheck('\001', CLOSED, '\007', OPEN),
+ new RngCheck('4', OPEN, '8', OPEN),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-carg 1", new Character('1')),
+ new MTest("-carg 3", new MErr('r', "3")),
+ new MTest("-carg a", new MErr('r', "a")),
+ new MTest("-carg m", new Character('m')),
+ new MTest("-carg z", new Character('z')),
+ new MTest("-carg A", new Character('A')),
+ new MTest("-carg 'L'", new Character('L')),
+ new MTest("-carg 'Z'", new Character('Z')),
+ new MTest("-carg \\001", new Character('\001')),
+ new MTest("-carg \\005", new Character('\005')),
+ new MTest("-carg '\\007'", new MErr('r', "'\\007'")),
+ new MTest("-carg '4'", new MErr('r', "'4'")),
+ new MTest("-carg 6", new Character('6')),
+ new MTest("-carg 8", new MErr('r', "8")),
+ new MTest("-carg '\\012'", new MErr('r', "'\\012'")),
+ new MTest("-carg 0", new MErr('r', "0")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd(
+ "-foo=%i{[-50,100]}", ih, 'i', 1, "-foo=",
+ new RngCheck[]
+ { new RngCheck(-50, CLOSED, 100, CLOSED),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-foo=-51", new MErr('r', "-51")),
+ new MTest("-foo=-0x32", new Long(-0x32)),
+ new MTest("-foo=-0x33", new MErr('r', "-0x33")),
+ new MTest("-foo=-0777", new MErr('r', "-0777")),
+ new MTest("-foo=-07", new Long(-07)),
+ new MTest("-foo=0", new Long(0)),
+ new MTest("-foo=100", new Long(100)),
+ new MTest("-foo=0x5e", new Long(0x5e)),
+ new MTest("-foo=066", new Long(066)),
+ new MTest("-foo=06677", new MErr('r', "06677")),
+ new MTest("-foo=0xbeef", new MErr('r', "0xbeef")),
+ new MTest("-foo=foo", new MErr('m', "foo")),
+ new MTest("-foo=-51d", new MErr('m', "-51d")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-foo2=%i", ih, 'i', 1, "-foo2=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-foo2=-51", new Long(-51)),
+ new MTest("-foo2=-0x33", new Long(-0x33)),
+ new MTest("-foo2=-0777", new Long(-0777)),
+ new MTest("-foo2=06677", new Long(06677)),
+ new MTest("-foo2=0xbeef", new Long(0xbeef)),
+ new MTest("-foo2=foo", new MErr('m', "foo")),
+ new MTest("-foo2=-51d", new MErr('m', "-51d")),
+ new MTest("-foo2=-51", new Long(-51)),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-foo3 %iX3", i3, 'i', 3, "-foo3 ", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-foo3 -51 678 0x45",
+ new long[] { -51, 678, 0x45 }),
+ new MTest("-foo3 55 16f 55", new MErr('m', "16f")),
+ new MTest("-foo3 55 16", new MErr('v', "3")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ Vector<String> vec = new Vector<String>(100);
+
+ test.checkAdd("-foov3 %iX3", vec, 'i', 3, "-foov3 ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-foov3 -1 2 4", new long[] { -1, 2, 4 }, 0),
+ new MTest("-foov3 10 3 9", new long[] { 10, 3, 9 }, 1),
+ new MTest("-foov3 123 1 0", new long[] { 123, 1, 0 }, 2),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+ test.checkAdd("-foov %i", vec, 'i', 1, "-foov ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-foov 11", new Long(11), 0),
+ new MTest("-foov 12", new Long(12), 1),
+ new MTest("-foov 13", new Long(13), 2),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd(
+ "-foo4 %i{[-50,100]}X2", i3, 'i', 2, "-foo4 ",
+ new RngCheck[]
+ { new RngCheck(-50, CLOSED, 100, CLOSED),
+ },
+ "", null);
+ tests = new MTest[]
+ {
+ new MTest("-foo4 -49 78",
+ new long[] { -49, 78 }),
+ new MTest("-foo4 -48 102", new MErr('r', "102")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd(
+ "-oct=%o{[-062,0144]}", ih, 'o', 1, "-oct=",
+ new RngCheck[]
+ { new RngCheck(-50, CLOSED, 100, CLOSED),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-oct=-063", new MErr('r', "-063")),
+ new MTest("-oct=-0x32", new MErr('m', "-0x32")),
+ new MTest("-oct=-0777", new MErr('r', "-0777")),
+ new MTest("-oct=-07", new Long(-07)),
+ new MTest("-oct=0", new Long(0)),
+ new MTest("-oct=100", new Long(64)),
+ new MTest("-oct=0xae", new MErr('m', "0xae")),
+ new MTest("-oct=66", new Long(066)),
+ new MTest("-oct=06677", new MErr('r', "06677")),
+ new MTest("-oct=0xbeef", new MErr('m', "0xbeef")),
+ new MTest("-oct=foo", new MErr('m', "foo")),
+ new MTest("-oct=-51d", new MErr('m', "-51d")),
+ new MTest("-oct=78", new MErr('m', "78")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-oct2=%o", ih, 'o', 1, "-oct2=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-oct2=-063", new Long(-063)),
+ new MTest("-oct2=-0777", new Long(-0777)),
+ new MTest("-oct2=06677", new Long(06677)),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd(
+ "-dec=%d{[-0x32,0x64]}", ih, 'd', 1, "-dec=",
+ new RngCheck[]
+ { new RngCheck(-50, CLOSED, 100, CLOSED),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-dec=-063", new MErr('r', "-063")),
+ new MTest("-dec=-0x32", new MErr('m', "-0x32")),
+ new MTest("-dec=-0777", new MErr('r', "-0777")),
+ new MTest("-dec=-07", new Long(-07)),
+ new MTest("-dec=0", new Long(0)),
+ new MTest("-dec=100", new Long(100)),
+ new MTest("-dec=0xae", new MErr('m', "0xae")),
+ new MTest("-dec=66", new Long(66)),
+ new MTest("-dec=06677", new MErr('r', "06677")),
+ new MTest("-dec=0xbeef", new MErr('m', "0xbeef")),
+ new MTest("-dec=foo", new MErr('m', "foo")),
+ new MTest("-dec=-51d", new MErr('m', "-51d")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-dec2=%d", ih, 'd', 1, "-dec2=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-dec2=-063", new Long(-63)),
+ new MTest("-dec2=-0777", new Long(-777)),
+ new MTest("-dec2=06677", new Long(6677)),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd(
+ "-hex=%x{[-0x32,0x64]}", ih, 'x', 1, "-hex=",
+ new RngCheck[]
+ { new RngCheck(-50, CLOSED, 100, CLOSED),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-hex=-06", new Long(-0x6)),
+ new MTest("-hex=-0x3g2", new MErr('m', "-0x3g2")),
+ new MTest("-hex=-0777", new MErr('r', "-0777")),
+ new MTest("-hex=-017", new Long(-0x17)),
+ new MTest("-hex=0", new Long(0)),
+ new MTest("-hex=64", new Long(0x64)),
+ new MTest("-hex=5e", new Long(0x5e)),
+ new MTest("-hex=66", new MErr('r', "66")),
+ new MTest("-hex=06677", new MErr('r', "06677")),
+ new MTest("-hex=0xbeef", new MErr('m', "0xbeef")),
+ new MTest("-hex=foo", new MErr('m', "foo")),
+ new MTest("-hex=-51d", new MErr('r', "-51d")),
+ new MTest("-hex=-51g", new MErr('m', "-51g")),
+ new MTest("-hex=", new MErr('c', "")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-hex2=%x", ih, 'x', 1, "-hex2=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-hex2=-0777", new Long(-0x777)),
+ new MTest("-hex2=66", new Long(0x66)),
+ new MTest("-hex2=06677", new Long(0x6677)),
+ new MTest("-hex2=-51d", new Long(-0x51d)),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd(
+ "-char=%c{['b','m']}", ch, 'c', 1, "-char=",
+ new RngCheck[]
+ { new RngCheck('b', CLOSED, 'm', CLOSED),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-char=a", new MErr('r', "a")),
+ new MTest("-char=b", new Character('b')),
+ new MTest("-char='b'", new Character('b')),
+ new MTest("-char='\142'", new Character('b')),
+ new MTest("-char='\141'", new MErr('r', "'\141'")),
+ new MTest("-char=\142", new Character('b')),
+ new MTest("-char=\141", new MErr('r', "\141")),
+ new MTest("-char=m", new Character('m')),
+ new MTest("-char=z", new MErr('r', "z")),
+ new MTest("-char=bb", new MErr('m', "bb")),
+ new MTest("-char='b", new MErr('m', "'b")),
+ new MTest("-char='", new MErr('m', "'")),
+ new MTest("-char=a'", new MErr('m', "a'")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-char2=%c", ch, 'c', 1, "-char2=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-char2=a", new Character('a')),
+ new MTest("-char2='\141'", new Character('\141')),
+ new MTest("-char2=\141", new Character('\141')),
+ new MTest("-char2=z", new Character('z')),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-charv3 %cX3", vec, 'c', 3, "-charv3 ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-charv3 a b c", new char[] { 'a', 'b', 'c' }, 0),
+ new MTest("-charv3 'g' f '\\n'", new char[] { 'g', 'f', '\n' }, 1),
+ new MTest("-charv3 1 \001 3", new char[] { '1', '\001', '3' }, 2),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+ test.checkAdd("-charv=%c", vec, 'c', 1, "-charv=", null, "", null);
+ tests = new MTest[]
+ { new MTest("-charv=d", new Character('d'), 0),
+ new MTest("-charv='g'", new Character('g'), 1),
+ new MTest("-charv=\111", new Character('\111'), 2),
+ };
+ vec.clear();
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd(
+ "-bool=%b{true}", bh, 'b', 1, "-bool=",
+ new RngCheck[]
+ { new RngCheck(true),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-bool=true", new Boolean(true)),
+ new MTest("-bool=false", new MErr('r', "false")),
+ new MTest("-bool=fals", new MErr('m', "fals")),
+ new MTest("-bool=falsem", new MErr('m', "falsem")),
+ new MTest("-bool=truex", new MErr('m', "truex")),
+ new MTest("-bool=foo", new MErr('m', "foo")),
+ new MTest("-bool=1", new MErr('m', "1")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd(
+ "-boo2=%b{true,false}", bh, 'b', 1, "-boo2=",
+ new RngCheck[]
+ { new RngCheck(true),
+ new RngCheck(false),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-boo2=true", new Boolean(true)),
+ new MTest("-boo2=false", new Boolean(false)),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-boo3=%b", bh, 'b', 1, "-boo3=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-boo3=true", new Boolean(true)),
+ new MTest("-boo3=false", new Boolean(false)),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-boo3 %bX3", b3, 'b', 3, "-boo3 ", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-boo3 true false true",
+ new boolean[] { true, false, true }),
+ new MTest("-boo3 true fals true", new MErr('m', "fals")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd("-boov3 %bX3", vec, 'b', 3, "-boov3 ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-boov3 true true false",
+ new boolean[] { true, true, false }, 0),
+ new MTest("-boov3 false false true",
+ new boolean[] { false, false, true }, 1),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+ test.checkAdd("-boov %b", vec, 'b', 1, "-boov ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-boov true", new Boolean(true), 0),
+ new MTest("-boov false", new Boolean(false), 1),
+ new MTest("-boov true", new Boolean(true), 2),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd("-v3 %vX2", b3, 'v', 2, "-v3 ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-v3", new boolean[] { true, true }),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd(
+ "-vf %v{false,true}X2", b3, 'v', 2, "-vf ",
+ new RngCheck[]
+ { new RngCheck(false),
+ new RngCheck(true),
+ },
+ "", null);
+ tests = new MTest[]
+ { new MTest("-vf", new boolean[] { false, false }),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd(
+ "-str=%s{(john,zzzz]}", sh, 's', 1, "-str=",
+ new RngCheck[]
+ { new RngCheck("john", OPEN, "zzzz", CLOSED),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-str=john", new MErr('r', "john")),
+ new MTest("-str=joho ", "joho "),
+ new MTest("-str=joho ", "joho "),
+ new MTest("-str=zzzz", "zzzz"),
+ new MTest("-str= joho", new MErr('r', " joho")),
+ new MTest("-str=jnhn ", new MErr('r', "jnhn ")),
+ new MTest("-str=zzzzz", new MErr('r', "zzzzz")),
+ new MTest("-str=\"joho\"", new MErr('r', "\"joho\"")),
+ new MTest("-str=\"joho", new MErr('r', "\"joho")),
+ new MTest("-str=joho j", "joho j"), // new MErr('m', "joho j")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-str2=%s", sh, 's', 1, "-str2=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-str2= jnhn", " jnhn"),
+ new MTest("-str2=zzzzz", "zzzzz"),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-str3 %sX3", s3, 's', 3, "-str3 ", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-str3 foo bar johnny",
+ new String[] { "foo", "bar", "johnny" }),
+ new MTest("-str3 zzzzz \"bad foo",
+ new String[] { "zzzzz", "\"bad", "foo"
+ }), // new MErr('m', "\"bad")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd("-strv3 %sX3", vec, 's', 3, "-strv3 ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-strv3 foo bar \"hihi\"",
+ new String[] { "foo", "bar", "\"hihi\"" }, 0),
+ new MTest("-strv3 a 123 gg",
+ new String[] { "a", "123", "gg" }, 1),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+ test.checkAdd("-strv=%s", vec, 's', 1, "-strv=", null, "", null);
+ tests = new MTest[]
+ { new MTest("-strv=d", "d", 0),
+ new MTest("-strv='g'", "'g'", 1),
+ new MTest("-strv=\\111", "\\111", 2),
+ };
+ vec.clear();
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd(
+ "-float=%f{(-0.001,1000.0]}", dh, 'f', 1, "-float=",
+ new RngCheck[]
+ { new RngCheck(-0.001, OPEN, 1000.0, CLOSED),
+ },
+ "", null);
+
+ tests = new MTest[]
+ {
+ new MTest("-float=-0.000999", new Double(-0.000999)),
+ new MTest("-float=1e-3", new Double(0.001)),
+ new MTest("-float=12.33e1", new Double(123.3)),
+ new MTest("-float=1e3", new Double(1e3)),
+ new MTest("-float=1000.000", new Double(1000.0)),
+ new MTest("-float=-0.001", new MErr('r', "-0.001")),
+ new MTest("-float=-1e-3", new MErr('r', "-1e-3")),
+ new MTest("-float=1000.001", new MErr('r', "1000.001")),
+ new MTest("-float=.", new MErr('m', ".")),
+ new MTest("-float= 124.5 ", new Double(124.5)),
+ new MTest("-float=124.5x", new MErr('m', "124.5x")),
+ new MTest("-float= foo ", new MErr('m', " foo ")),
+ new MTest("-float=1e1", new Double(10)),
+ new MTest("-float=1e ", new MErr('m', "1e ")),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-float2=%f", dh, 'f', 1, "-float2=", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-float2=-0.001", new Double(-0.001)),
+ new MTest("-float2=-1e-3", new Double(-1e-3)),
+ new MTest("-float2=1000.001", new Double(1000.001)),
+ };
+ test.checkMatches(tests, ONE_WORD);
+
+ test.checkAdd("-f3 %fX3", d3, 'f', 3, "-f3 ", null, "", null);
+ tests = new MTest[]
+ {
+ new MTest("-f3 -0.001 1.23e5 -9.88e-4",
+ new double[] { -0.001, 1.23e5, -9.88e-4 }),
+ new MTest("-f3 7.88 foo 9.0", new MErr('m', "foo")),
+ new MTest("-f3 7.88 . 9.0", new MErr('m', ".")),
+ new MTest("-f3 7.88 3.0 9.0x", new MErr('m', "9.0x")),
+ };
+ test.checkMatches(tests, MULTI_WORD);
+
+ test.checkAdd("-fv3 %fX3", vec, 'f', 3, "-fv3 ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-fv3 1.0 3.444 6.7",
+ new double[] { 1.0, 3.444, 6.7 }, 0),
+ new MTest("-fv3 13e-5 145.678 0.0001e45",
+ new double[] { 13e-5, 145.678, 0.0001e45 }, 1),
+ new MTest("-fv3 11.11 3.1245 -1e-4",
+ new double[] { 11.11, 3.1245, -1e-4 }, 2),
+ new MTest("-fv3 1.0 2 3",
+ new double[] { 1.0, 2.0, 3.0 }, 3),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+ test.checkAdd("-fv %f", vec, 'f', 1, "-fv ", null, "", null);
+ tests = new MTest[]
+ { new MTest("-fv -15.1234", new Double(-15.1234), 0),
+ new MTest("-fv -1.234e-7", new Double(-1.234e-7), 1),
+ new MTest("-fv 0.001111", new Double(0.001111), 2),
+ };
+ vec.clear();
+ test.checkMatches(tests, MULTI_WORD);
+
+ IntHolder intHolder = new IntHolder();
+ StringHolder strHolder = new StringHolder();
+
+ ArgParser parser = new ArgParser("test");
+ parser.addOption("-foo %d #an int", intHolder);
+ parser.addOption("-bar %s #a string", strHolder);
+ args = new String[]
+ { "zzz", "-cat", "-foo", "123", "yyy", "-bar", "xxxx", "xxx"
+ };
+
+ String[] unmatchedCheck = new String[]
+ { "zzz", "-cat", "yyy", "xxx"
+ };
+
+ String[] unmatched = parser.matchAllArgs(args, 0, 0);
+ test.checkStringArray(
+ "Unmatched args:", unmatched, unmatchedCheck);
+
+ vec.clear();
+ for (int i = 0; i < args.length;) {
+ try {
+ i = parser.matchArg(args, i);
+ if (parser.getUnmatchedArgument() != null) {
+ vec.add(parser.getUnmatchedArgument());
+ }
+ } catch (Exception e) {
+ }
+ }
+ unmatched = (String[]) vec.toArray(new String[0]);
+ test.checkStringArray(
+ "My unmatched args:", unmatched, unmatchedCheck);
+
+ System.out.println("\nPassed\n");
+
+ }
}
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/BooleanHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/BooleanHolder.java
index c5dece11..ba10022b 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/BooleanHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/BooleanHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,37 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' a boolean value,
- * enabling methods to return boolean values through
- * arguments.
- */
-public class BooleanHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' a boolean value,
+ * enabling methods to return boolean values through
+ * arguments.
+ */
+public class BooleanHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = -2863748864787121510L;
/**
- * Value of the boolean, set and examined
- * by the application as needed.
- */
- public boolean value;
+ * Value of the boolean, set and examined
+ * by the application as needed.
+ */
+ public boolean value;
- /**
- * Constructs a new <code>BooleanHolder</code> with an initial
- * value of <code>false</code>.
- */
- public BooleanHolder ()
- { value = false;
- }
+ /**
+ * Constructs a new <code>BooleanHolder</code> with an initial
+ * value of <code>false</code>.
+ */
+ public BooleanHolder() {
+ value = false;
+ }
- /**
- * Constructs a new <code>BooleanHolder</code> with a
- * specific initial value.
- *
- * @param b Initial boolean value.
- */
- public BooleanHolder (boolean b)
- { value = b;
- }
+ /**
+ * Constructs a new <code>BooleanHolder</code> with a
+ * specific initial value.
+ *
+ * @param b Initial boolean value.
+ */
+ public BooleanHolder(boolean b) {
+ value = b;
+ }
}
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/CharHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/CharHolder.java
index b30259b4..453cac8b 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/CharHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/CharHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,39 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' a character value,
- * enabling methods to return character values through
- * arguments.
- */
-public class CharHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' a character value,
+ * enabling methods to return character values through
+ * arguments.
+ */
+public class CharHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = 7340010668929015745L;
/**
- * Value of the character, set and examined
- * by the application as needed.
- */
- public char value;
+ * Value of the character, set and examined
+ * by the application as needed.
+ */
+ public char value;
- /**
- * Constructs a new <code>CharHolder</code> with an initial
- * value of 0.
- */
- public CharHolder ()
- { value = 0;
- }
+ /**
+ * Constructs a new <code>CharHolder</code> with an initial
+ * value of 0.
+ */
+ public CharHolder() {
+ value = 0;
+ }
- /**
- * Constructs a new <code>CharHolder</code> with a
- * specific initial value.
- *
- * @param c Initial character value.
- */
- public CharHolder (char c)
- { value = c;
- }
+ /**
+ * Constructs a new <code>CharHolder</code> with a
+ * specific initial value.
+ *
+ * @param c Initial character value.
+ */
+ public CharHolder(char c) {
+ value = c;
+ }
}
-
-
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/DoubleHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/DoubleHolder.java
index 293a9cc7..13012a64 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/DoubleHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/DoubleHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,38 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' a double value,
- * enabling methods to return double values through
- * arguments.
- */
-public class DoubleHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' a double value,
+ * enabling methods to return double values through
+ * arguments.
+ */
+public class DoubleHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = 5461991811517552431L;
/**
- * Value of the double, set and examined
- * by the application as needed.
- */
- public double value;
+ * Value of the double, set and examined
+ * by the application as needed.
+ */
+ public double value;
- /**
- * Constructs a new <code>DoubleHolder</code> with an initial
- * value of 0.
- */
- public DoubleHolder ()
- { value = 0;
- }
+ /**
+ * Constructs a new <code>DoubleHolder</code> with an initial
+ * value of 0.
+ */
+ public DoubleHolder() {
+ value = 0;
+ }
- /**
- * Constructs a new <code>DoubleHolder</code> with a
- * specific initial value.
- *
- * @param d Initial double value.
- */
- public DoubleHolder (double d)
- { value = d;
- }
+ /**
+ * Constructs a new <code>DoubleHolder</code> with a
+ * specific initial value.
+ *
+ * @param d Initial double value.
+ */
+ public DoubleHolder(double d) {
+ value = d;
+ }
}
-
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/FloatHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/FloatHolder.java
index 0fbcc45a..b8474b53 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/FloatHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/FloatHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,39 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' a float value,
- * enabling methods to return float values through
- * arguments.
- */
-public class FloatHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' a float value,
+ * enabling methods to return float values through
+ * arguments.
+ */
+public class FloatHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = -7962968109874934361L;
/**
- * Value of the float, set and examined
- * by the application as needed.
- */
- public float value;
+ * Value of the float, set and examined
+ * by the application as needed.
+ */
+ public float value;
- /**
- * Constructs a new <code>FloatHolder</code> with an initial
- * value of 0.
- */
- public FloatHolder ()
- { value = 0;
- }
+ /**
+ * Constructs a new <code>FloatHolder</code> with an initial
+ * value of 0.
+ */
+ public FloatHolder() {
+ value = 0;
+ }
- /**
- * Constructs a new <code>FloatHolder</code> with a
- * specific initial value.
- *
- * @param f Initial float value.
- */
- public FloatHolder (float f)
- { value = f;
- }
+ /**
+ * Constructs a new <code>FloatHolder</code> with a
+ * specific initial value.
+ *
+ * @param f Initial float value.
+ */
+ public FloatHolder(float f) {
+ value = f;
+ }
}
-
-
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/IntHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/IntHolder.java
index efd6d1bf..a94ceea1 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/IntHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/IntHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,38 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' an integer value,
- * enabling methods to return integer values through
- * arguments.
- */
-public class IntHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' an integer value,
+ * enabling methods to return integer values through
+ * arguments.
+ */
+public class IntHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = -5303361328570056819L;
/**
- * Value of the integer, set and examined
- * by the application as needed.
- */
- public int value;
+ * Value of the integer, set and examined
+ * by the application as needed.
+ */
+ public int value;
- /**
- * Constructs a new <code>IntHolder</code> with an initial
- * value of 0.
- */
- public IntHolder ()
- { value = 0;
- }
+ /**
+ * Constructs a new <code>IntHolder</code> with an initial
+ * value of 0.
+ */
+ public IntHolder() {
+ value = 0;
+ }
- /**
- * Constructs a new <code>IntHolder</code> with a
- * specific initial value.
- *
- * @param i Initial integer value.
- */
- public IntHolder (int i)
- { value = i;
- }
+ /**
+ * Constructs a new <code>IntHolder</code> with a
+ * specific initial value.
+ *
+ * @param i Initial integer value.
+ */
+ public IntHolder(int i) {
+ value = i;
+ }
}
-
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/LongHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/LongHolder.java
index 84752d60..5656d8b8 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/LongHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/LongHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,38 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' a long value,
- * enabling methods to return long values through
- * arguments.
- */
-public class LongHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' a long value,
+ * enabling methods to return long values through
+ * arguments.
+ */
+public class LongHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = 1559599139421340971L;
/**
- * Value of the long, set and examined
- * by the application as needed.
- */
- public long value;
+ * Value of the long, set and examined
+ * by the application as needed.
+ */
+ public long value;
- /**
- * Constructs a new <code>LongHolder</code> with an initial
- * value of 0.
- */
- public LongHolder ()
- { value = 0;
- }
+ /**
+ * Constructs a new <code>LongHolder</code> with an initial
+ * value of 0.
+ */
+ public LongHolder() {
+ value = 0;
+ }
- /**
- * Constructs a new <code>LongHolder</code> with a
- * specific initial value.
- *
- * @param l Initial long value.
- */
- public LongHolder (long l)
- { value = l;
- }
+ /**
+ * Constructs a new <code>LongHolder</code> with a
+ * specific initial value.
+ *
+ * @param l Initial long value.
+ */
+ public LongHolder(long l) {
+ value = l;
+ }
}
-
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/ObjectHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/ObjectHolder.java
index cc8361d9..70e050fd 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/ObjectHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/ObjectHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,37 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' an Object reference,
- * enabling methods to return Object references through
- * arguments.
- */
-public class ObjectHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' an Object reference,
+ * enabling methods to return Object references through
+ * arguments.
+ */
+public class ObjectHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = 1825881254530066307L;
/**
- * Value of the Object reference, set and examined
- * by the application as needed.
- */
- public Object value;
+ * Value of the Object reference, set and examined
+ * by the application as needed.
+ */
+ public Object value;
- /**
- * Constructs a new <code>ObjectHolder</code> with an initial
- * value of <code>null</code>.
- */
- public ObjectHolder ()
- { value = null;
- }
+ /**
+ * Constructs a new <code>ObjectHolder</code> with an initial
+ * value of <code>null</code>.
+ */
+ public ObjectHolder() {
+ value = null;
+ }
- /**
- * Constructs a new <code>ObjectHolder</code> with a
- * specific initial value.
- *
- * @param o Initial Object reference.
- */
- public ObjectHolder (Object o)
- { value = o;
- }
+ /**
+ * Constructs a new <code>ObjectHolder</code> with a
+ * specific initial value.
+ *
+ * @param o Initial Object reference.
+ */
+ public ObjectHolder(Object o) {
+ value = o;
+ }
}
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/SimpleExample.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/SimpleExample.java
index 8086131b..6970d318 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/SimpleExample.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/SimpleExample.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,39 +19,35 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Gives a very simple example of the use of
- * {@link argparser.ArgParser ArgParser}.
+ * Gives a very simple example of the use of {@link argparser.ArgParser ArgParser}.
*/
-public class SimpleExample
-{
- /**
- * Run this to invoke command line parsing.
- */
- public static void main (String[] args)
- {
- // create holder objects for storing results ...
-
- DoubleHolder theta = new DoubleHolder();
- StringHolder fileName = new StringHolder();
- BooleanHolder debug = new BooleanHolder();
-
- // create the parser and specify the allowed options ...
-
- ArgParser parser = new ArgParser("java argparser.SimpleExample");
- parser.addOption ("-theta %f #theta value (in degrees)", theta);
- parser.addOption ("-file %s #name of the operating file", fileName);
- parser.addOption ("-debug %v #enables display of debugging info",
- debug);
-
- // and then match the arguments
-
- parser.matchAllArgs (args);
-
- // now print out the values
-
- System.out.println ("theta=" + theta.value);
- System.out.println ("fileName=" + fileName.value);
- System.out.println ("debug=" + debug.value);
- }
-}
+public class SimpleExample {
+ /**
+ * Run this to invoke command line parsing.
+ */
+ public static void main(String[] args) {
+ // create holder objects for storing results ...
+
+ DoubleHolder theta = new DoubleHolder();
+ StringHolder fileName = new StringHolder();
+ BooleanHolder debug = new BooleanHolder();
+
+ // create the parser and specify the allowed options ...
+
+ ArgParser parser = new ArgParser("java argparser.SimpleExample");
+ parser.addOption("-theta %f #theta value (in degrees)", theta);
+ parser.addOption("-file %s #name of the operating file", fileName);
+ parser.addOption("-debug %v #enables display of debugging info",
+ debug);
+ // and then match the arguments
+
+ parser.matchAllArgs(args);
+
+ // now print out the values
+
+ System.out.println("theta=" + theta.value);
+ System.out.println("fileName=" + fileName.value);
+ System.out.println("debug=" + debug.value);
+ }
+}
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/StringHolder.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/StringHolder.java
index 9b41b6a2..93736034 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/StringHolder.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/StringHolder.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,38 +19,36 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Wrapper class which ``holds'' a String reference,
- * enabling methods to return String references through
- * arguments.
- */
-public class StringHolder implements java.io.Serializable
-{
- /**
+ * Wrapper class which ``holds'' a String reference,
+ * enabling methods to return String references through
+ * arguments.
+ */
+public class StringHolder implements java.io.Serializable {
+ /**
*
*/
private static final long serialVersionUID = -3184348746223759310L;
/**
- * Value of the String reference, set and examined
- * by the application as needed.
- */
- public String value;
+ * Value of the String reference, set and examined
+ * by the application as needed.
+ */
+ public String value;
- /**
- * Constructs a new <code>StringHolder</code> with an
- * initial value of <code>null</code>.
- */
- public StringHolder ()
- { value = null;
- }
+ /**
+ * Constructs a new <code>StringHolder</code> with an
+ * initial value of <code>null</code>.
+ */
+ public StringHolder() {
+ value = null;
+ }
- /**
- * Constructs a new <code>StringHolder</code> with a
- * specific initial value.
- *
- * @param s Initial String reference.
- */
- public StringHolder (String s)
- { value = s;
- }
+ /**
+ * Constructs a new <code>StringHolder</code> with a
+ * specific initial value.
+ *
+ * @param s Initial String reference.
+ */
+ public StringHolder(String s) {
+ value = s;
+ }
}
-
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanException.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanException.java
index 4b71a0f2..bf3ea6dc 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanException.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanException.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -19,40 +20,37 @@ package com.netscape.pkisilent.argparser;
import java.io.IOException;
-/**
- * Exception class used by <code>StringScanner</code> when
- * command line arguments do not parse correctly.
- *
- * @author John E. Lloyd, Winter 2001
- * @see StringScanner
- */
-class StringScanException extends IOException
-{
- /**
+/**
+ * Exception class used by <code>StringScanner</code> when
+ * command line arguments do not parse correctly.
+ *
+ * @author John E. Lloyd, Winter 2001
+ * @see StringScanner
+ */
+class StringScanException extends IOException {
+ /**
*
*/
private static final long serialVersionUID = 4923445904507805754L;
int failIdx;
- /**
- * Creates a new StringScanException with the given message.
- *
- * @param msg Error message
- * @see StringScanner
- */
+ /**
+ * Creates a new StringScanException with the given message.
+ *
+ * @param msg Error message
+ * @see StringScanner
+ */
- public StringScanException (String msg)
- { super (msg);
- }
+ public StringScanException(String msg) {
+ super(msg);
+ }
- public StringScanException (int idx, String msg)
- {
- super (msg);
- failIdx = idx;
- }
+ public StringScanException(int idx, String msg) {
+ super(msg);
+ failIdx = idx;
+ }
- public int getFailIndex()
- {
- return failIdx;
- }
+ public int getFailIndex() {
+ return failIdx;
+ }
}
diff --git a/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanner.java b/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanner.java
index 6153f180..c6bddf26 100644
--- a/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanner.java
+++ b/pki/base/silent/src/com/netscape/pkisilent/argparser/StringScanner.java
@@ -1,4 +1,5 @@
package com.netscape.pkisilent.argparser;
+
// --- BEGIN COPYRIGHT BLOCK ---
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,626 +19,550 @@ package com.netscape.pkisilent.argparser;
// --- END COPYRIGHT BLOCK ---
/**
- * Copyright John E. Lloyd, 2004. All rights reserved. Permission to use,
- * copy, modify and redistribute is granted, provided that this copyright
- * notice is retained and the author is given credit whenever appropriate.
- *
- * This software is distributed "as is", without any warranty, including
- * any implied warranty of merchantability or fitness for a particular
- * use. The author assumes no responsibility for, and shall not be liable
- * for, any special, indirect, or consequential damages, or any damages
- * whatsoever, arising out of or in connection with the use of this
- * software.
- */
-
-class StringScanner
-{
- private char[] buf;
- private int idx;
- private int len;
- private String stringDelimiters = "";
-
- public StringScanner (String s)
- {
- buf = new char[s.length()+1];
- s.getChars (0, s.length(), buf, 0);
- len = s.length();
- buf[len] = 0;
- idx = 0;
- }
-
- public int getIndex()
- { return idx;
- }
-
- public void setIndex(int i)
- { if (i < 0)
- { idx = 0;
- }
- else if (i > len)
- { idx = len;
- }
- else
- { idx = i;
- }
- }
-
- public void setStringDelimiters (String s)
- { stringDelimiters = s;
- }
-
- public String getStringDelimiters()
- { return stringDelimiters;
- }
-
- public char scanChar ()
- throws StringScanException
- {
- int idxSave = idx;
- skipWhiteSpace();
- try
- { if (buf[idx] == '\'')
- { return scanQuotedChar();
- }
- else
- { return scanUnquotedChar();
- }
- }
- catch (StringScanException e)
- { idx = idxSave;
- throw e;
- }
- }
-
- public char scanQuotedChar ()
- throws StringScanException
- {
- StringScanException exception = null;
- char retval = 0;
- int idxSave = idx;
-
- skipWhiteSpace();
- if (idx == len)
- { exception = new StringScanException (idx, "end of input");
- }
- else if (buf[idx++] == '\'')
- { try
- { retval = scanUnquotedChar();
- }
- catch (StringScanException e)
- { exception = e;
- }
- if (exception==null)
- { if (idx==len)
- { exception = new StringScanException
- (idx, "end of input");
- }
- else if (buf[idx++] != '\'')
- { exception = new StringScanException
- (idx-1, "unclosed quoted character");
- }
- }
- }
- else
- { exception = new StringScanException
- (idx-1, "uninitialized quoted character");
- }
- if (exception!=null)
- { idx = idxSave;
- throw exception;
- }
- return retval;
- }
-
- public char scanUnquotedChar ()
- throws StringScanException
- {
- StringScanException exception = null;
- char c, retval = 0;
- int idxSave = idx;
-
- if (idx == len)
- { exception = new StringScanException (idx, "end of input");
- }
- else if ((c = buf[idx++]) == '\\')
- { if (idx == len)
- { exception = new StringScanException (idx, "end of input");
- }
- else
- {
- c = buf[idx++];
- if (c == '"')
- { retval = '"';
- }
- else if (c == '\'')
- { retval = '\'';
- }
- else if (c == '\\')
- { retval = '\\';
- }
- else if (c == 'n')
- { retval = '\n';
- }
- else if (c == 't')
- { retval = '\t';
- }
- else if (c == 'b')
- { retval = '\b';
- }
- else if (c == 'r')
- { retval = '\r';
- }
- else if (c == 'f')
- { retval = '\f';
- }
- else if ('0' <= c && c < '8')
- { int v = c - '0';
- for (int j=0; j<2; j++)
- { if (idx==len)
- { break;
- }
- c = buf[idx];
- if ('0' <= c && c < '8' && (v*8 + (c-'0')) <= 255)
- { v = v*8 + (c-'0');
- idx++;
- }
- else
- { break;
- }
- }
- retval = (char)v;
- }
- else
- { exception = new StringScanException
- (idx-1, "illegal escape character '" + c + "'");
- }
- }
- }
- else
- { retval = c;
- }
- if (exception!=null)
- { idx = idxSave;
- throw exception;
- }
- return retval;
- }
-
- public String scanQuotedString ()
- throws StringScanException
- {
- StringScanException exception = null;
- StringBuffer sbuf = new StringBuffer(len);
- char c;
- int idxSave = idx;
-
- skipWhiteSpace();
- if (idx == len)
- { exception = new StringScanException (idx, "end of input");
- }
- else if ((c=buf[idx++]) == '"')
- { while (idx<len && (c=buf[idx]) != '"' && c != '\n')
- { if (c == '\\')
- { try
- { c = scanUnquotedChar();
- }
- catch (StringScanException e)
- { exception = e;
- break;
- }
- }
- else
- { idx++;
- }
- sbuf.append (c);
- }
- if (exception == null && idx>=len)
- { exception = new StringScanException (len, "end of input");
- }
- else if (exception == null && c == '\n')
- { exception = new StringScanException
- (idx, "unclosed quoted string");
- }
- else
- { idx++;
- }
- }
- else
- { exception = new StringScanException (idx-1,
-"quoted string must start with \"");
- }
- if (exception != null)
- { idx = idxSave;
- throw exception;
- }
- return sbuf.toString();
- }
-
- public String scanNonWhiteSpaceString()
- throws StringScanException
- {
- StringBuffer sbuf = new StringBuffer(len);
- int idxSave = idx;
- char c;
-
- skipWhiteSpace();
- if (idx == len)
- { StringScanException e = new StringScanException (
- idx, "end of input");
- idx = idxSave;
- throw e;
- }
- else
- { c = buf[idx++];
- while (idx<len && !Character.isWhitespace(c)
- && stringDelimiters.indexOf(c) == -1)
- { sbuf.append(c);
- c = buf[idx++];
- }
- if (Character.isWhitespace(c) ||
- stringDelimiters.indexOf(c) != -1)
- { idx--;
- }
- else
- { sbuf.append(c);
- }
- }
- return sbuf.toString();
- }
-
- public String scanString ()
- throws StringScanException
- {
- int idxSave = idx;
- skipWhiteSpace();
- try
- { if (buf[idx] == '"')
- { return scanQuotedString();
- }
- else
- { return scanNonWhiteSpaceString();
- }
- }
- catch (StringScanException e)
- { idx = idxSave;
- throw e;
- }
- }
-
- public String getString ()
- throws StringScanException
- {
- StringBuffer sbuf = new StringBuffer(len);
- while (idx < len)
- { sbuf.append (buf[idx++]);
- }
- return sbuf.toString();
- }
-
- public long scanInt ()
- throws StringScanException
- {
- int idxSave = idx;
- char c;
- int sign = 1;
-
- skipWhiteSpace();
- if ((c=buf[idx]) == '-' || c == '+')
- { sign = (c == '-' ? -1 : 1);
- idx++;
- }
- try
- { if (idx==len)
- { throw new StringScanException (len, "end of input");
- }
- else if ((c=buf[idx]) == '0')
- { if ((c=buf[idx+1]) == 'x' || c == 'X')
- { idx += 2;
- return sign*scanInt (16, false);
- }
- else
- { return sign*scanInt (8, false);
- }
- }
- else
- { return sign*scanInt (10, false);
- }
- }
- catch (StringScanException e)
- { idx = idxSave;
- throw e;
- }
- }
-
- public long scanInt (int radix)
- throws StringScanException
- {
- return scanInt (radix, /*skipWhite=*/true);
- }
-
- private String baseDesc (int radix)
- {
- switch (radix)
- { case 10:
- { return "decimal";
- }
- case 8:
- { return "octal";
- }
- case 16:
- { return "hex";
- }
- default:
- { return "base " + radix;
- }
- }
- }
-
- public long scanInt (int radix, boolean skipWhite)
- throws StringScanException
- {
- StringScanException exception = null;
- int charval, idxSave = idx;
- char c;
- long val = 0;
- boolean negate = false;
-
- if (skipWhite)
- { skipWhiteSpace();
- }
- if ((c=buf[idx]) == '-' || c == '+')
- { negate = (c == '-');
- idx++;
- }
- if (idx >= len)
- { exception = new StringScanException (len, "end of input");
- }
- else if ((charval=Character.digit(buf[idx++],radix)) == -1)
- { exception = new StringScanException
- (idx-1, "malformed " + baseDesc(radix) + " integer");
- }
- else
- { val = charval;
- while ((charval=Character.digit(buf[idx],radix)) != -1)
- { val = val*radix + charval;
- idx++;
- }
- if (Character.isLetter(c=buf[idx]) ||
- Character.isDigit(c) || c == '_')
- { exception = new StringScanException
- (idx, "malformed " + baseDesc(radix) + " integer");
- }
- }
- if (exception != null)
- { idx = idxSave;
- throw exception;
- }
- return negate ? -val : val;
- }
-
- public double scanDouble ()
- throws StringScanException
- {
- StringScanException exception = null;
- int idxSave = idx;
- char c;
- // parse [-][0-9]*[.][0-9]*[eE][-][0-9]*
- boolean hasDigits = false;
- boolean signed;
- double value = 0;
-
- skipWhiteSpace();
- if (idx == len)
- { exception = new StringScanException ("end of input");
- }
- else
- {
- if ((c=buf[idx]) == '-' || c == '+')
- { signed = true;
- idx++;
- }
- if (matchDigits())
- { hasDigits = true;
- }
- if (buf[idx] == '.')
- { idx++;
- }
- if (!hasDigits && (buf[idx] < '0' || buf[idx] > '9'))
- { if (idx==len)
- { exception = new StringScanException (idx, "end of input");
- }
- else
- { exception = new StringScanException (
- idx, "malformed floating number: no digits");
- }
- }
- else
- { matchDigits();
-
- if ((c=buf[idx]) == 'e' || c == 'E')
- { idx++;
- if ((c=buf[idx]) == '-' || c == '+')
- { signed = true;
- idx++;
- }
- if (buf[idx] < '0' || buf[idx] > '9')
- { if (idx==len)
- { exception = new StringScanException(
- idx, "end of input");
- }
- else
- { exception = new StringScanException (idx,
-"malformed floating number: no digits in exponent");
- }
- }
- else
- { matchDigits();
- }
- }
- }
- }
- if (exception == null)
- {
-// if (Character.isLetterOrDigit(c=buf[idx]) || c == '_')
-// { exception = new StringScanException (idx,
-//"malformed floating number");
-// }
-// else
- {
- try
- { value = Double.parseDouble(new String(buf, idxSave,
- idx-idxSave));
- }
- catch (NumberFormatException e)
- { exception = new StringScanException (
- idx, "malformed floating number");
- }
- }
- }
- if (exception != null)
- { idx = idxSave;
- throw exception;
- }
- return value;
- }
-
- public boolean scanBoolean ()
- throws StringScanException
- {
- StringScanException exception = null;
- int idxSave = idx;
- String testStr = "false";
- boolean testval = false;
- char c;
-
- skipWhiteSpace();
- if (buf[idx] == 't')
- { testStr = "true";
- testval = true;
- }
- else
- { testval = false;
- }
- int i = 0;
- for (i=0; i<testStr.length(); i++)
- { if (testStr.charAt(i) != buf[idx])
- { if (idx==len)
- { exception = new StringScanException (idx, "end of input");
- }
- break;
- }
- idx++;
- }
- if (exception==null)
- { if (i<testStr.length() ||
- Character.isLetterOrDigit(c=buf[idx]) || c == '_')
- { exception = new StringScanException (idx, "illegal boolean");
- }
- }
- if (exception != null)
- { idx = idxSave;
- throw exception;
- }
- return testval;
- }
-
- public boolean matchString (String s)
- {
- int k = idx;
- for (int i=0; i<s.length(); i++)
- { if (k >= len || s.charAt(i) != buf[k++])
- { return false;
- }
- }
- idx = k;
- return true;
- }
-
- public boolean matchDigits ()
- {
- int k = idx;
- char c;
-
- while ((c=buf[k]) >= '0' && c <= '9')
- { k++;
- }
- if (k > idx)
- { idx = k;
- return true;
- }
- else
- { return false;
- }
- }
-
- public void skipWhiteSpace()
- {
- while (Character.isWhitespace(buf[idx]))
- { idx++;
- }
- }
-
- public boolean atEnd()
- {
- return idx == len;
- }
-
- public boolean atBeginning()
- {
- return idx == 0;
- }
-
- public void ungetc()
- {
- if (idx > 0)
- { idx--;
- }
- }
-
- public char getc()
- {
- char c = buf[idx];
- if (idx < len)
- { idx++;
- }
- return c;
- }
-
- public char peekc()
- {
- return buf[idx];
- }
-
- public String substring (int i0, int i1)
- {
- if (i0 < 0)
- { i0 = 0;
- }
- else if (i0 >= len)
- { i0= len-1;
- }
- if (i1 < 0)
- { i1 = 0;
- }
- else if (i1 > len)
- { i1= len;
- }
- if (i1 <= i0)
- { return "";
- }
- return new String (buf, i0, i1-i0);
- }
-
- public String substring (int i0)
- {
- if (i0 < 0)
- { i0 = 0;
- }
- if (i0 >= len)
- { return "";
- }
- else
- { return new String (buf, i0, len-i0);
- }
- }
+ * Copyright John E. Lloyd, 2004. All rights reserved. Permission to use,
+ * copy, modify and redistribute is granted, provided that this copyright
+ * notice is retained and the author is given credit whenever appropriate.
+ *
+ * This software is distributed "as is", without any warranty, including
+ * any implied warranty of merchantability or fitness for a particular
+ * use. The author assumes no responsibility for, and shall not be liable
+ * for, any special, indirect, or consequential damages, or any damages
+ * whatsoever, arising out of or in connection with the use of this
+ * software.
+ */
+
+class StringScanner {
+ private char[] buf;
+ private int idx;
+ private int len;
+ private String stringDelimiters = "";
+
+ public StringScanner(String s) {
+ buf = new char[s.length() + 1];
+ s.getChars(0, s.length(), buf, 0);
+ len = s.length();
+ buf[len] = 0;
+ idx = 0;
+ }
+
+ public int getIndex() {
+ return idx;
+ }
+
+ public void setIndex(int i) {
+ if (i < 0) {
+ idx = 0;
+ } else if (i > len) {
+ idx = len;
+ } else {
+ idx = i;
+ }
+ }
+
+ public void setStringDelimiters(String s) {
+ stringDelimiters = s;
+ }
+
+ public String getStringDelimiters() {
+ return stringDelimiters;
+ }
+
+ public char scanChar()
+ throws StringScanException {
+ int idxSave = idx;
+ skipWhiteSpace();
+ try {
+ if (buf[idx] == '\'') {
+ return scanQuotedChar();
+ } else {
+ return scanUnquotedChar();
+ }
+ } catch (StringScanException e) {
+ idx = idxSave;
+ throw e;
+ }
+ }
+
+ public char scanQuotedChar()
+ throws StringScanException {
+ StringScanException exception = null;
+ char retval = 0;
+ int idxSave = idx;
+
+ skipWhiteSpace();
+ if (idx == len) {
+ exception = new StringScanException(idx, "end of input");
+ } else if (buf[idx++] == '\'') {
+ try {
+ retval = scanUnquotedChar();
+ } catch (StringScanException e) {
+ exception = e;
+ }
+ if (exception == null) {
+ if (idx == len) {
+ exception = new StringScanException
+ (idx, "end of input");
+ } else if (buf[idx++] != '\'') {
+ exception = new StringScanException
+ (idx - 1, "unclosed quoted character");
+ }
+ }
+ } else {
+ exception = new StringScanException
+ (idx - 1, "uninitialized quoted character");
+ }
+ if (exception != null) {
+ idx = idxSave;
+ throw exception;
+ }
+ return retval;
+ }
+
+ public char scanUnquotedChar()
+ throws StringScanException {
+ StringScanException exception = null;
+ char c, retval = 0;
+ int idxSave = idx;
+
+ if (idx == len) {
+ exception = new StringScanException(idx, "end of input");
+ } else if ((c = buf[idx++]) == '\\') {
+ if (idx == len) {
+ exception = new StringScanException(idx, "end of input");
+ } else {
+ c = buf[idx++];
+ if (c == '"') {
+ retval = '"';
+ } else if (c == '\'') {
+ retval = '\'';
+ } else if (c == '\\') {
+ retval = '\\';
+ } else if (c == 'n') {
+ retval = '\n';
+ } else if (c == 't') {
+ retval = '\t';
+ } else if (c == 'b') {
+ retval = '\b';
+ } else if (c == 'r') {
+ retval = '\r';
+ } else if (c == 'f') {
+ retval = '\f';
+ } else if ('0' <= c && c < '8') {
+ int v = c - '0';
+ for (int j = 0; j < 2; j++) {
+ if (idx == len) {
+ break;
+ }
+ c = buf[idx];
+ if ('0' <= c && c < '8' && (v * 8 + (c - '0')) <= 255) {
+ v = v * 8 + (c - '0');
+ idx++;
+ } else {
+ break;
+ }
+ }
+ retval = (char) v;
+ } else {
+ exception = new StringScanException
+ (idx - 1, "illegal escape character '" + c + "'");
+ }
+ }
+ } else {
+ retval = c;
+ }
+ if (exception != null) {
+ idx = idxSave;
+ throw exception;
+ }
+ return retval;
+ }
+
+ public String scanQuotedString()
+ throws StringScanException {
+ StringScanException exception = null;
+ StringBuffer sbuf = new StringBuffer(len);
+ char c;
+ int idxSave = idx;
+
+ skipWhiteSpace();
+ if (idx == len) {
+ exception = new StringScanException(idx, "end of input");
+ } else if ((c = buf[idx++]) == '"') {
+ while (idx < len && (c = buf[idx]) != '"' && c != '\n') {
+ if (c == '\\') {
+ try {
+ c = scanUnquotedChar();
+ } catch (StringScanException e) {
+ exception = e;
+ break;
+ }
+ } else {
+ idx++;
+ }
+ sbuf.append(c);
+ }
+ if (exception == null && idx >= len) {
+ exception = new StringScanException(len, "end of input");
+ } else if (exception == null && c == '\n') {
+ exception = new StringScanException
+ (idx, "unclosed quoted string");
+ } else {
+ idx++;
+ }
+ } else {
+ exception = new StringScanException(idx - 1,
+ "quoted string must start with \"");
+ }
+ if (exception != null) {
+ idx = idxSave;
+ throw exception;
+ }
+ return sbuf.toString();
+ }
+
+ public String scanNonWhiteSpaceString()
+ throws StringScanException {
+ StringBuffer sbuf = new StringBuffer(len);
+ int idxSave = idx;
+ char c;
+
+ skipWhiteSpace();
+ if (idx == len) {
+ StringScanException e = new StringScanException(
+ idx, "end of input");
+ idx = idxSave;
+ throw e;
+ } else {
+ c = buf[idx++];
+ while (idx < len && !Character.isWhitespace(c)
+ && stringDelimiters.indexOf(c) == -1) {
+ sbuf.append(c);
+ c = buf[idx++];
+ }
+ if (Character.isWhitespace(c) ||
+ stringDelimiters.indexOf(c) != -1) {
+ idx--;
+ } else {
+ sbuf.append(c);
+ }
+ }
+ return sbuf.toString();
+ }
+
+ public String scanString()
+ throws StringScanException {
+ int idxSave = idx;
+ skipWhiteSpace();
+ try {
+ if (buf[idx] == '"') {
+ return scanQuotedString();
+ } else {
+ return scanNonWhiteSpaceString();
+ }
+ } catch (StringScanException e) {
+ idx = idxSave;
+ throw e;
+ }
+ }
+
+ public String getString()
+ throws StringScanException {
+ StringBuffer sbuf = new StringBuffer(len);
+ while (idx < len) {
+ sbuf.append(buf[idx++]);
+ }
+ return sbuf.toString();
+ }
+
+ public long scanInt()
+ throws StringScanException {
+ int idxSave = idx;
+ char c;
+ int sign = 1;
+
+ skipWhiteSpace();
+ if ((c = buf[idx]) == '-' || c == '+') {
+ sign = (c == '-' ? -1 : 1);
+ idx++;
+ }
+ try {
+ if (idx == len) {
+ throw new StringScanException(len, "end of input");
+ } else if ((c = buf[idx]) == '0') {
+ if ((c = buf[idx + 1]) == 'x' || c == 'X') {
+ idx += 2;
+ return sign * scanInt(16, false);
+ } else {
+ return sign * scanInt(8, false);
+ }
+ } else {
+ return sign * scanInt(10, false);
+ }
+ } catch (StringScanException e) {
+ idx = idxSave;
+ throw e;
+ }
+ }
+
+ public long scanInt(int radix)
+ throws StringScanException {
+ return scanInt(radix, /*skipWhite=*/true);
+ }
+
+ private String baseDesc(int radix) {
+ switch (radix) {
+ case 10: {
+ return "decimal";
+ }
+ case 8: {
+ return "octal";
+ }
+ case 16: {
+ return "hex";
+ }
+ default: {
+ return "base " + radix;
+ }
+ }
+ }
+
+ public long scanInt(int radix, boolean skipWhite)
+ throws StringScanException {
+ StringScanException exception = null;
+ int charval, idxSave = idx;
+ char c;
+ long val = 0;
+ boolean negate = false;
+
+ if (skipWhite) {
+ skipWhiteSpace();
+ }
+ if ((c = buf[idx]) == '-' || c == '+') {
+ negate = (c == '-');
+ idx++;
+ }
+ if (idx >= len) {
+ exception = new StringScanException(len, "end of input");
+ } else if ((charval = Character.digit(buf[idx++], radix)) == -1) {
+ exception = new StringScanException
+ (idx - 1, "malformed " + baseDesc(radix) + " integer");
+ } else {
+ val = charval;
+ while ((charval = Character.digit(buf[idx], radix)) != -1) {
+ val = val * radix + charval;
+ idx++;
+ }
+ if (Character.isLetter(c = buf[idx]) ||
+ Character.isDigit(c) || c == '_') {
+ exception = new StringScanException
+ (idx, "malformed " + baseDesc(radix) + " integer");
+ }
+ }
+ if (exception != null) {
+ idx = idxSave;
+ throw exception;
+ }
+ return negate ? -val : val;
+ }
+
+ public double scanDouble()
+ throws StringScanException {
+ StringScanException exception = null;
+ int idxSave = idx;
+ char c;
+ // parse [-][0-9]*[.][0-9]*[eE][-][0-9]*
+ boolean hasDigits = false;
+ boolean signed;
+ double value = 0;
+
+ skipWhiteSpace();
+ if (idx == len) {
+ exception = new StringScanException("end of input");
+ } else {
+ if ((c = buf[idx]) == '-' || c == '+') {
+ signed = true;
+ idx++;
+ }
+ if (matchDigits()) {
+ hasDigits = true;
+ }
+ if (buf[idx] == '.') {
+ idx++;
+ }
+ if (!hasDigits && (buf[idx] < '0' || buf[idx] > '9')) {
+ if (idx == len) {
+ exception = new StringScanException(idx, "end of input");
+ } else {
+ exception = new StringScanException(
+ idx, "malformed floating number: no digits");
+ }
+ } else {
+ matchDigits();
+
+ if ((c = buf[idx]) == 'e' || c == 'E') {
+ idx++;
+ if ((c = buf[idx]) == '-' || c == '+') {
+ signed = true;
+ idx++;
+ }
+ if (buf[idx] < '0' || buf[idx] > '9') {
+ if (idx == len) {
+ exception = new StringScanException(
+ idx, "end of input");
+ } else {
+ exception = new StringScanException(idx,
+ "malformed floating number: no digits in exponent");
+ }
+ } else {
+ matchDigits();
+ }
+ }
+ }
+ }
+ if (exception == null) {
+ // if (Character.isLetterOrDigit(c=buf[idx]) || c == '_')
+ // { exception = new StringScanException (idx,
+ //"malformed floating number");
+ // }
+ // else
+ {
+ try {
+ value = Double.parseDouble(new String(buf, idxSave,
+ idx - idxSave));
+ } catch (NumberFormatException e) {
+ exception = new StringScanException(
+ idx, "malformed floating number");
+ }
+ }
+ }
+ if (exception != null) {
+ idx = idxSave;
+ throw exception;
+ }
+ return value;
+ }
+
+ public boolean scanBoolean()
+ throws StringScanException {
+ StringScanException exception = null;
+ int idxSave = idx;
+ String testStr = "false";
+ boolean testval = false;
+ char c;
+
+ skipWhiteSpace();
+ if (buf[idx] == 't') {
+ testStr = "true";
+ testval = true;
+ } else {
+ testval = false;
+ }
+ int i = 0;
+ for (i = 0; i < testStr.length(); i++) {
+ if (testStr.charAt(i) != buf[idx]) {
+ if (idx == len) {
+ exception = new StringScanException(idx, "end of input");
+ }
+ break;
+ }
+ idx++;
+ }
+ if (exception == null) {
+ if (i < testStr.length() ||
+ Character.isLetterOrDigit(c = buf[idx]) || c == '_') {
+ exception = new StringScanException(idx, "illegal boolean");
+ }
+ }
+ if (exception != null) {
+ idx = idxSave;
+ throw exception;
+ }
+ return testval;
+ }
+
+ public boolean matchString(String s) {
+ int k = idx;
+ for (int i = 0; i < s.length(); i++) {
+ if (k >= len || s.charAt(i) != buf[k++]) {
+ return false;
+ }
+ }
+ idx = k;
+ return true;
+ }
+
+ public boolean matchDigits() {
+ int k = idx;
+ char c;
+
+ while ((c = buf[k]) >= '0' && c <= '9') {
+ k++;
+ }
+ if (k > idx) {
+ idx = k;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void skipWhiteSpace() {
+ while (Character.isWhitespace(buf[idx])) {
+ idx++;
+ }
+ }
+
+ public boolean atEnd() {
+ return idx == len;
+ }
+
+ public boolean atBeginning() {
+ return idx == 0;
+ }
+
+ public void ungetc() {
+ if (idx > 0) {
+ idx--;
+ }
+ }
+
+ public char getc() {
+ char c = buf[idx];
+ if (idx < len) {
+ idx++;
+ }
+ return c;
+ }
+
+ public char peekc() {
+ return buf[idx];
+ }
+
+ public String substring(int i0, int i1) {
+ if (i0 < 0) {
+ i0 = 0;
+ } else if (i0 >= len) {
+ i0 = len - 1;
+ }
+ if (i1 < 0) {
+ i1 = 0;
+ } else if (i1 > len) {
+ i1 = len;
+ }
+ if (i1 <= i0) {
+ return "";
+ }
+ return new String(buf, i0, i1 - i0);
+ }
+
+ public String substring(int i0) {
+ if (i0 < 0) {
+ i0 = 0;
+ }
+ if (i0 >= len) {
+ return "";
+ } else {
+ return new String(buf, i0, len - i0);
+ }
+ }
}