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.java53
-rwxr-xr-xpki/base/silent/src/com/netscape/pkisilent/argparser/ArgParser.java4120
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/ArgParserTest.java3023
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/BooleanHolder.java52
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/CharHolder.java52
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/DoubleHolder.java51
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/FloatHolder.java52
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/IntHolder.java51
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/LongHolder.java51
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/ObjectHolder.java52
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/SimpleExample.java66
-rw-r--r--pki/base/silent/src/com/netscape/pkisilent/argparser/StringHolder.java53
-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.java1168
14 files changed, 4293 insertions, 4605 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..3a78e5ce 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,35 @@ 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..ff231499 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;
@@ -40,191 +41,200 @@ import java.lang.reflect.Array;
import java.util.Vector;
/**
- * ArgParser is used to parse the command line arguments for a java
- * application program. It provides a compact way to specify options and match
- * them against command line arguments, with support for
- * <a href=#rangespec>range checking</a>,
- * <a href=#multipleOptionNames>multiple option names</a> (aliases),
- * <a href=#singleWordOptions>single word options</a>,
- * <a href=#multipleOptionValues>multiple values associated with an option</a>,
- * <a href=#multipleOptionInvocation>multiple option invocation</a>,
- * <a href=#helpInfo>generating help information</a>,
- * <a href=#customArgParsing>custom argument parsing</a>, and
- * <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.
- *
+ * ArgParser is used to parse the command line arguments for a java application
+ * program. It provides a compact way to specify options and match them against
+ * command line arguments, with support for <a href=#rangespec>range
+ * checking</a>, <a href=#multipleOptionNames>multiple option names</a>
+ * (aliases), <a href=#singleWordOptions>single word options</a>, <a
+ * href=#multipleOptionValues>multiple values associated with an option</a>, <a
+ * href=#multipleOptionInvocation>multiple option invocation</a>, <a
+ * href=#helpInfo>generating help information</a>, <a
+ * href=#customArgParsing>custom argument parsing</a>, and <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},
+ * <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
+ *
+ * <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
+ * 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>
- *
+ * 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
+ * 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.
- *
+ *
* <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
+ * 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>
@@ -232,52 +242,53 @@ import java.util.Vector;
* 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.
- *
+ *
+ * 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.
- *
+ *
+ * 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
- *
+ * 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>.
- *
+ * 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
+ * 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
@@ -291,48 +302,47 @@ import java.util.Vector;
*
* 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
+ * 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);
@@ -342,12 +352,13 @@ 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}:
+ * 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 +376,1787 @@ 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.
- *
+ * 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..762f4f15 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
- * operation of the parser class.
- *
+ * 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..dba72b6d 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,34 @@ 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..eed57892 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,32 @@ 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..b75f9f15 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,32 @@ 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..14a13d9e 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,32 @@ 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..446af9eb 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,32 @@ 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..37aa1c91 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,32 @@ 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..edb835ee 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,34 @@ 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..1fc11524 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,36 @@ 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..ea85c7d0 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,34 @@ 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..9d942f0d 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..56cc2a26 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,549 @@ 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);
+ }
+ }
}