From 2f390e9938fd127846aac3e790d9507514827ba8 Mon Sep 17 00:00:00 2001 From: zml2008 Date: Tue, 13 Sep 2011 22:41:19 -0700 Subject: [PATCH] Added multiword args and some improvements to value flags. --- .../minecraft/util/commands/Command.java | 10 +- .../util/commands/CommandContext.java | 122 ++++++------------ .../util/commands/CommandsManager.java | 32 +++-- src/main/java/com/sk89q/util/ArrayUtil.java | 22 ++++ 4 files changed, 91 insertions(+), 95 deletions(-) create mode 100644 src/main/java/com/sk89q/util/ArrayUtil.java diff --git a/src/main/java/com/sk89q/minecraft/util/commands/Command.java b/src/main/java/com/sk89q/minecraft/util/commands/Command.java index 0e164fcc1..ca4ef0269 100644 --- a/src/main/java/com/sk89q/minecraft/util/commands/Command.java +++ b/src/main/java/com/sk89q/minecraft/util/commands/Command.java @@ -63,15 +63,9 @@ public @interface Command { * Flags allow special processing for flags such as -h in the command, * allowing users to easily turn on a flag. This is a string with * each character being a flag. Use A-Z and a-z as possible flags. + * Appending a flag with a : makes the flag character before a value flag, + * meaning that if it is given it must have a value */ String flags() default ""; - - /** - * Value flags are special flags, that take a value after the flag. - * The semantics are the same as with the flags parameter. - * They aren't automatically documented and thus need to be added - * to the "usage" parameter separately. - */ - String valueFlags() default ""; } diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java index 94fce79b5..5f88d0d3e 100644 --- a/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandContext.java @@ -18,11 +18,11 @@ package com.sk89q.minecraft.util.commands; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import static com.sk89q.util.ArrayUtil.removePortionOfArray; public class CommandContext { protected static final String QUOTE_CHARS = "\'\""; @@ -30,16 +30,30 @@ public class CommandContext { protected final Set booleanFlags = new HashSet(); protected final Map valueFlags = new HashMap(); - public CommandContext(String args) { - this(args.split(" ")); + public CommandContext(String args) throws CommandException { + this(args.split(" "), null); } - public CommandContext(String[] args) { - char quotedChar; - for (int i = 1; i < args.length; ++i) { - if (args[i].length() == 0) { + public CommandContext(String[] args) throws CommandException { + this(args, null); + } + + public CommandContext(String args, Set valueFlags) throws CommandException { + this(args.split(" "), valueFlags); + } + + /** + * @param args An array with arguments empty strings will be ignored by most things + * @param valueFlags A set containing all value flags. Pass null to disable value flag parsing. + * @throws CommandException This is thrown if a value flag was passed without a value. + */ + public CommandContext(String[] args, Set valueFlags) throws CommandException { + // Go through empty args and multiword args first + for (int i = 1; i < args.length; i++) { + char quotedChar; + if (args[i].length() < 1) { args = removePortionOfArray(args, i, i, null); - } else if (QUOTE_CHARS.indexOf(String.valueOf(args[i].charAt(0))) != -1) { + } else if (QUOTE_CHARS.indexOf(args[i].charAt(0)) != -1) { StringBuilder build = new StringBuilder(); quotedChar = args[i].charAt(0); int endIndex = i; @@ -55,76 +69,35 @@ public class CommandContext { } } args = removePortionOfArray(args, i, endIndex, build.toString()); - } else if (args[i].charAt(0) == '-' && args[i].matches("^-[a-zA-Z]+$")) { + } + } + // Then flags + for (int i = 1; i < args.length; ++i) { + if (args[i].charAt(0) == '-' && args[i].matches("^-[a-zA-Z]+$")) { for (int k = 1; k < args[i].length(); ++k) { - booleanFlags.add(args[i].charAt(k)); + if (valueFlags != null && valueFlags.contains(args[i].charAt(k))) { + int index = i + 1; + if (args.length - 1 < index) { + throw new CommandException("Value flag '" + args[i].charAt(k) + "' specified without value"); + } + if (this.valueFlags.containsKey(args[i].charAt(k))) { + throw new CommandException("Value flag '" + args[i].charAt(k) + "' already given"); + } + this.valueFlags.put(args[i].charAt(k), args[index]); + args = removePortionOfArray(args, index, index, null); + } else { + booleanFlags.add(args[i].charAt(k)); + } } args = removePortionOfArray(args, i, i, null); + } else if (args[i].matches("^--$")) { + args = removePortionOfArray(args, i, i, null); + break; } } this.args = args; } - public CommandContext(String args, Set isValueFlag) throws CommandException { - this(args.split(" "), isValueFlag); - } - - /** - * @param args An array with arguments empty strings will be ignored by most things - * @param isValueFlag A set containing all value flags. Pass null to disable flag parsing altogether. - * @throws CommandException This is thrown if a value flag was passed without a value. - */ - public CommandContext(String[] args, Set isValueFlag) throws CommandException { - if (isValueFlag == null) { - this.args = args; - return; - } - - int nextArg = 1; - - while (nextArg < args.length) { - // Fetch argument - String arg = args[nextArg++]; - - // Empty argument? (multiple consecutive spaces) - if (arg.isEmpty()) - continue; - - // No more flags? - if (arg.charAt(0) != '-' || arg.length() == 1 || !arg.matches("^-[a-zA-Z]+$")) { - --nextArg; - break; - } - - // Handle flag parsing terminator -- - if (arg.equals("--")) - break; - - // Go through the flags - for (int i = 1; i < arg.length(); ++i) { - char flagName = arg.charAt(i); - - if (isValueFlag.contains(flagName)) { - // Skip empty arguments... - while (nextArg < args.length && args[nextArg].isEmpty()) - ++nextArg; - - if (nextArg >= args.length) - throw new CommandException("No value specified for the '-"+flagName+"' flag."); - - // If it is a value flag, read another argument and add it - valueFlags.put(flagName, args[nextArg++]); - } - else { - booleanFlags.add(flagName); - } - } - } - - this.args = Arrays.copyOfRange(args, nextArg-1, args.length); - this.args[0] = args[0]; - } - public String getCommand() { return args[0]; } @@ -233,13 +206,4 @@ public class CommandContext { public int argsLength() { return args.length - 1; } - - public static String[] removePortionOfArray(String[] array, int from, int to, String replace) { - String[] newArray = new String[from + array.length - to - (replace == null ? 1 : 0)]; - System.arraycopy(array, 0, newArray, 0, from); - if (replace != null) newArray[from] = replace; - System.arraycopy(array, to + (replace == null ? 0 : 1), newArray, from + (replace == null ? 0 : 1), - array.length - to - 1); - return newArray; - } } diff --git a/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java b/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java index 0f37fd427..f384b64ea 100644 --- a/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java +++ b/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java @@ -27,6 +27,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.sk89q.util.StringUtil; +import static com.sk89q.util.ArrayUtil.removePortionOfArray; /** *

Manager for handling commands. This allows you to easily process commands, @@ -228,8 +229,17 @@ public abstract class CommandsManager { for (int i = 0; i <= level; ++i) { command.append(args[i] + " "); } - - command.append(cmd.flags().length() > 0 ? "[-" + cmd.flags() + "] " : ""); + if (cmd.flags().length() > 0) { + char[] flags = cmd.flags().toCharArray(); + for (int i = 0; i < flags.length; ++i) { + if (flags.length > i + 1) { + if (flags[i + 1] == ':') { + flags = removePortionOfArray(flags, i, i + 1, null); + } + } + } + if (flags.length > 0) command.append("[-" + String.valueOf(flags) + "] "); + } command.append(cmd.usage()); return command.toString(); @@ -378,14 +388,19 @@ public abstract class CommandsManager { String[] newArgs = new String[args.length - level]; System.arraycopy(args, level, newArgs, 0, args.length - level); - final String valueFlags = cmd.valueFlags(); - final Set isValueFlag = new HashSet(); + final Set valueFlags = new HashSet(); - for (int i = 0; i < valueFlags.length(); ++i) { - isValueFlag.add(valueFlags.charAt(i)); + char[] flags = cmd.flags().toCharArray(); + for (int i = 0; i < flags.length; ++i) { + if (flags.length > i + 1) { + if (flags[i + 1] == ':') { + valueFlags.add(flags[i]); + flags = removePortionOfArray(flags, i + 1, i + 1, null); + } + } } - CommandContext context = new CommandContext(newArgs, isValueFlag); + CommandContext context = new CommandContext(newArgs, valueFlags); if (context.argsLength() < cmd.min()) throw new CommandUsageException("Too few arguments.", getUsage(args, level, cmd)); @@ -393,8 +408,9 @@ public abstract class CommandsManager { if (cmd.max() != -1 && context.argsLength() > cmd.max()) throw new CommandUsageException("Too many arguments.", getUsage(args, level, cmd)); + String flagStr = String.valueOf(flags); for (char flag : context.getFlags()) { - if (cmd.flags().indexOf(String.valueOf(flag)) == -1) + if (flagStr.indexOf(flag) == -1) throw new CommandUsageException("Unknown flag: " + flag, getUsage(args, level, cmd)); } diff --git a/src/main/java/com/sk89q/util/ArrayUtil.java b/src/main/java/com/sk89q/util/ArrayUtil.java new file mode 100644 index 000000000..8e80cbeea --- /dev/null +++ b/src/main/java/com/sk89q/util/ArrayUtil.java @@ -0,0 +1,22 @@ +package com.sk89q.util; + +public class ArrayUtil { + + public static String[] removePortionOfArray(String[] array, int from, int to, String replace) { + String[] newArray = new String[from + array.length - to - (replace == null ? 1 : 0)]; + System.arraycopy(array, 0, newArray, 0, from); + if (replace != null) newArray[from] = replace; + System.arraycopy(array, to + 1, newArray, from + (replace == null ? 0 : 1), + array.length - to - 1); + return newArray; + } + + public static char[] removePortionOfArray(char[] array, int from, int to, Character replace) { + char[] newArray = new char[from + array.length - to - (replace == null ? 1 : 0)]; + System.arraycopy(array, 0, newArray, 0, from); + if (replace != null) newArray[from] = replace; + System.arraycopy(array, to + 1, newArray, from + (replace == null ? 0 : 1), + array.length - to - 1); + return newArray; + } +}