@@ -55,6 +55,9 @@ public class DefaultParser implements CommandLineParser {
5555 /** Flag indicating if partial matching of long options is supported. */
5656 private final boolean allowPartialMatching ;
5757
58+ /** Flag indicating if balanced leading and trailing double quotes should be stripped from option arguments. */
59+ private final boolean stripLeadingAndTrailingQuotes ;
60+
5861 /**
5962 * Creates a new DefaultParser instance with partial matching enabled.
6063 *
@@ -76,6 +79,7 @@ public class DefaultParser implements CommandLineParser {
7679 */
7780 public DefaultParser () {
7881 this .allowPartialMatching = true ;
82+ this .stripLeadingAndTrailingQuotes = true ;
7983 }
8084
8185 /**
@@ -101,6 +105,20 @@ public DefaultParser() {
101105 */
102106 public DefaultParser (final boolean allowPartialMatching ) {
103107 this .allowPartialMatching = allowPartialMatching ;
108+ this .stripLeadingAndTrailingQuotes = true ;
109+ }
110+
111+ /**
112+ * Create a new DefaultParser instance with the specified partial matching and quote
113+ * stripping policy.
114+ *
115+ * @param allowPartialMatching if partial matching of long options shall be enabled
116+ * @param stripLeadingAndTrailingQuotes if balanced outer double quoutes should be stripped
117+ */
118+ private DefaultParser (final boolean allowPartialMatching ,
119+ final boolean stripLeadingAndTrailingQuotes ) {
120+ this .allowPartialMatching = allowPartialMatching ;
121+ this .stripLeadingAndTrailingQuotes = stripLeadingAndTrailingQuotes ;
104122 }
105123
106124 /**
@@ -415,7 +433,7 @@ private void handleToken(final String token) throws ParseException {
415433 } else if ("--" .equals (token )) {
416434 skipParsing = true ;
417435 } else if (currentOption != null && currentOption .acceptsArg () && isArgument (token )) {
418- currentOption .addValueForProcessing (Util . stripLeadingAndTrailingQuotes (token ));
436+ currentOption .addValueForProcessing (conditionallyStripLeadingAndTrailingQuotes (token ));
419437 } else if (token .startsWith ("--" )) {
420438 handleLongOption (token );
421439 } else if (token .startsWith ("-" ) && !"-" .equals (token )) {
@@ -625,4 +643,117 @@ private void updateRequiredOptions(final Option option) throws AlreadySelectedEx
625643 group .setSelected (option );
626644 }
627645 }
646+
647+ /**
648+ * Strip balanced leading and trailing quotes if the stripLeadingAndTrailingQuotes is set
649+ *
650+ * @param token
651+ * @return token with the quotes stripped (if set)
652+ */
653+ protected String conditionallyStripLeadingAndTrailingQuotes (final String token ) {
654+ if (stripLeadingAndTrailingQuotes ) {
655+ return Util .stripLeadingAndTrailingQuotes (token );
656+ } else {
657+ return token ;
658+ }
659+ }
660+
661+ /**
662+ * Returns a {@link Builder} to create an {@link DefaultParser} using descriptive
663+ * methods.
664+ *
665+ * @return a new {@link Builder} instance
666+ * @since 1.5
667+ */
668+ public static Builder builder ()
669+ {
670+ return new Builder ();
671+ }
672+
673+ /**
674+ * A nested builder class to create <code>DefaultParser</code> instances
675+ * using descriptive methods.
676+ * <p>
677+ * Example usage:
678+ * <pre>
679+ * DefaultParser parser = Option.builder()
680+ * .setAllowPartialMatching(false)
681+ * .setStripLeadingAndTrailingQuotes(false)
682+ * .build();
683+ * </pre>
684+ *
685+ * @since 1.5
686+ */
687+ public static final class Builder
688+ {
689+
690+ private boolean allowPartialMatching = true ;
691+
692+ private boolean stripLeadingAndTrailingQuotes = true ;
693+
694+ /**
695+ * Constructs a new <code>Builder</code> for a <code>DefaultParser</code> instance.
696+ *
697+ * Both allowPartialMatching and stripLeadingAndTrailingQuotes are true by default,
698+ * mimicking the argument-less constructor.
699+ */
700+ private Builder ()
701+ {
702+ }
703+
704+ /**
705+ * Sets if partial matching of long options is supported.
706+ *
707+ * By "partial matching" we mean that given the following code:
708+ *
709+ * <pre>
710+ * {
711+ * @code
712+ * final Options options = new Options();
713+ * options.addOption(new Option("d", "debug", false, "Turn on debug."));
714+ * options.addOption(new Option("e", "extract", false, "Turn on extract."));
715+ * options.addOption(new Option("o", "option", true, "Turn on option with argument."));
716+ * }
717+ * </pre>
718+ *
719+ * with "partial matching" turned on, {@code -de} only matches the {@code "debug"} option. However, with
720+ * "partial matching" disabled, {@code -de} would enable both {@code debug} as well as {@code extract}
721+ *
722+ * @param allowPartialMatching whether to allow partial matching of long options
723+ * @return this builder, to allow method chaining
724+ */
725+ public Builder setAllowPartialMatching (final boolean allowPartialMatching )
726+ {
727+ this .allowPartialMatching = allowPartialMatching ;
728+ return this ;
729+ }
730+
731+ /**
732+ * Sets if balanced leading and trailing double quotes should be stripped from option arguments.
733+ *
734+ * with "stripping of balanced leading and trailing double quotes from option arguments" turned
735+ * on, the outermost balanced double quotes of option arguments values will be removed.
736+ * ie.
737+ * for <code>-o '"x"'</code> getValue() will return <code>x</code>, instead of <code>"x"</code>
738+ *
739+ * @param stripLeadingAndTrailingQuotes whether balanced leading and trailing double quotes should be stripped from option arguments.
740+ * @return this builder, to allow method chaining
741+ */
742+ public Builder setStripLeadingAndTrailingQuotes (final boolean stripLeadingAndTrailingQuotes )
743+ {
744+ this .stripLeadingAndTrailingQuotes = stripLeadingAndTrailingQuotes ;
745+ return this ;
746+ }
747+
748+ /**
749+ * Constructs an DefaultParser with the values declared by this {@link Builder}.
750+ *
751+ * @return the new {@link DefaultParser}
752+ */
753+ public DefaultParser build ()
754+ {
755+ return new DefaultParser (allowPartialMatching , stripLeadingAndTrailingQuotes );
756+
757+ }
758+ }
628759}
0 commit comments