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