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