🐛 Fixed quoted parsing in StringArgument

This commit is contained in:
Alexander Söderberg 2020-10-17 23:05:28 +02:00 committed by Alexander Söderberg
parent 9bfb0f17d6
commit 720019b508
3 changed files with 51 additions and 23 deletions

View file

@ -37,10 +37,15 @@ import java.util.List;
import java.util.Queue;
import java.util.StringJoiner;
import java.util.function.BiFunction;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@SuppressWarnings("unused")
public final class StringArgument<C> extends CommandArgument<C, String> {
private static final Pattern QUOTED_DOUBLE = Pattern.compile("\"(?<inner>(?:[^\"\\\\]|\\\\.)*)\"");
private static final Pattern QUOTED_SINGLE = Pattern.compile("'(?<inner>(?:[^'\\\\]|\\\\.)*)'");
private final StringMode stringMode;
private StringArgument(
@ -305,6 +310,40 @@ public final class StringArgument<C> extends CommandArgument<C, String> {
}
inputQueue.remove();
return ArgumentParseResult.success(input);
} else if (this.stringMode == StringMode.QUOTED) {
final StringJoiner sj = new StringJoiner(" ");
for (final String string : inputQueue) {
sj.add(string);
}
final String string = sj.toString();
Matcher matcher = QUOTED_DOUBLE.matcher(string);
String inner = null;
if (matcher.find()) {
inner = matcher.group("inner");
} else {
matcher = QUOTED_SINGLE.matcher(string);
if (matcher.find()) {
inner = matcher.group("inner");
}
}
if (inner != null) {
final int numSpaces = (int) inner.chars().filter(c -> c == ' ').count();
for (int i = 0; i <= numSpaces; i++) {
inputQueue.remove();
}
} else {
inner = inputQueue.remove();
if (inner.startsWith("\"") || inner.startsWith("'")) {
return ArgumentParseResult.failure(new StringParseException(sj.toString(),
StringMode.QUOTED, commandContext));
}
}
inner = inner.replace("\\\"", "\"").replace("\\\'", "\"");
return ArgumentParseResult.success(inner);
}
final StringJoiner sj = new StringJoiner(" ");
@ -321,33 +360,10 @@ public final class StringArgument<C> extends CommandArgument<C, String> {
break;
}
if (this.stringMode == StringMode.QUOTED) {
if (!started) {
if (string.startsWith("\"") || string.startsWith("'")) {
start = string.charAt(0);
string = string.substring(1);
started = true;
} else {
/* Just read a single string instead */
inputQueue.remove();
return ArgumentParseResult.success(string);
}
} else if (string.endsWith(Character.toString(start))) {
sj.add(string.substring(0, string.length() - 1));
inputQueue.remove();
finished = true;
break;
}
}
sj.add(string);
inputQueue.remove();
}
if (this.stringMode == StringMode.QUOTED && !finished) {
return ArgumentParseResult.failure(new StringParseException(sj.toString(), StringMode.QUOTED, commandContext));
}
return ArgumentParseResult.success(sj.toString());
}

View file

@ -30,6 +30,8 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.concurrent.CompletionException;
class StringArgumentTest {
private static final String[] storage = new String[2];
@ -85,6 +87,13 @@ class StringArgumentTest {
manager.executeCommand(new TestCommandSender(), "quoted quoted unquoted");
Assertions.assertEquals("quoted", storage[0]);
Assertions.assertEquals("unquoted", storage[1]);
clear();
manager.executeCommand(new TestCommandSender(), "quoted \"quoted \\\" string\" unquoted").join();
Assertions.assertEquals("quoted \" string", storage[0]);
Assertions.assertEquals("unquoted", storage[1]);
clear();
Assertions.assertThrows(CompletionException.class, () -> manager.executeCommand(new TestCommandSender(),
"'quoted quoted unquoted").join());
}
@Test