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
;
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
{
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
); }
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
36 public static class UnknownOptionException
extends OptionException
{
37 UnknownOptionException( String optionName
) {
38 super("unknown option '" + optionName
+ "'");
39 this.optionName
= optionName
;
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;
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
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());
65 * @return the name of the option whose value was illegal (e.g. "-u")
67 public Option
getOption() { return this.option
; }
70 * @return the illegal value
72 public String
getValue() { return this.value
; }
73 private Option option
;
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
) {
112 throw new IllegalOptionValueException(this, "");
114 return this.parseValue(arg
, locale
);
122 * Override to extract and convert an option value passed on the
125 protected Object
parseValue( String arg
, Locale locale
)
126 throws IllegalOptionValueException
{
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
{
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
{
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
{
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
) {
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
);
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
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();
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
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
);
366 throw new UnknownOptionException(curArg
);
369 if ( opt
.wantsValue() ) {
370 if ( valueArg
== null ) {
373 if ( position
< argv
.length
) {
374 valueArg
= argv
[position
];
377 value
= opt
.getValue(valueArg
, locale
);
380 value
= opt
.getValue(null, locale
);
382 this.values
.put(opt
.longForm(), value
);
389 for ( ; position
< argv
.length
; ++position
) {
390 otherArgs
.addElement(argv
[position
]);
393 this.remainingArgs
= new String
[otherArgs
.size()];
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);