View Javadoc

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