1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jdo.impl.enhancer;
18
19 import java.io.PrintWriter;
20
21 import java.util.Arrays;
22 import java.util.Map;
23 import java.util.List;
24 import java.util.Iterator;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.Properties;
28
29
30 /***
31 * Represents a set of options a program may support.
32 *
33 * @author Martin Zaun
34 */
35 public class OptionSet
36 extends LogSupport
37 {
38
39 static public final int OK = 0;
40 static public final int USAGE_ERROR = -1;
41
42
43 static public final String prefix = "-";
44 static public final String lprefix = "--";
45
46
47
48 /***
49 * The base class of all option types.
50 */
51 static public abstract class Option
52 {
53 /***
54 * The set the option is registered with.
55 */
56 protected OptionSet set;
57
58 /***
59 * The long form name of this option.
60 */
61 public final String name;
62
63 /***
64 * The short form name of this option.
65 */
66 public final String abbrev;
67
68 /***
69 * A description of this option.
70 */
71 public final String descr;
72
73 /***
74 * Creates an instance.
75 */
76 public Option(String name,
77 String abbrev,
78 String descr)
79 {
80 affirm(name != null);
81 this.name = name;
82 this.abbrev = abbrev;
83 this.descr = descr;
84 }
85
86 /***
87 * Parse this option for arguments it may require.
88 */
89 abstract public int parse(Iterator i);
90
91 /***
92 * Returns a <code>String</code> representation of this option's
93 * value for printing.
94 */
95 abstract public String asNameValue();
96
97 /***
98 * Returns a usage description of this option.
99 */
100 public String asUsageHelp()
101 {
102 String abbr = (abbrev == null ? " " : prefix + abbrev + "|");
103 return (abbr + lprefix + name + " " + descr);
104 }
105 }
106
107 /***
108 * An option that always causes a USAGE_ERROR when parsed (used for
109 * '-h|--help' kind of options).
110 */
111 static public class HelpOption extends Option
112 {
113 /***
114 * Creates an instance.
115 */
116 public HelpOption(String name,
117 String abbrev,
118 String descr)
119 {
120 super(name, abbrev, descr);
121 }
122
123 public int parse(Iterator i)
124 {
125 return USAGE_ERROR;
126 }
127
128 public String asNameValue()
129 {
130 return ("help = false");
131 }
132 }
133
134 /***
135 * An option representing a boolean flag.
136 */
137 static public class FlagOption extends Option
138 {
139 /***
140 * The default value for this option.
141 */
142 public final boolean deflt;
143
144 /***
145 * The value of this option.
146 */
147 public boolean value;
148
149 /***
150 * Creates an instance.
151 */
152 public FlagOption(String name,
153 String abbrev,
154 String descr)
155 {
156 this(name, abbrev, descr, false);
157 }
158
159 /***
160 * Creates an instance.
161 */
162 public FlagOption(String name,
163 String abbrev,
164 String descr,
165 boolean deflt)
166 {
167 super(name, abbrev, descr);
168 this.deflt = deflt;
169 this.value = deflt;
170 }
171
172 public int parse(Iterator i)
173 {
174 if (value != deflt) {
175 set.printUsageError("Repeated option: "
176 + prefix + abbrev + "/" + lprefix + name);
177 return USAGE_ERROR;
178 }
179 value = true;
180 return OK;
181 }
182
183 public String asNameValue()
184 {
185 return (name + " = " + String.valueOf(value));
186 }
187 }
188
189 /***
190 * An option representing a <code>int</code> value.
191 */
192 static public class IntOption extends Option
193 {
194 /***
195 * The default value for this option.
196 */
197 public final int deflt;
198
199 /***
200 * The value of this option.
201 */
202 public int value;
203
204 /***
205 * Creates an instance.
206 */
207 public IntOption(String name,
208 String abbrev,
209 String descr)
210 {
211 this(name, abbrev, descr, 0);
212 }
213
214 /***
215 * Creates an instance.
216 */
217 public IntOption(String name,
218 String abbrev,
219 String descr,
220 int deflt)
221 {
222 super(name, abbrev, descr);
223 this.deflt = deflt;
224 this.value = deflt;
225 }
226
227 public int parse(Iterator i)
228 {
229 if (value != deflt) {
230 set.printUsageError("Repeated option: "
231 + prefix + abbrev + "/" + lprefix + name);
232 return USAGE_ERROR;
233 }
234 if (!i.hasNext()) {
235 set.printUsageError("Missing argument to option: "
236 + prefix + abbrev + "/" + lprefix + name);
237 return USAGE_ERROR;
238 }
239 try {
240 value = Integer.valueOf((String)i.next()).intValue();
241 } catch (NumberFormatException ex) {
242 set.printUsageError("Illegal argument to option: "
243 + prefix + abbrev + "/" + lprefix + name);
244 return USAGE_ERROR;
245 }
246 return OK;
247 }
248
249 public String asNameValue()
250 {
251 return (name + " = " + String.valueOf(value));
252 }
253 }
254
255 /***
256 * An option representing a <code>String</code> value.
257 */
258 static public class StringOption extends Option
259 {
260 /***
261 * The default value for this option.
262 */
263 public final String deflt;
264
265 /***
266 * The value of this option.
267 */
268 public String value;
269
270 /***
271 * Creates an instance.
272 */
273 public StringOption(String name,
274 String abbrev,
275 String descr)
276 {
277 this(name, abbrev, descr, null);
278 }
279
280 /***
281 * Creates an instance.
282 */
283 public StringOption(String name,
284 String abbrev,
285 String descr,
286 String deflt)
287 {
288 super(name, abbrev, descr);
289 this.deflt = deflt;
290 this.value = deflt;
291 }
292
293 public int parse(Iterator i)
294 {
295 if (value != deflt) {
296 set.printUsageError("Repeated option: "
297 + prefix + abbrev + "/" + lprefix + name);
298 return USAGE_ERROR;
299 }
300 if (!i.hasNext()) {
301 set.printUsageError("Missing argument to option: "
302 + prefix + abbrev + "/" + lprefix + name);
303 return USAGE_ERROR;
304 }
305 value = (String)i.next();
306 if (value.startsWith(prefix)) {
307 set.printUsageError("Missing argument to option: "
308 + prefix + abbrev + "/" + lprefix + name);
309 return USAGE_ERROR;
310 }
311 return OK;
312 }
313
314 public String asNameValue()
315 {
316 return (name + " = " + String.valueOf(value));
317 }
318 }
319
320
321
322 /***
323 * The list of registered options.
324 */
325 protected final List options = new ArrayList();
326
327 /***
328 * Maps the option's long form against option instances.
329 */
330 protected final Map names = new HashMap();
331
332 /***
333 * Maps the option's short form against option instances.
334 */
335 protected final Map abbrevs = new HashMap();
336
337 /***
338 * The collected arguments.
339 */
340 protected final List arguments = new ArrayList();
341
342 /***
343 * Usage printout.
344 */
345 public String usageHeader
346 = "Usage: <options>.. <arguments>..";
347
348 /***
349 * Usage printout.
350 */
351 public String optionsHeader
352 = "Options:";
353
354 /***
355 * Usage printout.
356 */
357 public String argumentsHeader
358 = "Arguments:";
359
360 /***
361 * Usage printout.
362 */
363 public String returnHeader
364 = "Returns: A non-zero value in case of errors.";
365
366 /***
367 * Usage printout.
368 */
369 public String indent
370 = " ";
371
372 /***
373 * Creates an instance.
374 */
375 public OptionSet(PrintWriter out,
376 PrintWriter err)
377 {
378 super(out, err);
379 }
380
381 /***
382 * Creates an instance.
383 */
384 public OptionSet(PrintWriter out,
385 PrintWriter err,
386 String usageHeader,
387 String optionsHeader,
388 String argumentsHeader,
389 String returnHeader,
390 String indent)
391 {
392 this(out, err);
393 this.usageHeader = usageHeader;
394 this.optionsHeader = optionsHeader;
395 this.argumentsHeader = argumentsHeader;
396 this.returnHeader = returnHeader;
397 this.indent = indent;
398 }
399
400
401
402 /***
403 * Registers an option with the set.
404 */
405 public void register(Option option)
406 {
407 affirm(option != null);
408 option.set = this;
409 options.add(option);
410
411 affirm(option.name != null);
412 Object obj = names.put(lprefix + option.name, option);
413 affirm(obj == null, "Option already registered: " + option.name);
414
415 if (option.abbrev != null) {
416 obj = abbrevs.put(prefix + option.abbrev, option);
417 affirm(obj == null, "Option already registered: " + option.name);
418 }
419 }
420
421 /***
422 * Creates and registers an option representing a usage-help request.
423 */
424 public HelpOption createHelpOption(String name,
425 String abbrev,
426 String descr)
427 {
428 final HelpOption opt = new HelpOption(name, abbrev, descr);
429 register(opt);
430 return opt;
431 }
432
433 /***
434 * Creates and registers an option representing a boolean flag.
435 */
436 public FlagOption createFlagOption(String name,
437 String abbrev,
438 String descr)
439 {
440 final FlagOption opt = new FlagOption(name, abbrev, descr);
441 register(opt);
442 return opt;
443 }
444
445 /***
446 * Creates and registers an option representing a boolean flag.
447 */
448 public FlagOption createFlagOption(String name,
449 String abbrev,
450 String descr,
451 boolean deflt)
452 {
453 final FlagOption opt = new FlagOption(name, abbrev, descr, deflt);
454 register(opt);
455 return opt;
456 }
457
458 /***
459 * Creates and registers an option representing a <code>int</code>
460 * value.
461 */
462 public IntOption createIntOption(String name,
463 String abbrev,
464 String descr)
465 {
466 final IntOption opt = new IntOption(name, abbrev, descr);
467 register(opt);
468 return opt;
469 }
470
471 /***
472 * Creates and registers an option representing a <code>int</code>
473 * value.
474 */
475 public IntOption createIntOption(String name,
476 String abbrev,
477 String descr,
478 int deflt)
479 {
480 final IntOption opt = new IntOption(name, abbrev, descr, deflt);
481 register(opt);
482 return opt;
483 }
484
485 /***
486 * Creates and registers an option representing a <code>String</code>
487 * value.
488 */
489 public StringOption createStringOption(String name,
490 String abbrev,
491 String descr)
492 {
493 final StringOption opt = new StringOption(name, abbrev, descr);
494 register(opt);
495 return opt;
496 }
497
498 /***
499 * Creates and registers an option representing a <code>String</code>
500 * value.
501 */
502 public StringOption createStringOption(String name,
503 String abbrev,
504 String descr,
505 String deflt)
506 {
507 final StringOption opt
508 = new StringOption(name, abbrev, descr, deflt);
509 register(opt);
510 return opt;
511 }
512
513
514
515 /***
516 * Parses options and arguments.
517 */
518 public int parse(String[] argv)
519 {
520 affirm(argv != null);
521 for (Iterator i = Arrays.asList(argv).iterator(); i.hasNext();) {
522 final String arg = (String)i.next();
523
524
525 if (arg == null || arg.length() == 0) {
526
527 continue;
528 }
529
530
531 if (!arg.startsWith(prefix)) {
532 arguments.add(arg);
533 continue;
534 }
535
536
537 Option option = (Option)abbrevs.get(arg);
538 if (option == null) {
539 option = (Option)names.get(arg);
540 }
541
542
543 if (option == null) {
544 printlnErr("Unrecognized option: " + arg);
545 return USAGE_ERROR;
546 }
547
548
549 int res = option.parse(i);
550 if (res != OK) {
551 return res;
552 }
553 }
554 return OK;
555 }
556
557 /***
558 * Checks options and arguments.
559 */
560 public int check()
561 {
562 return OK;
563 }
564
565 /***
566 * Parse and check options and arguments.
567 */
568 public int process(String[] args)
569 {
570 int res = OK;
571 if ((res = parse(args)) != OK) {
572 printUsage();
573 return res;
574 }
575 if ((res = check()) != OK) {
576 printUsage();
577 return res;
578 }
579 return res;
580 }
581
582
583
584 /***
585 * Print a usage error message to System.err.
586 */
587 public void printUsageError(String msg)
588 {
589 printlnErr("USAGE ERROR: " + msg);
590 }
591
592 /***
593 * Print a usage message to System.err.
594 */
595 public void printUsage()
596 {
597 println();
598 printUsageHeader();
599 printOptionHeader();
600 printOptionUsage();
601 printArgumentHeader();
602 printArgumentUsage();
603 printReturnHeader();
604 printReturnUsage();
605 }
606
607 /***
608 * Print a usage message to System.err.
609 */
610 public void printUsageHeader()
611 {
612 printlnErr(usageHeader);
613 }
614
615 /***
616 * Print a usage message to System.err.
617 */
618 public void printOptionHeader()
619 {
620 printlnErr();
621 printlnErr(optionsHeader);
622 }
623
624 /***
625 * Print a usage message to System.err.
626 */
627 public void printOptionUsage()
628 {
629 for (Iterator i = options.iterator(); i.hasNext();) {
630 printlnErr(indent + ((Option)i.next()).asUsageHelp());
631 }
632 }
633
634 /***
635 * Print a usage message to System.err.
636 */
637 public void printArgumentHeader()
638 {
639 printlnErr();
640 printlnErr(argumentsHeader);
641 }
642
643 /***
644 * Print a usage message to System.err.
645 */
646 public void printArgumentUsage()
647 {}
648
649 /***
650 * Print a usage message to System.err.
651 */
652 public void printReturnHeader()
653 {
654 printlnErr();
655 printlnErr(returnHeader);
656 }
657
658 /***
659 * Print a usage message to System.err.
660 */
661 public void printReturnUsage()
662 {}
663
664
665
666 /***
667 * Print options and arguments.
668 */
669 public void printAll()
670 {
671 printOptions();
672 printArguments();
673 }
674
675 /***
676 * Print options.
677 */
678 public void printOptions()
679 {
680 println();
681 println(optionsHeader);
682 for (Iterator i = options.iterator(); i.hasNext();) {
683 println(indent + ((Option)i.next()).asNameValue());
684 }
685 }
686
687 /***
688 * Print arguments.
689 */
690 public void printArguments()
691 {
692 println();
693 println(argumentsHeader);
694 print(indent);
695 for (Iterator i = arguments.iterator(); i.hasNext();) {
696 print(" " + i.next());
697 }
698 }
699
700
701
702 /***
703 * Tests the class.
704 */
705 static public void main(String[] args)
706 {
707 final PrintWriter out = new PrintWriter(System.out, true);
708 out.println("--> OptionSet.main()");
709 final OptionSet options = new OptionSet(out, out);
710 out.println(" options.process() ...");
711 int res = options.process(args);
712 out.println(" return value: " + res);
713 out.println("<-- OptionSet.main()");
714 }
715 }