imported from svn
[metux-java.git] / jargs / CmdLineParser.java
blob0ee22a80017da1a16701294bf6054958b6554d84
2 package jargs.gnu;
4 import java.text.NumberFormat;
5 import java.text.ParseException;
6 import java.util.Hashtable;
7 import java.util.Vector;
8 import java.util.Enumeration;
9 import java.util.Locale;
11 /**
12 * Largely GNU-compatible command-line options parser. Has short (-v) and
13 * long-form (--verbose) option support, and also allows options with
14 * associated values (-d 2, --debug 2, --debug=2). Option processing
15 * can be explicitly terminated by the argument '--'.
17 * @author Steve Purcell
18 * @version $Revision: 1.1.1.1 $
19 * @see jargs.examples.gnu.OptionTest
21 public class CmdLineParser {
23 /**
24 * Base class for exceptions that may be thrown when options are parsed
26 public static abstract class OptionException extends Exception {
27 OptionException(String msg) { super(msg); }
30 /**
31 * Thrown when the parsed command-line contains an option that is not
32 * recognised. <code>getMessage()</code> returns
33 * an error string suitable for reporting the error to the user (in
34 * English).
36 public static class UnknownOptionException extends OptionException {
37 UnknownOptionException( String optionName ) {
38 super("unknown option '" + optionName + "'");
39 this.optionName = optionName;
42 /**
43 * @return the name of the option that was unknown (e.g. "-u")
45 public String getOptionName() { return this.optionName; }
46 private String optionName = null;
49 /**
50 * Thrown when an illegal or missing value is given by the user for
51 * an option that takes a value. <code>getMessage()</code> returns
52 * an error string suitable for reporting the error to the user (in
53 * English).
55 public static class IllegalOptionValueException extends OptionException {
56 public IllegalOptionValueException( Option opt, String value ) {
57 super("illegal value '" + value + "' for option " +
58 (opt.shortForm() != null ? "-" + opt.shortForm() + "/" : "") +
59 "--" + opt.longForm());
60 this.option = opt;
61 this.value = value;
64 /**
65 * @return the name of the option whose value was illegal (e.g. "-u")
67 public Option getOption() { return this.option; }
69 /**
70 * @return the illegal value
72 public String getValue() { return this.value; }
73 private Option option;
74 private String value;
77 /**
78 * Representation of a command-line option
80 public static abstract class Option {
82 protected Option( String longForm, boolean wantsValue ) {
83 this(null, longForm, wantsValue);
86 protected Option( char shortForm, String longForm,
87 boolean wantsValue ) {
88 this(new String(new char[]{shortForm}), longForm, wantsValue);
91 private Option( String shortForm, String longForm, boolean wantsValue ) {
92 if ( longForm == null )
93 throw new IllegalArgumentException("null arg forms not allowed");
94 this.shortForm = shortForm;
95 this.longForm = longForm;
96 this.wantsValue = wantsValue;
99 public String shortForm() { return this.shortForm; }
101 public String longForm() { return this.longForm; }
104 * Tells whether or not this option wants a value
106 public boolean wantsValue() { return this.wantsValue; }
108 public final Object getValue( String arg, Locale locale )
109 throws IllegalOptionValueException {
110 if ( this.wantsValue ) {
111 if ( arg == null ) {
112 throw new IllegalOptionValueException(this, "");
114 return this.parseValue(arg, locale);
116 else {
117 return Boolean.TRUE;
122 * Override to extract and convert an option value passed on the
123 * command-line
125 protected Object parseValue( String arg, Locale locale )
126 throws IllegalOptionValueException {
127 return null;
130 private String shortForm = null;
131 private String longForm = null;
132 private boolean wantsValue = false;
134 public static class BooleanOption extends Option {
135 public BooleanOption( char shortForm, String longForm ) {
136 super(shortForm, longForm, false);
138 public BooleanOption( String longForm ) {
139 super(longForm, false);
144 * An option that expects an integer value
146 public static class IntegerOption extends Option {
147 public IntegerOption( char shortForm, String longForm ) {
148 super(shortForm, longForm, true);
150 public IntegerOption( String longForm ) {
151 super(longForm, true);
153 protected Object parseValue( String arg, Locale locale )
154 throws IllegalOptionValueException {
155 try {
156 return new Integer(arg);
158 catch (NumberFormatException e) {
159 throw new IllegalOptionValueException(this, arg);
165 * An option that expects a long integer value
167 public static class LongOption extends Option {
168 public LongOption( char shortForm, String longForm ) {
169 super(shortForm, longForm, true);
171 public LongOption( String longForm ) {
172 super(longForm, true);
174 protected Object parseValue( String arg, Locale locale )
175 throws IllegalOptionValueException {
176 try {
177 return new Long(arg);
179 catch (NumberFormatException e) {
180 throw new IllegalOptionValueException(this, arg);
186 * An option that expects a floating-point value
188 public static class DoubleOption extends Option {
189 public DoubleOption( char shortForm, String longForm ) {
190 super(shortForm, longForm, true);
192 public DoubleOption( String longForm ) {
193 super(longForm, true);
195 protected Object parseValue( String arg, Locale locale )
196 throws IllegalOptionValueException {
197 try {
198 NumberFormat format = NumberFormat.getNumberInstance(locale);
199 Number num = (Number)format.parse(arg);
200 return new Double(num.doubleValue());
202 catch (ParseException e) {
203 throw new IllegalOptionValueException(this, arg);
209 * An option that expects a string value
211 public static class StringOption extends Option {
212 public StringOption( char shortForm, String longForm ) {
213 super(shortForm, longForm, true);
215 public StringOption( String longForm ) {
216 super(longForm, true);
218 protected Object parseValue( String arg, Locale locale ) {
219 return arg;
225 * Add the specified Option to the list of accepted options
227 public final Option addOption( Option opt ) {
228 if ( opt.shortForm() != null )
229 this.options.put("-" + opt.shortForm(), opt);
230 this.options.put("--" + opt.longForm(), opt);
231 return opt;
235 * Convenience method for adding a string option.
236 * @return the new Option
238 public final Option addStringOption( char shortForm, String longForm ) {
239 return addOption(new Option.StringOption(shortForm, longForm));
243 * Convenience method for adding a string option.
244 * @return the new Option
246 public final Option addStringOption( String longForm ) {
247 return addOption(new Option.StringOption(longForm));
251 * Convenience method for adding an integer option.
252 * @return the new Option
254 public final Option addIntegerOption( char shortForm, String longForm ) {
255 return addOption(new Option.IntegerOption(shortForm, longForm));
259 * Convenience method for adding an integer option.
260 * @return the new Option
262 public final Option addIntegerOption( String longForm ) {
263 return addOption(new Option.IntegerOption(longForm));
267 * Convenience method for adding a long integer option.
268 * @return the new Option
270 public final Option addLongOption( char shortForm, String longForm ) {
271 return addOption(new Option.LongOption(shortForm, longForm));
275 * Convenience method for adding a long integer option.
276 * @return the new Option
278 public final Option addLongOption( String longForm ) {
279 return addOption(new Option.LongOption(longForm));
283 * Convenience method for adding a double option.
284 * @return the new Option
286 public final Option addDoubleOption( char shortForm, String longForm ) {
287 return addOption(new Option.DoubleOption(shortForm, longForm));
291 * Convenience method for adding a double option.
292 * @return the new Option
294 public final Option addDoubleOption( String longForm ) {
295 return addOption(new Option.DoubleOption(longForm));
299 * Convenience method for adding a boolean option.
300 * @return the new Option
302 public final Option addBooleanOption( char shortForm, String longForm ) {
303 return addOption(new Option.BooleanOption(shortForm, longForm));
307 * Convenience method for adding a boolean option.
308 * @return the new Option
310 public final Option addBooleanOption( String longForm ) {
311 return addOption(new Option.BooleanOption(longForm));
315 * @return the parsed value of the given Option, or null if the
316 * option was not set
318 public final Object getOptionValue( Option o ) {
319 return values.get(o.longForm());
323 * @return the non-option arguments
325 public final String[] getRemainingArgs() {
326 return this.remainingArgs;
330 * Extract the options and non-option arguments from the given
331 * list of command-line arguments. The default locale is used for
332 * parsing options whose values might be locale-specific.
334 public final void parse( String[] argv )
335 throws IllegalOptionValueException, UnknownOptionException {
336 parse(argv, Locale.getDefault());
340 * Extract the options and non-option arguments from the given
341 * list of command-line arguments. The specified locale is used for
342 * parsing options whose values might be locale-specific.
344 public final void parse( String[] argv, Locale locale )
345 throws IllegalOptionValueException, UnknownOptionException {
346 Vector otherArgs = new Vector();
347 int position = 0;
348 this.values = new Hashtable(10);
349 while ( position < argv.length ) {
350 String curArg = argv[position];
351 if ( curArg.startsWith("-") ) {
352 if ( curArg.equals("--") ) { // end of options
353 position += 1;
354 break;
356 String valueArg = null;
357 if ( curArg.startsWith("--") ) { // handle --arg=value
358 int equalsPos = curArg.indexOf("=");
359 if ( equalsPos != -1 ) {
360 valueArg = curArg.substring(equalsPos+1);
361 curArg = curArg.substring(0,equalsPos);
364 Option opt = (Option)this.options.get(curArg);
365 if ( opt == null ) {
366 throw new UnknownOptionException(curArg);
368 Object value = null;
369 if ( opt.wantsValue() ) {
370 if ( valueArg == null ) {
371 position += 1;
372 valueArg = null;
373 if ( position < argv.length ) {
374 valueArg = argv[position];
377 value = opt.getValue(valueArg, locale);
379 else {
380 value = opt.getValue(null, locale);
382 this.values.put(opt.longForm(), value);
383 position += 1;
385 else {
386 break;
389 for ( ; position < argv.length; ++position ) {
390 otherArgs.addElement(argv[position]);
393 this.remainingArgs = new String[otherArgs.size()];
394 int i = 0;
395 for (Enumeration e = otherArgs.elements(); e.hasMoreElements(); ++i) {
396 this.remainingArgs[i] = (String)e.nextElement();
400 private String[] remainingArgs = null;
401 private Hashtable options = new Hashtable(10);
402 private Hashtable values = new Hashtable(10);