/* XBN Java: Generically useful, non-GUI Java code. http://sourceforge.net/projects/xbnjava Copyright (C) 1997-2003, Jeff Epstein All rights reserved. Modifications: No Redistribution in binary form, with or without modifications, are permitted provided that the following conditions are met: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * If modifications are made to source code then this license should indicate that fact in the "Modifications" section above. * Neither the author, nor the contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [NOTE: This license contains NO advertising clause.] */ package xbn.programs; import xbn.XBNObject; import xbn.output.OSysDotOut; import xbn.output.Outputter; import xbn.output.OWSDOAndFile; import xbn.string.UtilString; import xbn.util.RangeConfig; import xbn.util.Utility; import org.apache.commons.cli.BasicParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import java.io.PrintWriter; /**

Random functions for parsing, casting, verification and notification of values from org.apache.commons.cli.CommandLine. See org.apache.commons.cli.CommandLine.

Source code:  UtilCommandLine.java

How to pass a dash in as the first character in a value (as in a negative number)?

@version 0.9b @author Jeff Epstein, http://sourceforge.net/projects/xbnjava. **/ public class UtilCommandLine extends XBNObject { private final HelpFormatter hf = new HelpFormatter(); private final UtilString uStr = new UtilString(); private static int iPRINT_HELP_SIG_CODE = -1; private static final int iSIG_OS = 1; private static final int iSIG_OSB = 2; private static final int iSIG_OSSS = 3; private static final int iSIG_OSSSB = 4; private static final int iSIG_OISSS = 5; private static final int iSIG_OISSSB = 6; private static final int iSIG_OPISSIIS = 7; private static final int iSIG_OPISSIISB = 8; private CommandLine cl = null; private Options opts = null; private PrintWriter pw = null; private int iWidth = -1; private String sCmdLineSyntax = null; private String sHeader = null; private int iLeftPad = -1; private int iDescPad = -1; private String sFooter = null; private boolean bAutoUsage = false; public UtilCommandLine(Options o_ptions, String s_cmdLineSyntax) { throwAXIfNull(o_ptions, "o_ptions", sCNSTR); throwAXIfBadStr(s_cmdLineSyntax, "s_cmdLineSyntax", sCNSTR); opts = o_ptions; sCmdLineSyntax = s_cmdLineSyntax; iPRINT_HELP_SIG_CODE = iSIG_OS; } public UtilCommandLine(Options o_ptions, String s_cmdLineSyntax, boolean b_autoUsage) { this(o_ptions, s_cmdLineSyntax); bAutoUsage = b_autoUsage; iPRINT_HELP_SIG_CODE = iSIG_OSB; } public UtilCommandLine(Options o_ptions, String s_cmdLineSyntax, String s_header, String s_footer) { this(o_ptions, s_cmdLineSyntax); sHeader = s_header; sFooter = s_footer; iPRINT_HELP_SIG_CODE = iSIG_OSSS; } public UtilCommandLine(Options o_ptions, String s_cmdLineSyntax, String s_header, String s_footer, boolean b_autoUsage) { this(o_ptions, s_cmdLineSyntax); sHeader = s_header; sFooter = s_footer; bAutoUsage = b_autoUsage; iPRINT_HELP_SIG_CODE = iSIG_OSSSB; } public UtilCommandLine(Options o_ptions, int i_width, String s_cmdLineSyntax, String s_header, String s_footer) { this(o_ptions, s_cmdLineSyntax); iWidth = i_width; sHeader = s_header; sFooter = s_footer; iPRINT_HELP_SIG_CODE = iSIG_OISSS; } public UtilCommandLine(Options o_ptions, int i_width, String s_cmdLineSyntax, String s_header, String s_footer, boolean b_autoUsage) { this(o_ptions, s_cmdLineSyntax); iWidth = i_width; sHeader = s_header; sFooter = s_footer; bAutoUsage = b_autoUsage; iPRINT_HELP_SIG_CODE = iSIG_OISSSB; } public UtilCommandLine(Options o_ptions, PrintWriter print_writer, int i_width, String s_cmdLineSyntax, String s_header, String s_footer, int i_leftPad, int i_descPad) { this(o_ptions, s_cmdLineSyntax); pw = print_writer; iWidth = i_width; sHeader = s_header; sFooter = s_footer; iLeftPad = i_leftPad; iDescPad = i_descPad; iPRINT_HELP_SIG_CODE = iSIG_OPISSIIS; } public UtilCommandLine(Options o_ptions, PrintWriter print_writer, int i_width, String s_cmdLineSyntax, String s_header, String s_footer, int i_leftPad, int i_descPad, boolean b_autoUsage) { this(o_ptions, s_cmdLineSyntax); pw = print_writer; iWidth = i_width; sHeader = s_header; sFooter = s_footer; iLeftPad = i_leftPad; iDescPad = i_descPad; bAutoUsage = b_autoUsage; iPRINT_HELP_SIG_CODE = iSIG_OPISSIISB; } /**

Get the CommandLine after parsing the actually-provided command line.

@return getCommandLine(as_cmdLineParams, (new BasicParser())) **/ public final CommandLine getCommandLine(String[] as_cmdLineParams) { return getCommandLine(as_cmdLineParams, (new BasicParser())); } /**

Get the CommandLine after parsing the actually-provided command line.

In order, this first outputs the actually-provided command line, parses the actually-provided command line (and crashes with the usage message if anything is wrong), and then returns the derived CommandLine, as returned by cmd_linePrsr.parse().

This should only be called once. Second and subsequent requests for the CommandLine object should use getCommandLine instead.

@param as_cmdLineParams The array of command line parameters, provided directly from the 'main' function in your application. May not be null. @param cmd_linePrsr The CommandLineParser. May not be null. **/ public final CommandLine getCommandLine(String[] as_cmdLineParams, CommandLineParser cmd_linePrsr) { throwAXIfNull(cmd_linePrsr, "cmd_linePrsr", sCNSTR); throwAXIfNull(as_cmdLineParams, "as_cmdLineParams", sCNSTR); String sActlCmdLine = "java " + getCmdLineSyntax() + " " + (new Utility()).getActlCmdLineParams(as_cmdLineParams).toString(); sopl("ACTUALLY PROVIDED COMMAND LINE:\n------------\n" + sActlCmdLine + "\n------------"); try { cl = cmd_linePrsr.parse(getOptions(), as_cmdLineParams); } catch(ParseException px) { crash("Command line arguments invalid: " + px.toString()); } output(sES); return cl; } /**

Get the CommandLine, as previously parsed. (as_cmdLineParams, cmd_linePrsr) must be called before this using this function.

@return The CommandLine as originally generated by the two-parameter version of this function. **/ public final CommandLine getCommandLine() { if(cl == null) { throwAX("getCommandLine: must call getCommandLine(as_cmdLineParams, cmd_linePrsr) before calling this."); } return cl; } /**

Get the PrintWriter, exactly as provided to the constructor.

**/ public final PrintWriter getPrintWriter() { return pw; } /**

Get the width value, exactly as provided to the constructor.

**/ public final int getWidth() { return iWidth; } /**

Get the command-line syntax string, exactly as provided to the constructor.

**/ public final String getCmdLineSyntax() { return sCmdLineSyntax; } /**

Get the header string, exactly as provided to the constructor.

**/ public final String getHeader() { return sHeader; } /**

Get the Options, exactly as provided to the constructor.

**/ public final Options getOptions() { return opts; } /**

Get the left-pad value, exactly as provided to the constructor.

**/ public final int getLeftPad() { return iLeftPad; } /**

Get the description-pad value, exactly as provided to the constructor.

**/ public final int getDescPad() { return iDescPad; } /**

Get the footer string, exactly as provided to the constructor.

**/ public final String getFooter() { return sFooter; } /**

Get the auto-usage value, exactly as provided to the constructor.

**/ public final boolean getAutoUsage() { return bAutoUsage; } /**

Stop execution, and print out usage.

Equal to printHelp(null)

**/ public final void crash() { printHelp(null); } /**

Stop execution, and print out usage. If an error message is provided, print it out, too (and first).

**/ public final void crash(String s_error) { printHelp(null); output(sES); throwAX("ERROR in command line parameters. " + s_error + "."); } private void output(String s_message) { if(getPrintWriter() != null) { getPrintWriter().println(s_message); } else { sopl(s_message); } } private void outputNoln(String s_message) { if(getPrintWriter() != null) { getPrintWriter().print(s_message); } else { sop(s_message); } } /**

Print out the usage string.

Equal to printHelp(null)

**/ public final void printHelp() { printHelp(null); } /**

Print out the usage string, plus an optional error message.

Depending on the constructor signature use, that (similar) version of the [HelpFormatter].printHelp function is used.

@param s_error A specific error message, if appropriate. If null, then no specific error message is output. If non-null, then this is printed out immediately before the usage message. **/ public final void printHelp(String s_error) { if(s_error != null) { output(s_error); } if(iPRINT_HELP_SIG_CODE == iSIG_OS) { hf.printHelp(sCmdLineSyntax, opts); } else if(iPRINT_HELP_SIG_CODE == iSIG_OSB) { hf.printHelp(sCmdLineSyntax, opts, bAutoUsage); } else if(iPRINT_HELP_SIG_CODE == iSIG_OSSS) { hf.printHelp(sCmdLineSyntax, sHeader, opts, sFooter); } else if(iPRINT_HELP_SIG_CODE == iSIG_OSSSB) { hf.printHelp(sCmdLineSyntax, sHeader, opts, sFooter, bAutoUsage); } else if(iPRINT_HELP_SIG_CODE == iSIG_OISSS) { hf.printHelp(iWidth, sCmdLineSyntax, sHeader, opts, sFooter); } else if(iPRINT_HELP_SIG_CODE == iSIG_OISSSB) { hf.printHelp(iWidth, sCmdLineSyntax, sHeader, opts, sFooter, bAutoUsage); } else if(iPRINT_HELP_SIG_CODE == iSIG_OPISSIIS) { hf.printHelp(pw, iWidth, sCmdLineSyntax, sHeader, opts, iLeftPad, iDescPad, sFooter); } else if(iPRINT_HELP_SIG_CODE == iSIG_OPISSIISB) { hf.printHelp(pw, iWidth, sCmdLineSyntax, sHeader, opts, iLeftPad, iDescPad, sFooter, bAutoUsage); } else { throwAX("printHelp: iSIG_OPISSIISB"); } } /**

Get an Outputter to write to screen only, or both to screen and file.

@return getOSDOOrOSDOAndFile(s_optionName, true) **/ public final Outputter getOSDOOrOSDOAndFile(String s_optionName) { return getOSDOOrOSDOAndFile(s_optionName, true); } /**

Get an Outputter to write to screen only, or both to screen and file.

@param s_optionName The name of the parameter. If this parameter is provided, then it must have an argument, and that argument must be a legal (writeable and optionally existing) file name. @paarm b_appendToFile If the file exists, should it be appended to, or overwritten? When this command-line parameter is not provided, this parameter is ignored. @return If getCommandLine().hasOption(s_optionName): new Outputter(new OWSDOAndFile(getCommandLine().getOptionValue(s_optionName), b_appendToFile))
Otherwise, return new OSysDotOut() **/ public final Outputter getOSDOOrOSDOAndFile(String s_optionName, boolean b_appendToFile) { if(getCommandLine().hasOption(s_optionName)) { return new Outputter(new OWSDOAndFile(getCommandLine().getOptionValue(s_optionName), b_appendToFile)); } else { return new OSysDotOut(); } } /**

Get the int value of a parameter.

@return getInt(s_optionName, false, -1, (new RangeConfig())) **/ public final int getInt(String s_optionName) { return getInt(s_optionName, false, -1, (new RangeConfig())); } /**

Get the int value of a parameter. If the parameter was not provided, use an alternate default value.

@return getInt(s_optionName, true, i_defaultValue, (new RangeConfig())) **/ public final int getInt(String s_optionName, int i_defaultValue) { return getInt(s_optionName, true, i_defaultValue, (new RangeConfig())); } /**

Get the int value of a parameter, which must conform to a range.

@return getInt(s_optionName, false, -1, range_config) **/ public final int getInt(String s_optionName, RangeConfig range_config) { return getInt(s_optionName, false, -1, range_config); } /**

Get the int value of a parameter, which must conform to a range. If the parameter was not provided, use an alternate default value.

@return getInt(s_optionName, true, i_defaultValue, range_config) **/ public final int getInt(String s_optionName, int i_defaultValue, RangeConfig range_config) { return getInt(s_optionName, true, i_defaultValue, range_config); } /**

Get the int value of a parameter.

@param s_optionName The name of the desired parameter, which must have an argument. The value of the argument must be a legal int, acording to Integer.valueOf. @param b_useDefaultValue If true, then if the parameter was not provided on the command line, return i_defaultValue instead. @param i_defaultValue The default value to return, when the parameter is not provided. Ignored when b_useDefaultValue is false. Ignored when b_useDefaultValue is true, and this parameter was provided. When not ignored, must conform to range_config.isValid. @param range_config The range that the value must conform to. **/ public final int getInt(String s_optionName, boolean b_useDefaultValue, int i_defaultValue, RangeConfig range_config) { String sValue = getCommandLine().getOptionValue(s_optionName); if(sValue == null && b_useDefaultValue) { try { if(!range_config.isValid(i_defaultValue)) { crash("getInt: The parameter '" + s_optionName + "' was not provided AND b_useDefaultValue is true BUT i_defaultValue ('" + i_defaultValue + "') is invalid according to [" + range_config.toString() + "]."); } } catch(NullPointerException npx) { throwAX("getInt: range_config is null."); } return i_defaultValue; } //This parameter was provided. int iValue = -1; try { return Integer.valueOf(sValue).intValue(); } catch(NumberFormatException nfx) { crash("getInt: Value of '" + s_optionName + "' (" + sValue + ") is not an int according to Integer.valueOf()."); } try { if(!range_config.isValid(iValue)) { crash("getInt: Value of '" + s_optionName + "' (" + iValue + ") is invalid according to [" + range_config.toString() + "]"); } } catch(NullPointerException npx) { throwAX("getInt: range_config is null."); } return i_defaultValue; } }