private String unquote(String value) { if (!commandSpec.parser().trimQuotes()) { return value; } return value == null ? null : (value.length() > 1 && value.startsWith("\"") && value.endsWith("\"")) ? value.substring(1, value.length() - 1) : value; }
private static String restoreQuotedValues(String part, Queue<String> quotedValues, ParserSpec parser) { StringBuilder result = new StringBuilder(); boolean escaping = false, inQuote = false, skip = false; for (int ch = 0, i = 0; i < part.length(); i += Character.charCount(ch)) { ch = part.codePointAt(i); switch (ch) { case '\\': escaping = !escaping; break; case '\"': if (!escaping) { inQuote = !inQuote; if (!inQuote) { result.append(quotedValues.remove()); } skip = parser.trimQuotes(); } break; default: escaping = false; break; } if (!skip) { result.appendCodePoint(ch); } skip = false; } return result.toString(); }
@SuppressWarnings("unchecked") @Test public void testInterpreterApplyValueToSingleValuedField() throws Exception { Class c = Class.forName("picocli.CommandLine$Interpreter"); Class lookBehindClass = Class.forName("picocli.CommandLine$LookBehind"); Method applyValueToSingleValuedField = c.getDeclaredMethod("applyValueToSingleValuedField", ArgSpec.class, lookBehindClass, Range.class, Stack.class, Set.class, String.class); applyValueToSingleValuedField.setAccessible(true); CommandSpec spec = CommandSpec.create(); spec.parser().trimQuotes(true); CommandLine cmd = new CommandLine(spec); Object interpreter = PicocliTestUtil.interpreter(cmd); Method clear = c.getDeclaredMethod("clear"); clear.setAccessible(true); clear.invoke(interpreter); // initializes the interpreter instance PositionalParamSpec arg = PositionalParamSpec.builder().arity("1").build(); Object SEPARATE = lookBehindClass.getDeclaredField("SEPARATE").get(null); int value = (Integer) applyValueToSingleValuedField.invoke(interpreter, arg, SEPARATE, Range.valueOf("1"), new Stack<String>(), new HashSet<String>(), ""); assertEquals(0, value); }
@SuppressWarnings("unchecked") @Test public void testInterpreterApplyValueToSingleValuedField() throws Exception { Class c = Class.forName("picocli.CommandLine$Interpreter"); Class lookBehindClass = Class.forName("picocli.CommandLine$LookBehind"); Method applyValueToSingleValuedField = c.getDeclaredMethod("applyValueToSingleValuedField", ArgSpec.class, lookBehindClass, Range.class, Stack.class, Set.class, String.class); applyValueToSingleValuedField.setAccessible(true); CommandSpec spec = CommandSpec.create(); spec.parser().trimQuotes(true); CommandLine cmd = new CommandLine(spec); Object interpreter = PicocliTestUtil.interpreter(cmd); Method clear = c.getDeclaredMethod("clear"); clear.setAccessible(true); clear.invoke(interpreter); // initializes the interpreter instance PositionalParamSpec arg = PositionalParamSpec.builder().arity("1").build(); Object SEPARATE = lookBehindClass.getDeclaredField("SEPARATE").get(null); int value = (Integer) applyValueToSingleValuedField.invoke(interpreter, arg, SEPARATE, Range.valueOf("1"), new Stack<String>(), new HashSet<String>(), ""); assertEquals(0, value); }
private String restoreQuotedValues(String part, Queue<String> quotedValues, ParserSpec parser) { StringBuilder result = new StringBuilder(); boolean escaping = false, inQuote = false, skip = false; for (int ch = 0, i = 0; i < part.length(); i += Character.charCount(ch)) { ch = part.codePointAt(i); switch (ch) { case '\\': escaping = !escaping; break; case '\"': if (!escaping) { inQuote = !inQuote; if (!inQuote) { result.append(quotedValues.remove()); } skip = parser.trimQuotes(); } break; default: escaping = false; break; } if (!skip) { result.appendCodePoint(ch); } skip = false; } return result.toString(); }
/** Sets whether the parser should trim quotes from command line arguments before processing them. The default is * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is set and empty, or * if its value is "true". * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.</p> * <p>Calling this method will cause the "picocli.trimQuotes" property to have no effect.</p> * @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 3.7 */ public CommandLine setTrimQuotes(boolean newValue) { getCommandSpec().parser().trimQuotes(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setTrimQuotes(newValue); } return this; }
@SuppressWarnings("unchecked") @Ignore @Test public void testInterpreterProcessClusteredShortOptions() throws Exception { Class c = Class.forName("picocli.CommandLine$Interpreter"); Method processClusteredShortOptions = c.getDeclaredMethod("processClusteredShortOptions", Collection.class, Set.class, String.class, Stack.class); processClusteredShortOptions.setAccessible(true); CommandSpec spec = CommandSpec.create(); spec.addOption(OptionSpec.builder("-x").arity("0").build()); spec.parser().trimQuotes(true); CommandLine cmd = new CommandLine(spec); Object interpreter = PicocliTestUtil.interpreter(cmd); Stack<String> stack = new Stack<String>(); String arg = "-xa"; processClusteredShortOptions.invoke(interpreter, new ArrayList<ArgSpec>(), new HashSet<String>(), arg, stack); // TODO }
@SuppressWarnings("unchecked") @Test public void testInterpreterUnquote() throws Exception { Class c = Class.forName("picocli.CommandLine$Interpreter"); Method unquote = c.getDeclaredMethod("unquote", String.class); unquote.setAccessible(true); CommandSpec spec = CommandSpec.create(); spec.parser().trimQuotes(true); CommandLine cmd = new CommandLine(spec); Object interpreter = PicocliTestUtil.interpreter(cmd); assertNull(unquote.invoke(interpreter, new Object[]{null})); assertEquals("abc", unquote.invoke(interpreter, "\"abc\"")); assertEquals("", unquote.invoke(interpreter, "\"\"")); assertEquals("only balanced quotes 1", "\"abc", unquote.invoke(interpreter, "\"abc")); assertEquals("only balanced quotes 2", "abc\"", unquote.invoke(interpreter, "abc\"")); assertEquals("only balanced quotes 3", "\"", unquote.invoke(interpreter, "\"")); assertEquals("no quotes", "X", unquote.invoke(interpreter, "X")); }
@Test public void testArgSpecSplitValue_MultipleQuotedValues_QuotesTrimmedIfRequested() { ParserSpec parser = new ParserSpec().trimQuotes(true); ArgSpec spec = PositionalParamSpec.builder().splitRegex(",").build(); String[] actual = spec.splitValue("a,b,\"c,d,e\",f,\"xxx,yyy\"", parser, Range.valueOf("0"), 0); assertArrayEquals(new String[]{"a", "b", "c,d,e", "f", "xxx,yyy"}, actual); }
private String unquote(String value) { if (!commandSpec.parser().trimQuotes()) { return value; } return value == null ? null : (value.length() > 1 && value.startsWith("\"") && value.endsWith("\"")) ? value.substring(1, value.length() - 1) : value; }
/** Returns whether the parser should trim quotes from command line arguments before processing them. The default is * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is present and empty, * or if its value is "true". * @return {@code true} if the parser should trim quotes from command line arguments before processing them, {@code false} otherwise; * @since 3.7 */ public boolean isTrimQuotes() { return getCommandSpec().parser().trimQuotes(); }
/** Sets whether the parser should trim quotes from command line arguments before processing them. The default is * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is set and empty, or * if its value is "true". * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added * later will have the default setting. To ensure a setting is applied to all * subcommands, call the setter last, after adding subcommands.</p> * <p>Calling this method will cause the "picocli.trimQuotes" property to have no effect.</p> * @param newValue the new setting * @return this {@code CommandLine} object, to allow method chaining * @since 3.7 */ public CommandLine setTrimQuotes(boolean newValue) { getCommandSpec().parser().trimQuotes(newValue); for (CommandLine command : getCommandSpec().subcommands().values()) { command.setTrimQuotes(newValue); } return this; }
@SuppressWarnings("unchecked") @Ignore @Test public void testInterpreterProcessClusteredShortOptions() throws Exception { Class c = Class.forName("picocli.CommandLine$Interpreter"); Method processClusteredShortOptions = c.getDeclaredMethod("processClusteredShortOptions", Collection.class, Set.class, String.class, Stack.class); processClusteredShortOptions.setAccessible(true); CommandSpec spec = CommandSpec.create(); spec.addOption(OptionSpec.builder("-x").arity("0").build()); spec.parser().trimQuotes(true); CommandLine cmd = new CommandLine(spec); Object interpreter = PicocliTestUtil.interpreter(cmd); Stack<String> stack = new Stack<String>(); String arg = "-xa"; processClusteredShortOptions.invoke(interpreter, new ArrayList<ArgSpec>(), new HashSet<String>(), arg, stack); // TODO }
@SuppressWarnings("unchecked") @Test public void testInterpreterUnquote() throws Exception { Class c = Class.forName("picocli.CommandLine$Interpreter"); Method unquote = c.getDeclaredMethod("unquote", String.class); unquote.setAccessible(true); CommandSpec spec = CommandSpec.create(); spec.parser().trimQuotes(true); CommandLine cmd = new CommandLine(spec); Object interpreter = PicocliTestUtil.interpreter(cmd); assertNull(unquote.invoke(interpreter, new Object[]{null})); assertEquals("abc", unquote.invoke(interpreter, "\"abc\"")); assertEquals("", unquote.invoke(interpreter, "\"\"")); assertEquals("only balanced quotes 1", "\"abc", unquote.invoke(interpreter, "\"abc")); assertEquals("only balanced quotes 2", "abc\"", unquote.invoke(interpreter, "abc\"")); assertEquals("only balanced quotes 3", "\"", unquote.invoke(interpreter, "\"")); assertEquals("no quotes", "X", unquote.invoke(interpreter, "X")); }
@Test public void testArgSpecSplitValue_MultipleQuotedValues_QuotesTrimmedIfRequested() { ParserSpec parser = new ParserSpec().trimQuotes(true); ArgSpec spec = PositionalParamSpec.builder().splitRegex(",").build(); String[] actual = spec.splitValue("a,b,\"c,d,e\",f,\"xxx,yyy\"", parser, Range.valueOf("0"), 0); assertArrayEquals(new String[]{"a", "b", "c,d,e", "f", "xxx,yyy"}, actual); }
/** Returns whether the parser should trim quotes from command line arguments before processing them. The default is * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is present and empty, * or if its value is "true". * @return {@code true} if the parser should trim quotes from command line arguments before processing them, {@code false} otherwise; * @since 3.7 */ public boolean isTrimQuotes() { return getCommandSpec().parser().trimQuotes(); }