001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.commons.cli;
017:
018: import java.io.PrintWriter;
019:
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.Collections;
023: import java.util.Comparator;
024: import java.util.Iterator;
025: import java.util.List;
026:
027: /**
028: * A formatter of help messages for the current command line options
029: *
030: * @author Slawek Zachcial
031: * @author John Keyes (john at integralsource.com)
032: **/
033: public class HelpFormatter {
034: // --------------------------------------------------------------- Constants
035:
036: /** default number of characters per line */
037: public static final int DEFAULT_WIDTH = 74;
038:
039: /** default padding to the left of each line */
040: public static final int DEFAULT_LEFT_PAD = 1;
041:
042: /**
043: * the number of characters of padding to be prefixed
044: * to each description line
045: */
046: public static final int DEFAULT_DESC_PAD = 3;
047:
048: /** the string to display at the begining of the usage statement */
049: public static final String DEFAULT_SYNTAX_PREFIX = "usage: ";
050:
051: /** default prefix for shortOpts */
052: public static final String DEFAULT_OPT_PREFIX = "-";
053:
054: /** default prefix for long Option */
055: public static final String DEFAULT_LONG_OPT_PREFIX = "--";
056:
057: /** default name for an argument */
058: public static final String DEFAULT_ARG_NAME = "arg";
059:
060: // -------------------------------------------------------------- Attributes
061:
062: /**
063: * number of characters per line
064: *
065: * @deprecated Scope will be made private for next major version
066: * - use get/setWidth methods instead.
067: */
068: public int defaultWidth = DEFAULT_WIDTH;
069:
070: /**
071: * amount of padding to the left of each line
072: *
073: * @deprecated Scope will be made private for next major version
074: * - use get/setLeftPadding methods instead.
075: */
076: public int defaultLeftPad = DEFAULT_LEFT_PAD;
077:
078: /**
079: * the number of characters of padding to be prefixed
080: * to each description line
081: *
082: * @deprecated Scope will be made private for next major version
083: * - use get/setDescPadding methods instead.
084: */
085: public int defaultDescPad = DEFAULT_DESC_PAD;
086:
087: /**
088: * the string to display at the begining of the usage statement
089: *
090: * @deprecated Scope will be made private for next major version
091: * - use get/setSyntaxPrefix methods instead.
092: */
093: public String defaultSyntaxPrefix = DEFAULT_SYNTAX_PREFIX;
094:
095: /**
096: * the new line string
097: *
098: * @deprecated Scope will be made private for next major version
099: * - use get/setNewLine methods instead.
100: */
101: public String defaultNewLine = System.getProperty("line.separator");
102:
103: /**
104: * the shortOpt prefix
105: *
106: * @deprecated Scope will be made private for next major version
107: * - use get/setOptPrefix methods instead.
108: */
109: public String defaultOptPrefix = DEFAULT_OPT_PREFIX;
110:
111: /**
112: * the long Opt prefix
113: *
114: * @deprecated Scope will be made private for next major version
115: * - use get/setLongOptPrefix methods instead.
116: */
117: public String defaultLongOptPrefix = DEFAULT_LONG_OPT_PREFIX;
118:
119: /**
120: * the name of the argument
121: *
122: * @deprecated Scope will be made private for next major version
123: * - use get/setArgName methods instead.
124: */
125: public String defaultArgName = DEFAULT_ARG_NAME;
126:
127: /**
128: * Sets the 'width'.
129: *
130: * @param width the new value of 'width'
131: */
132: public void setWidth(int width) {
133: this .defaultWidth = width;
134: }
135:
136: /**
137: * Returns the 'width'.
138: *
139: * @return the 'width'
140: */
141: public int getWidth() {
142: return this .defaultWidth;
143: }
144:
145: /**
146: * Sets the 'leftPadding'.
147: *
148: * @param padding the new value of 'leftPadding'
149: */
150: public void setLeftPadding(int padding) {
151: this .defaultLeftPad = padding;
152: }
153:
154: /**
155: * Returns the 'leftPadding'.
156: *
157: * @return the 'leftPadding'
158: */
159: public int getLeftPadding() {
160: return this .defaultLeftPad;
161: }
162:
163: /**
164: * Sets the 'descPadding'.
165: *
166: * @param padding the new value of 'descPadding'
167: */
168: public void setDescPadding(int padding) {
169: this .defaultDescPad = padding;
170: }
171:
172: /**
173: * Returns the 'descPadding'.
174: *
175: * @return the 'descPadding'
176: */
177: public int getDescPadding() {
178: return this .defaultDescPad;
179: }
180:
181: /**
182: * Sets the 'syntaxPrefix'.
183: *
184: * @param prefix the new value of 'syntaxPrefix'
185: */
186: public void setSyntaxPrefix(String prefix) {
187: this .defaultSyntaxPrefix = prefix;
188: }
189:
190: /**
191: * Returns the 'syntaxPrefix'.
192: *
193: * @return the 'syntaxPrefix'
194: */
195: public String getSyntaxPrefix() {
196: return this .defaultSyntaxPrefix;
197: }
198:
199: /**
200: * Sets the 'newLine'.
201: *
202: * @param newline the new value of 'newLine'
203: */
204: public void setNewLine(String newline) {
205: this .defaultNewLine = newline;
206: }
207:
208: /**
209: * Returns the 'newLine'.
210: *
211: * @return the 'newLine'
212: */
213: public String getNewLine() {
214: return this .defaultNewLine;
215: }
216:
217: /**
218: * Sets the 'optPrefix'.
219: *
220: * @param prefix the new value of 'optPrefix'
221: */
222: public void setOptPrefix(String prefix) {
223: this .defaultOptPrefix = prefix;
224: }
225:
226: /**
227: * Returns the 'optPrefix'.
228: *
229: * @return the 'optPrefix'
230: */
231: public String getOptPrefix() {
232: return this .defaultOptPrefix;
233: }
234:
235: /**
236: * Sets the 'longOptPrefix'.
237: *
238: * @param prefix the new value of 'longOptPrefix'
239: */
240: public void setLongOptPrefix(String prefix) {
241: this .defaultLongOptPrefix = prefix;
242: }
243:
244: /**
245: * Returns the 'longOptPrefix'.
246: *
247: * @return the 'longOptPrefix'
248: */
249: public String getLongOptPrefix() {
250: return this .defaultLongOptPrefix;
251: }
252:
253: /**
254: * Sets the 'argName'.
255: *
256: * @param name the new value of 'argName'
257: */
258: public void setArgName(String name) {
259: this .defaultArgName = name;
260: }
261:
262: /**
263: * Returns the 'argName'.
264: *
265: * @return the 'argName'
266: */
267: public String getArgName() {
268: return this .defaultArgName;
269: }
270:
271: // ------------------------------------------------------------------ Public
272:
273: /**
274: * <p>Print the help for <code>options</code> with the specified
275: * command line syntax. This method prints help information to
276: * System.out.</p>
277: *
278: * @param cmdLineSyntax the syntax for this application
279: * @param options the Options instance
280: */
281: public void printHelp(String cmdLineSyntax, Options options) {
282: printHelp(defaultWidth, cmdLineSyntax, null, options, null,
283: false);
284: }
285:
286: /**
287: * <p>Print the help for <code>options</code> with the specified
288: * command line syntax. This method prints help information to
289: * System.out.</p>
290: *
291: * @param cmdLineSyntax the syntax for this application
292: * @param options the Options instance
293: * @param autoUsage whether to print an automatically generated
294: * usage statement
295: */
296: public void printHelp(String cmdLineSyntax, Options options,
297: boolean autoUsage) {
298: printHelp(defaultWidth, cmdLineSyntax, null, options, null,
299: autoUsage);
300: }
301:
302: /**
303: * <p>Print the help for <code>options</code> with the specified
304: * command line syntax. This method prints help information to
305: * System.out.</p>
306: *
307: * @param cmdLineSyntax the syntax for this application
308: * @param header the banner to display at the begining of the help
309: * @param options the Options instance
310: * @param footer the banner to display at the end of the help
311: */
312: public void printHelp(String cmdLineSyntax, String header,
313: Options options, String footer) {
314: printHelp(cmdLineSyntax, header, options, footer, false);
315: }
316:
317: /**
318: * <p>Print the help for <code>options</code> with the specified
319: * command line syntax. This method prints help information to
320: * System.out.</p>
321: *
322: * @param cmdLineSyntax the syntax for this application
323: * @param header the banner to display at the begining of the help
324: * @param options the Options instance
325: * @param footer the banner to display at the end of the help
326: * @param autoUsage whether to print an automatically generated
327: * usage statement
328: */
329: public void printHelp(String cmdLineSyntax, String header,
330: Options options, String footer, boolean autoUsage) {
331: printHelp(defaultWidth, cmdLineSyntax, header, options, footer,
332: autoUsage);
333: }
334:
335: /**
336: * <p>Print the help for <code>options</code> with the specified
337: * command line syntax. This method prints help information to
338: * System.out.</p>
339: *
340: * @param width the number of characters to be displayed on each line
341: * @param cmdLineSyntax the syntax for this application
342: * @param header the banner to display at the begining of the help
343: * @param options the Options instance
344: * @param footer the banner to display at the end of the help
345: */
346: public void printHelp(int width, String cmdLineSyntax,
347: String header, Options options, String footer) {
348: printHelp(width, cmdLineSyntax, header, options, footer, false);
349: }
350:
351: /**
352: * <p>Print the help for <code>options</code> with the specified
353: * command line syntax. This method prints help information to
354: * System.out.</p>
355: *
356: * @param width the number of characters to be displayed on each line
357: * @param cmdLineSyntax the syntax for this application
358: * @param header the banner to display at the begining of the help
359: * @param options the Options instance
360: * @param footer the banner to display at the end of the help
361: * @param autoUsage whether to print an automatically generated
362: * usage statement
363: */
364: public void printHelp(int width, String cmdLineSyntax,
365: String header, Options options, String footer,
366: boolean autoUsage) {
367: PrintWriter pw = new PrintWriter(System.out);
368:
369: printHelp(pw, width, cmdLineSyntax, header, options,
370: defaultLeftPad, defaultDescPad, footer, autoUsage);
371: pw.flush();
372: }
373:
374: /**
375: * <p>Print the help for <code>options</code> with the specified
376: * command line syntax.</p>
377: *
378: * @param pw the writer to which the help will be written
379: * @param width the number of characters to be displayed on each line
380: * @param cmdLineSyntax the syntax for this application
381: * @param header the banner to display at the begining of the help
382: * @param options the Options instance
383: * @param leftPad the number of characters of padding to be prefixed
384: * to each line
385: * @param descPad the number of characters of padding to be prefixed
386: * to each description line
387: * @param footer the banner to display at the end of the help
388: */
389: public void printHelp(PrintWriter pw, int width,
390: String cmdLineSyntax, String header, Options options,
391: int leftPad, int descPad, String footer) {
392: printHelp(pw, width, cmdLineSyntax, header, options, leftPad,
393: descPad, footer, false);
394: }
395:
396: /**
397: * <p>Print the help for <code>options</code> with the specified
398: * command line syntax.</p>
399: *
400: * @param pw the writer to which the help will be written
401: * @param width the number of characters to be displayed on each line
402: * @param cmdLineSyntax the syntax for this application
403: * @param header the banner to display at the begining of the help
404: * @param options the Options instance
405: * @param leftPad the number of characters of padding to be prefixed
406: * to each line
407: * @param descPad the number of characters of padding to be prefixed
408: * to each description line
409: * @param footer the banner to display at the end of the help
410: * @param autoUsage whether to print an automatically generated
411: * usage statement
412: */
413: public void printHelp(PrintWriter pw, int width,
414: String cmdLineSyntax, String header, Options options,
415: int leftPad, int descPad, String footer, boolean autoUsage) {
416: if ((cmdLineSyntax == null) || (cmdLineSyntax.length() == 0)) {
417: throw new IllegalArgumentException(
418: "cmdLineSyntax not provided");
419: }
420:
421: if (autoUsage) {
422: printUsage(pw, width, cmdLineSyntax, options);
423: } else {
424: printUsage(pw, width, cmdLineSyntax);
425: }
426:
427: if ((header != null) && (header.trim().length() > 0)) {
428: printWrapped(pw, width, header);
429: }
430:
431: printOptions(pw, width, options, leftPad, descPad);
432:
433: if ((footer != null) && (footer.trim().length() > 0)) {
434: printWrapped(pw, width, footer);
435: }
436: }
437:
438: /**
439: * <p>Prints the usage statement for the specified application.</p>
440: *
441: * @param pw The PrintWriter to print the usage statement
442: * @param width The number of characters to display per line
443: * @param app The application name
444: * @param options The command line Options
445: *
446: */
447: public void printUsage(PrintWriter pw, int width, String app,
448: Options options) {
449: // initialise the string buffer
450: StringBuffer buff = new StringBuffer(defaultSyntaxPrefix)
451: .append(app).append(" ");
452:
453: // create a list for processed option groups
454: final Collection processedGroups = new ArrayList();
455:
456: // temp variable
457: Option option;
458:
459: List optList = new ArrayList(options.getOptions());
460: Collections.sort(optList, new OptionComparator());
461: // iterate over the options
462: for (Iterator i = optList.iterator(); i.hasNext();) {
463: // get the next Option
464: option = (Option) i.next();
465:
466: // check if the option is part of an OptionGroup
467: OptionGroup group = options.getOptionGroup(option);
468:
469: // if the option is part of a group
470: if (group != null) {
471: // and if the group has not already been processed
472: if (!processedGroups.contains(group)) {
473: // add the group to the processed list
474: processedGroups.add(group);
475:
476: // add the usage clause
477: appendOptionGroup(buff, group);
478: }
479:
480: // otherwise the option was displayed in the group
481: // previously so ignore it.
482: }
483:
484: // if the Option is not part of an OptionGroup
485: else {
486: appendOption(buff, option, option.isRequired());
487: }
488:
489: if (i.hasNext()) {
490: buff.append(" ");
491: }
492: }
493:
494: // call printWrapped
495: printWrapped(pw, width, buff.toString().indexOf(' ') + 1, buff
496: .toString());
497: }
498:
499: /**
500: * Appends the usage clause for an OptionGroup to a StringBuffer.
501: * The clause is wrapped in square brackets if the group is required.
502: * The display of the options is handled by appendOption
503: * @param buff the StringBuffer to append to
504: * @param group the group to append
505: * @see #appendOption(StringBuffer,Option,boolean)
506: */
507: private static void appendOptionGroup(final StringBuffer buff,
508: final OptionGroup group) {
509: if (!group.isRequired()) {
510: buff.append("[");
511: }
512:
513: List optList = new ArrayList(group.getOptions());
514: Collections.sort(optList, new OptionComparator());
515: // for each option in the OptionGroup
516: for (Iterator i = optList.iterator(); i.hasNext();) {
517: // whether the option is required or not is handled at group level
518: appendOption(buff, (Option) i.next(), true);
519:
520: if (i.hasNext()) {
521: buff.append(" | ");
522: }
523: }
524:
525: if (!group.isRequired()) {
526: buff.append("]");
527: }
528: }
529:
530: /**
531: * Appends the usage clause for an Option to a StringBuffer.
532: *
533: * @param buff the StringBuffer to append to
534: * @param option the Option to append
535: * @param required whether the Option is required or not
536: */
537: private static void appendOption(final StringBuffer buff,
538: final Option option, final boolean required) {
539: if (!required) {
540: buff.append("[");
541: }
542:
543: if (option.getOpt() != null) {
544: buff.append("-").append(option.getOpt());
545: } else {
546: buff.append("--").append(option.getLongOpt());
547: }
548:
549: // if the Option has a value
550: if (option.hasArg() && (option.getArgName() != null)) {
551: buff.append(" <").append(option.getArgName()).append(">");
552: }
553:
554: // if the Option is not a required option
555: if (!required) {
556: buff.append("]");
557: }
558: }
559:
560: /**
561: * <p>Print the cmdLineSyntax to the specified writer, using the
562: * specified width.</p>
563: *
564: * @param pw The printWriter to write the help to
565: * @param width The number of characters per line for the usage statement.
566: * @param cmdLineSyntax The usage statement.
567: */
568: public void printUsage(PrintWriter pw, int width,
569: String cmdLineSyntax) {
570: int argPos = cmdLineSyntax.indexOf(' ') + 1;
571:
572: printWrapped(pw, width, defaultSyntaxPrefix.length() + argPos,
573: defaultSyntaxPrefix + cmdLineSyntax);
574: }
575:
576: /**
577: * <p>Print the help for the specified Options to the specified writer,
578: * using the specified width, left padding and description padding.</p>
579: *
580: * @param pw The printWriter to write the help to
581: * @param width The number of characters to display per line
582: * @param options The command line Options
583: * @param leftPad the number of characters of padding to be prefixed
584: * to each line
585: * @param descPad the number of characters of padding to be prefixed
586: * to each description line
587: */
588: public void printOptions(PrintWriter pw, int width,
589: Options options, int leftPad, int descPad) {
590: StringBuffer sb = new StringBuffer();
591:
592: renderOptions(sb, width, options, leftPad, descPad);
593: pw.println(sb.toString());
594: }
595:
596: /**
597: * <p>Print the specified text to the specified PrintWriter.</p>
598: *
599: * @param pw The printWriter to write the help to
600: * @param width The number of characters to display per line
601: * @param text The text to be written to the PrintWriter
602: */
603: public void printWrapped(PrintWriter pw, int width, String text) {
604: printWrapped(pw, width, 0, text);
605: }
606:
607: /**
608: * <p>Print the specified text to the specified PrintWriter.</p>
609: *
610: * @param pw The printWriter to write the help to
611: * @param width The number of characters to display per line
612: * @param nextLineTabStop The position on the next line for the first tab.
613: * @param text The text to be written to the PrintWriter
614: */
615: public void printWrapped(PrintWriter pw, int width,
616: int nextLineTabStop, String text) {
617: StringBuffer sb = new StringBuffer(text.length());
618:
619: renderWrappedText(sb, width, nextLineTabStop, text);
620: pw.println(sb.toString());
621: }
622:
623: // --------------------------------------------------------------- Protected
624:
625: /**
626: * <p>Render the specified Options and return the rendered Options
627: * in a StringBuffer.</p>
628: *
629: * @param sb The StringBuffer to place the rendered Options into.
630: * @param width The number of characters to display per line
631: * @param options The command line Options
632: * @param leftPad the number of characters of padding to be prefixed
633: * to each line
634: * @param descPad the number of characters of padding to be prefixed
635: * to each description line
636: *
637: * @return the StringBuffer with the rendered Options contents.
638: */
639: protected StringBuffer renderOptions(StringBuffer sb, int width,
640: Options options, int leftPad, int descPad) {
641: final String lpad = createPadding(leftPad);
642: final String dpad = createPadding(descPad);
643:
644: // first create list containing only <lpad>-a,--aaa where
645: // -a is opt and --aaa is long opt; in parallel look for
646: // the longest opt string this list will be then used to
647: // sort options ascending
648: int max = 0;
649: StringBuffer optBuf;
650: List prefixList = new ArrayList();
651: Option option;
652: List optList = options.helpOptions();
653:
654: Collections.sort(optList, new OptionComparator());
655:
656: for (Iterator i = optList.iterator(); i.hasNext();) {
657: option = (Option) i.next();
658: optBuf = new StringBuffer(8);
659:
660: if (option.getOpt() == null) {
661: optBuf.append(lpad)
662: .append(" " + defaultLongOptPrefix).append(
663: option.getLongOpt());
664: } else {
665: optBuf.append(lpad).append(defaultOptPrefix).append(
666: option.getOpt());
667:
668: if (option.hasLongOpt()) {
669: optBuf.append(',').append(defaultLongOptPrefix)
670: .append(option.getLongOpt());
671: }
672: }
673:
674: if (option.hasArg()) {
675: if (option.hasArgName()) {
676: optBuf.append(" <").append(option.getArgName())
677: .append(">");
678: } else {
679: optBuf.append(' ');
680: }
681: }
682:
683: prefixList.add(optBuf);
684: max = (optBuf.length() > max) ? optBuf.length() : max;
685: }
686:
687: int x = 0;
688:
689: for (Iterator i = optList.iterator(); i.hasNext();) {
690: option = (Option) i.next();
691: optBuf = new StringBuffer(prefixList.get(x++).toString());
692:
693: if (optBuf.length() < max) {
694: optBuf.append(createPadding(max - optBuf.length()));
695: }
696:
697: optBuf.append(dpad);
698:
699: int nextLineTabStop = max + descPad;
700:
701: if (option.getDescription() != null) {
702: optBuf.append(option.getDescription());
703: }
704:
705: renderWrappedText(sb, width, nextLineTabStop, optBuf
706: .toString());
707:
708: if (i.hasNext()) {
709: sb.append(defaultNewLine);
710: }
711: }
712:
713: return sb;
714: }
715:
716: /**
717: * <p>Render the specified text and return the rendered Options
718: * in a StringBuffer.</p>
719: *
720: * @param sb The StringBuffer to place the rendered text into.
721: * @param width The number of characters to display per line
722: * @param nextLineTabStop The position on the next line for the first tab.
723: * @param text The text to be rendered.
724: *
725: * @return the StringBuffer with the rendered Options contents.
726: */
727: protected StringBuffer renderWrappedText(StringBuffer sb,
728: int width, int nextLineTabStop, String text) {
729: int pos = findWrapPos(text, width, 0);
730:
731: if (pos == -1) {
732: sb.append(rtrim(text));
733:
734: return sb;
735: }
736: sb.append(rtrim(text.substring(0, pos))).append(defaultNewLine);
737:
738: // all following lines must be padded with nextLineTabStop space
739: // characters
740: final String padding = createPadding(nextLineTabStop);
741:
742: while (true) {
743: text = padding + text.substring(pos).trim();
744: pos = findWrapPos(text, width, nextLineTabStop);
745:
746: if (pos == -1) {
747: sb.append(text);
748:
749: return sb;
750: }
751:
752: sb.append(rtrim(text.substring(0, pos))).append(
753: defaultNewLine);
754: }
755: }
756:
757: /**
758: * Finds the next text wrap position after <code>startPos</code> for the
759: * text in <code>text</code> with the column width <code>width</code>.
760: * The wrap point is the last postion before startPos+width having a
761: * whitespace character (space, \n, \r).
762: *
763: * @param text The text being searched for the wrap position
764: * @param width width of the wrapped text
765: * @param startPos position from which to start the lookup whitespace
766: * character
767: * @return postion on which the text must be wrapped or -1 if the wrap
768: * position is at the end of the text
769: */
770: protected int findWrapPos(String text, int width, int startPos) {
771: int pos = -1;
772:
773: // the line ends before the max wrap pos or a new line char found
774: if (((pos = text.indexOf('\n', startPos)) != -1 && pos <= width)
775: || ((pos = text.indexOf('\t', startPos)) != -1 && pos <= width)) {
776: return pos + 1;
777: } else if ((startPos + width) >= text.length()) {
778: return -1;
779: }
780:
781: // look for the last whitespace character before startPos+width
782: pos = startPos + width;
783:
784: char c;
785:
786: while ((pos >= startPos) && ((c = text.charAt(pos)) != ' ')
787: && (c != '\n') && (c != '\r')) {
788: --pos;
789: }
790:
791: // if we found it - just return
792: if (pos > startPos) {
793: return pos;
794: }
795:
796: // must look for the first whitespace chearacter after startPos
797: // + width
798: pos = startPos + width;
799:
800: while ((pos <= text.length())
801: && ((c = text.charAt(pos)) != ' ') && (c != '\n')
802: && (c != '\r')) {
803: ++pos;
804: }
805:
806: return (pos == text.length()) ? (-1) : pos;
807: }
808:
809: /**
810: * <p>Return a String of padding of length <code>len</code>.</p>
811: *
812: * @param len The length of the String of padding to create.
813: *
814: * @return The String of padding
815: */
816: protected String createPadding(int len) {
817: StringBuffer sb = new StringBuffer(len);
818:
819: for (int i = 0; i < len; ++i) {
820: sb.append(' ');
821: }
822:
823: return sb.toString();
824: }
825:
826: /**
827: * <p>Remove the trailing whitespace from the specified String.</p>
828: *
829: * @param s The String to remove the trailing padding from.
830: *
831: * @return The String of without the trailing padding
832: */
833: protected String rtrim(String s) {
834: if ((s == null) || (s.length() == 0)) {
835: return s;
836: }
837:
838: int pos = s.length();
839:
840: while ((pos > 0) && Character.isWhitespace(s.charAt(pos - 1))) {
841: --pos;
842: }
843:
844: return s.substring(0, pos);
845: }
846:
847: // ------------------------------------------------------ Package protected
848: // ---------------------------------------------------------------- Private
849: // ---------------------------------------------------------- Inner classes
850: /**
851: * <p>This class implements the <code>Comparator</code> interface
852: * for comparing Options.</p>
853: */
854: private static class OptionComparator implements Comparator {
855:
856: /**
857: * <p>Compares its two arguments for order. Returns a negative
858: * integer, zero, or a positive integer as the first argument
859: * is less than, equal to, or greater than the second.</p>
860: *
861: * @param o1 The first Option to be compared.
862: * @param o2 The second Option to be compared.
863: *
864: * @return a negative integer, zero, or a positive integer as
865: * the first argument is less than, equal to, or greater than the
866: * second.
867: */
868: public int compare(Object o1, Object o2) {
869: Option opt1 = (Option) o1;
870: Option opt2 = (Option) o2;
871:
872: return opt1.getKey().compareToIgnoreCase(opt2.getKey());
873: }
874: }
875: }
|