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 */ 017package Apache.CLI; 018 019import java.util.ArrayList; 020import java.util.Enumeration; 021import java.util.List; 022import java.util.Properties; 023 024/** Default parser. */ 025@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="LICENSE") 026@SuppressWarnings({"rawtypes", "unchecked"}) 027public class DefaultParser implements CommandLineParser 028{ 029 /** 030 * A nested builder class to create {@code DefaultParser} instances 031 * using descriptive methods. 032 * 033 * <BR /><BR />Example usage: 034 * 035 * <DIV CLASS=EXAMPLE>{@code 036 * DefaultParser parser = Option 037 * .builder() 038 * .setAllowPartialMatching(false) 039 * .setStripLeadingAndTrailingQuotes(false) 040 * .build(); 041 * }</DIV> 042 */ 043 @Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="LICENSE") 044 public static final class Builder 045 { 046 // Flag indicating if partial matching of long options is supported. 047 private boolean allowPartialMatching = true; 048 049 // Flag indicating if balanced leading and trailing double quotes should be stripped from 050 // option arguments. 051 052 private Boolean stripLeadingAndTrailingQuotes; 053 054 /** 055 * Constructs a new {@code Builder} for a {@code DefaultParser} instance. 056 * 057 * <BR /><BR />Both allowPartialMatching and stripLeadingAndTrailingQuotes are true by 058 * default, mimicking the argument-less constructor. 059 */ 060 private Builder() { } 061 062 /** 063 * Builds an DefaultParser with the values declared by this {@link Builder}. 064 * 065 * @return the new {@link DefaultParser} 066 */ 067 public DefaultParser build() 068 { return new DefaultParser(allowPartialMatching, stripLeadingAndTrailingQuotes); } 069 070 /** 071 * Sets if partial matching of long options is supported. 072 * 073 * <BR /><BR />By "partial matching" we mean that given the following code: 074 * 075 * <DIV CLASS=EXAMPLE>{@code 076 * final Options options = new Options(); 077 * 078 * options.addOption(new Option("d", "debug", false, "Turn on debug.")); 079 * options.addOption(new Option("e", "extract", false, "Turn on extract.")); 080 * options.addOption(new Option("o", "option", true, "Turn on option with argument.")); 081 * }</DIV> 082 * 083 * <BR />If "partial matching" is turned on, {@code -de} only matches the {@code "debug"} 084 * option. However, with "partial matching" disabled, {@code -de} would enable both 085 * {@code debug} as well as {@code extract} 086 * 087 * @param allowPartialMatching whether to allow partial matching of long options 088 * @return this builder, to allow method 089 */ 090 public Builder setAllowPartialMatching(final boolean allowPartialMatching) 091 { 092 this.allowPartialMatching = allowPartialMatching; 093 return this; 094 } 095 096 /** 097 * Sets if balanced leading and trailing double quotes should be stripped from option 098 * arguments. 099 * 100 * <BR /><BR />If "stripping of balanced leading and trailing double quotes from option 101 * arguments" is true, the outermost balanced double quotes of option arguments values will 102 * be removed. For example, {@code -o '"x"'} getValue() will return {@code x}, instead of 103 * {@code "x"} 104 * 105 * <BR /><BR />If "stripping of balanced leading and trailing double quotes from option 106 * arguments" is null, then quotes will be stripped from option values separated by space 107 * from the option, but kept in other cases, which is the historic behavior. 108 * 109 * @param stripLeadingAndTrailingQuotes whether balanced leading and trailing double quotes 110 * should be stripped from option arguments. 111 * 112 * @return this builder, to allow method chaining 113 */ 114 public Builder setStripLeadingAndTrailingQuotes 115 (final Boolean stripLeadingAndTrailingQuotes) 116 { 117 this.stripLeadingAndTrailingQuotes = stripLeadingAndTrailingQuotes; 118 return this; 119 } 120 } 121 122 /** 123 * Creates a new {@link Builder} to create an {@link DefaultParser} using descriptive 124 * methods. 125 * 126 * @return a new {@link Builder} instance 127 */ 128 public static Builder builder() 129 { return new Builder(); } 130 131 /** The command-line instance. */ 132 protected CommandLine cmd; 133 134 /** The current options. */ 135 protected Options options; 136 137 /** 138 * Flag indicating how unrecognized tokens are handled. {@code true} to stop the parsing and 139 * add the remaining tokens to the args list. {@code false} to throw an exception. 140 */ 141 protected boolean stopAtNonOption; 142 143 /** The token currently processed. */ 144 protected String currentToken; 145 146 /** The last option parsed. */ 147 protected Option currentOption; 148 149 /** 150 * Flag indicating if tokens should no longer be analyzed and simply added as arguments of the 151 * command line. 152 */ 153 protected boolean skipParsing; 154 155 /** The required options and groups expected to be found when parsing the command line. */ 156 protected List expectedOpts; 157 158 // Flag indicating if partial matching of long options is supported. 159 private final boolean allowPartialMatching; 160 161 /** 162 * Flag indicating if balanced leading and trailing double quotes should be stripped from 163 * option arguments. null represents the historic arbitrary behavior 164 */ 165 private final Boolean stripLeadingAndTrailingQuotes; 166 167 /** 168 * Creates a new DefaultParser instance with partial matching enabled. 169 * 170 * By "partial matching" we mean that given the following code: 171 * 172 * <DIV CLASS=EXAMPLE>{@code 173 * final Options options = new Options(); 174 * 175 * options.addOption(new Option("d", "debug", false, "Turn on debug.")); 176 * options.addOption(new Option("e", "extract", false, "Turn on extract.")); 177 * options.addOption(new Option("o", "option", true, "Turn on option with argument.")); 178 * }</DIV> 179 * 180 * <BR /><BR />with "partial matching" turned on, {@code -de} only matches the {@code "debug"} 181 * option. However, with "partial matching" disabled, {@code -de} would enable both 182 * {@code debug} as well as {@code extract} options. 183 */ 184 public DefaultParser() 185 { 186 this.allowPartialMatching = true; 187 this.stripLeadingAndTrailingQuotes = null; 188 } 189 190 /** 191 * Create a new DefaultParser instance with the specified partial matching policy. 192 * 193 * <BR /><BR />By "partial matching" we mean that given the following code: 194 * 195 * <DIV CLASS=EXAMPLE>{@code 196 * final Options options = new Options(); 197 * 198 * options.addOption(new Option("d", "debug", false, "Turn on debug.")); 199 * options.addOption(new Option("e", "extract", false, "Turn on extract.")); 200 * options.addOption(new Option("o", "option", true, "Turn on option with argument.")); 201 * }</DIV> 202 * 203 * <BR /><BR />with "partial matching" turned on, {@code -de} only matches the {@code "debug"} 204 * option. However, with "partial matching" disabled, {@code -de} would enable both 205 * {@code debug} as well as {@code extract} options. 206 * 207 * @param allowPartialMatching if partial matching of long options shall be enabled 208 */ 209 public DefaultParser(final boolean allowPartialMatching) 210 { 211 this.allowPartialMatching = allowPartialMatching; 212 this.stripLeadingAndTrailingQuotes = null; 213 } 214 215 /** 216 * Creates a new DefaultParser instance with the specified partial matching and quote 217 * stripping policy. 218 * 219 * @param allowPartialMatching if partial matching of long options shall be enabled 220 * @param stripLeadingAndTrailingQuotes if balanced outer double quoutes should be stripped 221 */ 222 private DefaultParser( 223 final boolean allowPartialMatching, 224 final Boolean stripLeadingAndTrailingQuotes 225 ) 226 { 227 this.allowPartialMatching = allowPartialMatching; 228 this.stripLeadingAndTrailingQuotes = stripLeadingAndTrailingQuotes; 229 } 230 231 // Throws a {@link MissingArgumentException} if the current option didn't receive the number of 232 // arguments expected. 233 234 private void checkRequiredArgs() throws ParseException 235 { 236 if (currentOption != null && currentOption.requiresArg()) 237 throw new MissingArgumentException(currentOption); 238 } 239 240 /** 241 * Throws a {@link MissingOptionException} if all of the required options are not present. 242 * @throws MissingOptionException if any of the required Options are not present. 243 */ 244 protected void checkRequiredOptions() throws MissingOptionException 245 { 246 // if there are required options that have not been processed 247 if (!expectedOpts.isEmpty()) throw new MissingOptionException(expectedOpts); 248 } 249 250 /** 251 * Searches for a prefix that is the long name of an option (-Xmx512m) 252 * @param token 253 */ 254 private String getLongPrefix(final String token) 255 { 256 final String t = Util.stripLeadingHyphens(token); 257 258 int i; 259 String opt = null; 260 261 for (i = t.length() - 2; i > 1; i--) 262 { 263 final String prefix = t.substring(0, i); 264 265 if (options.hasLongOption(prefix)) 266 { 267 opt = prefix; 268 break; 269 } 270 } 271 272 return opt; 273 } 274 275 /** 276 * Gets a list of matching option strings for the given token, depending on the selected 277 * partial matching policy. 278 * 279 * @param token the token (may contain leading dashes) 280 * 281 * @return the list of matching option strings or an empty list if no matching option could be 282 * found 283 */ 284 private List<String> getMatchingLongOptions(final String token) 285 { 286 if (allowPartialMatching) return options.getMatchingOptions(token); 287 288 final List<String> matches = new ArrayList<>(1); 289 290 if (options.hasLongOption(token)) 291 { 292 final Option option = options.getOption(token); 293 matches.add(option.getLongOpt()); 294 } 295 296 return matches; 297 } 298 299 /** 300 * Breaks {@code token} into its constituent parts using the following algorithm. 301 * 302 * <UL CLASS=JDUL> 303 * 304 * <LI>ignore the first character ("<b>-</b>")</LI> 305 * <LI>for each remaining character check if an {@link Option} exists with that id.</LI> 306 * 307 * <LI> if an {@link Option} does exist then add that character prepended with "<b>-</b>" to 308 * the list of processed tokens. 309 * </LI> 310 * 311 * <LI> if the {@link Option} can have an argument value and there are remaining characters in 312 * the token then add the remaining characters as a token to the list of processed tokens. 313 * </LI> 314 * 315 * <LI> if an {@link Option} does <b>NOT</b> exist <b>AND</b> {@code stopAtNonOption} <b>IS</b> 316 * set then add the special token "<b>--</b>" followed by the remaining characters and 317 * also the remaining tokens directly to the processed tokens list. 318 * </LI> 319 * 320 * <LI> if an {@link Option} does <b>NOT</b> exist <b>AND</b> {@code stopAtNonOption} <b>IS 321 * NOT</b> set then add that character prepended with "<b>-</b>". 322 * </LI> 323 * 324 * </UL> 325 * 326 * @param token The current token to be <b>burst</b> at the first non-Option encountered. 327 * 328 * @throws ParseException if there are any problems encountered while parsing the command line 329 * token. 330 */ 331 protected void handleConcatenatedOptions(final String token) throws ParseException 332 { 333 for (int i = 1; i < token.length(); i++) 334 { 335 final String ch = String.valueOf(token.charAt(i)); 336 337 if (!options.hasOption(ch)) 338 { 339 handleUnknownToken(stopAtNonOption && i > 1 ? token.substring(i) : token); 340 break; 341 } 342 343 handleOption(options.getOption(ch)); 344 345 if (currentOption != null && token.length() != i + 1) 346 { 347 // add the trail as an argument of the option 348 currentOption.addValueForProcessing(stripLeadingAndTrailingQuotesDefaultOff(token.substring(i + 1))); 349 break; 350 } 351 } 352 } 353 354 /** 355 * Handles the following tokens: {@code --L --L=V --L V --l} 356 * @param token the command line token to handle 357 */ 358 private void handleLongOption(final String token) throws ParseException 359 { 360 if (token.indexOf('=') == -1) handleLongOptionWithoutEqual(token); 361 else handleLongOptionWithEqual(token); 362 } 363 364 /** 365 * Handles the following tokens: {@code --L=V -L=V --l=V -l=V} 366 * @param token the command line token to handle 367 */ 368 private void handleLongOptionWithEqual(final String token) throws ParseException 369 { 370 final int pos = token.indexOf('='); 371 final String value = token.substring(pos + 1); 372 final String opt = token.substring(0, pos); 373 374 final List<String> matchingOpts = getMatchingLongOptions(opt); 375 376 if (matchingOpts.isEmpty()) 377 handleUnknownToken(currentToken); 378 379 else if (matchingOpts.size() > 1 && !options.hasLongOption(opt)) 380 throw new AmbiguousOptionException(opt, matchingOpts); 381 382 else 383 { 384 final String key = options.hasLongOption(opt) ? opt : matchingOpts.get(0); 385 final Option option = options.getOption(key); 386 387 if (option.acceptsArg()) 388 { 389 handleOption(option); 390 391 currentOption.addValueForProcessing 392 (stripLeadingAndTrailingQuotesDefaultOff(value)); 393 394 currentOption = null; 395 } 396 397 else handleUnknownToken(currentToken); 398 } 399 } 400 401 /** 402 * Handles the following tokens: {@code --L -L --l -l} 403 * @param token the command line token to handle 404 */ 405 private void handleLongOptionWithoutEqual(final String token) throws ParseException 406 { 407 final List<String> matchingOpts = getMatchingLongOptions(token); 408 409 if (matchingOpts.isEmpty()) 410 handleUnknownToken(currentToken); 411 412 else if (matchingOpts.size() > 1 && !options.hasLongOption(token)) 413 throw new AmbiguousOptionException(token, matchingOpts); 414 415 else 416 { 417 final String key = options.hasLongOption(token) ? token : matchingOpts.get(0); 418 handleOption(options.getOption(key)); 419 } 420 } 421 422 private void handleOption(Option option) throws ParseException 423 { 424 // check the previous option before handling the next one 425 checkRequiredArgs(); 426 427 option = (Option) option.clone(); 428 429 updateRequiredOptions(option); 430 431 cmd.addOption(option); 432 433 currentOption = option.hasArg() ? option : null; 434 } 435 436 /** 437 * Sets the values of Options using the values in {@code properties}. 438 * @param properties The value properties to be processed. 439 */ 440 private void handleProperties(final Properties properties) throws ParseException 441 { 442 if (properties == null) return; 443 444 for (final Enumeration<?> e = properties.propertyNames(); e.hasMoreElements();) 445 { 446 final String option = e.nextElement().toString(); 447 448 final Option opt = options.getOption(option); 449 450 if (opt == null) 451 throw new UnrecognizedOptionException("Default option wasn't defined", option); 452 453 // if the option is part of a group, check if another option of the group has been 454 // selected 455 456 final OptionGroup group = options.getOptionGroup(opt); 457 final boolean selected = group != null && group.getSelected() != null; 458 459 if (!cmd.hasOption(option) && !selected) 460 { 461 // get the value from the properties 462 final String value = properties.getProperty(option); 463 464 if (opt.hasArg()) 465 { 466 if (opt.getValues() == null || opt.getValues().length == 0) 467 opt.addValueForProcessing(stripLeadingAndTrailingQuotesDefaultOff(value)); 468 } 469 470 else if (!( "yes".equalsIgnoreCase(value) 471 || "true".equalsIgnoreCase(value) 472 || "1".equalsIgnoreCase(value) 473 )) 474 475 // if the value is not yes, true or 1 then don't add the option to the 476 // CommandLine 477 continue; 478 479 handleOption(opt); 480 currentOption = null; 481 } 482 } 483 } 484 485 /** 486 * Handles the following tokens: 487 * 488 * <BR /><BR /><UL CLASS=JDUL> 489 * <LI>{@code -S -SV -S V -S=V -S1S2 -S1S2 V -SV1=V2}</LI> 490 * <LI>{@code -L -LV -L V -L=V -l}</LI> 491 * </UL> 492 * 493 * @param token the command line token to handle 494 */ 495 private void handleShortAndLongOption(final String token) throws ParseException 496 { 497 final String t = Util.stripLeadingHyphens(token); 498 499 final int pos = t.indexOf('='); 500 501 if (t.length() == 1) 502 { 503 // -S 504 if (options.hasShortOption(t)) handleOption(options.getOption(t)); 505 else handleUnknownToken(token); 506 } 507 508 else if (pos == -1) 509 { 510 // no equal sign found (-xxx) 511 if (options.hasShortOption(t)) handleOption(options.getOption(t)); 512 513 else if (!getMatchingLongOptions(t).isEmpty()) 514 // -L or -l 515 handleLongOptionWithoutEqual(token); 516 517 else 518 { 519 // look for a long prefix (-Xmx512m) 520 final String opt = getLongPrefix(t); 521 522 if (opt != null && options.getOption(opt).acceptsArg()) 523 { 524 handleOption(options.getOption(opt)); 525 currentOption.addValueForProcessing(stripLeadingAndTrailingQuotesDefaultOff(t.substring(opt.length()))); 526 currentOption = null; 527 } 528 529 else if (isJavaProperty(t)) 530 { 531 // -SV1 (-Dflag) 532 handleOption(options.getOption(t.substring(0, 1))); 533 currentOption.addValueForProcessing(stripLeadingAndTrailingQuotesDefaultOff(t.substring(1))); 534 currentOption = null; 535 } 536 537 else 538 // -S1S2S3 or -S1S2V 539 handleConcatenatedOptions(token); 540 } 541 } 542 543 else 544 { 545 // equal sign found (-xxx=yyy) 546 final String opt = t.substring(0, pos); 547 final String value = t.substring(pos + 1); 548 549 if (opt.length() == 1) 550 { 551 // -S=V 552 final Option option = options.getOption(opt); 553 554 if (option != null && option.acceptsArg()) 555 { 556 handleOption(option); 557 currentOption.addValueForProcessing(value); 558 currentOption = null; 559 } 560 561 else handleUnknownToken(token); 562 } 563 564 else if (isJavaProperty(opt)) 565 { 566 // -SV1=V2 (-Dkey=value) 567 handleOption(options.getOption(opt.substring(0, 1))); 568 569 currentOption.addValueForProcessing(opt.substring(1)); 570 currentOption.addValueForProcessing(value); 571 572 currentOption = null; 573 } 574 575 else 576 // -L=V or -l=V 577 handleLongOptionWithEqual(token); 578 } 579 } 580 581 /** 582 * Handles any command line token. 583 * @param token the command line token to handle 584 * @throws ParseException 585 */ 586 private void handleToken(final String token) throws ParseException 587 { 588 currentToken = token; 589 590 if (skipParsing) cmd.addArg(token); 591 else if ("--".equals(token)) skipParsing = true; 592 593 else if (currentOption != null && currentOption.acceptsArg() && isArgument(token)) 594 currentOption.addValueForProcessing(stripLeadingAndTrailingQuotesDefaultOn(token)); 595 596 else if (token.startsWith("--")) handleLongOption(token); 597 else if (token.startsWith("-") && !"-".equals(token)) handleShortAndLongOption(token); 598 else handleUnknownToken(token); 599 600 if (currentOption != null && !currentOption.acceptsArg()) 601 currentOption = null; 602 } 603 604 /** 605 * Handles an unknown token. If the token starts with a dash an UnrecognizedOptionException is thrown. Otherwise the 606 * token is added to the arguments of the command line. If the stopAtNonOption flag is set, this stops the parsing and 607 * the remaining tokens are added as-is in the arguments of the command line. 608 * 609 * @param token the command line token to handle 610 */ 611 private void handleUnknownToken(final String token) throws ParseException 612 { 613 if (token.startsWith("-") && token.length() > 1 && !stopAtNonOption) 614 throw new UnrecognizedOptionException("Unrecognized option: " + token, token); 615 616 cmd.addArg(token); 617 618 if (stopAtNonOption) skipParsing = true; 619 } 620 621 /** 622 * Tests if the token is a valid argument. 623 * @param token 624 */ 625 private boolean isArgument(final String token) 626 { return !isOption(token) || isNegativeNumber(token); } 627 628 // Tests if the specified token is a Java-like property (-Dkey=value). 629 private boolean isJavaProperty(final String token) 630 { 631 final String opt = token.isEmpty() ? null : token.substring(0, 1); 632 final Option option = options.getOption(opt); 633 634 return option != null 635 && (option.getArgs() >= 2 || option.getArgs() == Option.UNLIMITED_VALUES); 636 } 637 638 // Tests if the token looks like a long option. 639 private boolean isLongOption(final String token) 640 { 641 if (token == null || !token.startsWith("-") || token.length() == 1) return false; 642 643 final int pos = token.indexOf("="); 644 645 final String t = pos == -1 ? token : token.substring(0, pos); 646 647 if (!getMatchingLongOptions(t).isEmpty()) 648 649 // long or partial long options (--L, -L, --L=V, -L=V, --l, --l=V) 650 return true; 651 652 if (getLongPrefix(token) != null && !token.startsWith("--")) 653 654 // -LV 655 return true; 656 657 return false; 658 } 659 660 // Tests if the token is a negative number. 661 private boolean isNegativeNumber(final String token) 662 { 663 try 664 { 665 Double.parseDouble(token); 666 return true; 667 } 668 669 catch (final NumberFormatException e) 670 { return false; } 671 } 672 673 // Tests if the token looks like an option. 674 private boolean isOption(final String token) 675 { return isLongOption(token) || isShortOption(token); } 676 677 // Tests if the token looks like a short option. 678 private boolean isShortOption(final String token) 679 { 680 // short options (-S, -SV, -S=V, -SV1=V2, -S1S2) 681 if (token == null || !token.startsWith("-") || token.length() == 1) return false; 682 683 // remove leading "-" and "=value" 684 final int pos = token.indexOf("="); 685 final String optName = pos == -1 ? token.substring(1) : token.substring(1, pos); 686 687 if (options.hasShortOption(optName)) return true; 688 689 // check for several concatenated short options 690 return !optName.isEmpty() 691 && options.hasShortOption(String.valueOf(optName.charAt(0))); 692 } 693 694 @Override 695 public CommandLine parse(final Options options, final String[] arguments) 696 throws ParseException 697 { return parse(options, arguments, null); } 698 699 @Override 700 public CommandLine parse 701 (final Options options, final String[] arguments, final boolean stopAtNonOption) 702 throws ParseException 703 { return parse(options, arguments, null, stopAtNonOption); } 704 705 /** 706 * Parses the arguments according to the specified options and properties. 707 * @param options the specified Options 708 * @param arguments the command line arguments 709 * @param properties command line option name-value pairs 710 * @return the list of atomic option and value tokens 711 * 712 * @throws ParseException if there are any problems encountered while parsing the command line 713 * tokens. 714 */ 715 public CommandLine parse 716 (final Options options, final String[] arguments, final Properties properties) 717 throws ParseException 718 { return parse(options, arguments, properties, false); } 719 720 /** 721 * Parses the arguments according to the specified options and properties. 722 * @param options the specified Options 723 * @param arguments the command line arguments 724 * @param properties command line option name-value pairs 725 * 726 * @param stopAtNonOption if {@code true} an unrecognized argument stops the parsing and the 727 * remaining arguments are added to the {@link CommandLine}s args list. If {@code false} an 728 * unrecognized argument triggers a ParseException. 729 * 730 * @return the list of atomic option and value tokens 731 * 732 * @throws ParseException if there are any problems encountered while parsing the command line 733 * tokens. 734 */ 735 public CommandLine parse( 736 final Options options, 737 final String[] arguments, 738 final Properties properties, 739 final boolean stopAtNonOption 740 ) 741 throws ParseException 742 { 743 this.options = options; 744 this.stopAtNonOption = stopAtNonOption; 745 746 skipParsing = false; 747 currentOption = null; 748 expectedOpts = new ArrayList<>(options.getRequiredOptions()); 749 750 // clear the data from the groups 751 for (final OptionGroup group : options.getOptionGroups()) group.setSelected(null); 752 753 cmd = new CommandLine(); 754 755 if (arguments != null) 756 for (final String argument : arguments) handleToken(argument); 757 758 // check the arguments of the last option 759 checkRequiredArgs(); 760 761 // add the default options 762 handleProperties(properties); 763 764 checkRequiredOptions(); 765 766 return cmd; 767 } 768 769 /** 770 * Strips balanced leading and trailing quotes if the stripLeadingAndTrailingQuotes is set 771 * If stripLeadingAndTrailingQuotes is null, then do not strip 772 * 773 * @param token a string 774 * @return token with the quotes stripped (if set) 775 */ 776 private String stripLeadingAndTrailingQuotesDefaultOff(final String token) 777 { 778 if (stripLeadingAndTrailingQuotes != null && stripLeadingAndTrailingQuotes) 779 return Util.stripLeadingAndTrailingQuotes(token); 780 781 return token; 782 } 783 784 /** 785 * Strips balanced leading and trailing quotes if the stripLeadingAndTrailingQuotes is set 786 * If stripLeadingAndTrailingQuotes is null, then do not strip 787 * 788 * @param token a string 789 * @return token with the quotes stripped (if set) 790 */ 791 private String stripLeadingAndTrailingQuotesDefaultOn(final String token) 792 { 793 if (stripLeadingAndTrailingQuotes == null || stripLeadingAndTrailingQuotes) 794 return Util.stripLeadingAndTrailingQuotes(token); 795 796 return token; 797 } 798 799 // Removes the option or its group from the list of expected elements. 800 private void updateRequiredOptions(final Option option) throws AlreadySelectedException 801 { 802 if (option.isRequired()) expectedOpts.remove(option.getKey()); 803 804 // if the option is in an OptionGroup make that option the selected option of the group 805 if (options.getOptionGroup(option) != null) 806 { 807 final OptionGroup group = options.getOptionGroup(option); 808 809 if (group.isRequired()) expectedOpts.remove(group); 810 811 group.setSelected(option); 812 } 813 } 814}