diff options
| author | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-08 22:39:59 -0300 |
|---|---|---|
| committer | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2017-10-08 22:39:59 -0300 |
| commit | c82e3b3b2de0633317ec8fc85925e91422820597 (patch) | |
| tree | 96567416ce23c5ce85601f9cedc3a94bb1c55cba /base/src/main/java/bjc/utils/cli/objects | |
| parent | b3ac1c8690c3e14c879913e5dcc03a5f5e14876e (diff) | |
Start splitting into maven modules
Diffstat (limited to 'base/src/main/java/bjc/utils/cli/objects')
3 files changed, 612 insertions, 0 deletions
diff --git a/base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java b/base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java new file mode 100644 index 0000000..ec66fe2 --- /dev/null +++ b/base/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java @@ -0,0 +1,392 @@ +package bjc.utils.cli.objects; + +import java.io.InputStreamReader; +import java.io.Reader; + +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; +import java.util.function.Predicate; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import bjc.utils.ioutils.Prompter; +import bjc.utils.ioutils.blocks.*; + +import static bjc.utils.cli.objects.Command.CommandStatus; +import static bjc.utils.cli.objects.Command.CommandStatus.*; + +public class BlockReaderCLI { + private final Logger LOGGER = Logger.getLogger(BlockReaderCLI.class.getName()); + + public static class BlockReaderState { + public final Map<String, BlockReader> readers; + public final Map<String, Reader> sources; + + public BlockReaderState(Map<String, BlockReader> readers, Map<String, Reader> sources) { + this.readers = readers; + this.sources = sources; + } + } + + private BlockReaderState stat; + + /** + * Create a new CLI for configuring BlockReaders. + * + * @param srcs + * The container of initial I/O sources. + */ + public BlockReaderCLI(Map<String, Reader> srcs) { + stat = new BlockReaderState(new HashMap<>(), srcs); + } + + public static void main(String[] args) { + /* + * Create/configure I/O sources. + */ + Map<String, Reader> sources = new HashMap<>(); + sources.put("stdio", new InputStreamReader(System.in)); + + BlockReaderCLI reader = new BlockReaderCLI(sources); + + reader.run(new Scanner(System.in), "console", true); + } + + /** + * Run the CLI on an input source. + * + * @param input + * The place to read input from. + * @param ioSource + * The name of the place to read input from. + * @param interactive + * Whether or not the source is interactive + */ + public void run(Scanner input, String ioSource, boolean interactive) { + int lno = 0; + while(input.hasNextLine()) { + if(interactive) + System.out.printf("reader-conf(%d)>", lno); + + String ln = input.nextLine(); + + lno += 1; + + Command com = Command.fromString(ln, lno, ioSource); + if(com == null) continue; + + CommandStatus stat = handleCommand(com, interactive); + if(stat == FINISH || stat == ERROR) { + return; + } + } + + input.close(); + } + + /* + * Handle a command. + */ + public CommandStatus handleCommand(Command com, boolean interactive) { + switch(com.nameCommand) { + case "def-filtered": + return defFiltered(com); + case "def-layered": + return defLayered(com); + case "def-pushback": + return defPushback(com); + case "def-simple": + return defSimple(com); + case "def-serial": + return defSerial(com); + case "def-toggled": + return defToggled(com); + case "}": + case "end": + case "exit": + case "quit": + if(interactive) + System.out.printf("Exiting reader-conf, %d readers configured in %d commands\n", + stat.readers.size(), com.lineNo); + return FINISH; + default: + LOGGER.severe(com.error("Unknown command '%s'\n", com.nameCommand)); + return FAIL; + } + } + + private CommandStatus defFiltered(Command com) { + String remn = com.remnCommand; + + /* + * Get the block name. + */ + int idx = remn.indexOf(' '); + if(idx == -1) { + LOGGER.severe(com.error("No name argument for def-filtered.\n")); + return FAIL; + } + String blockName = remn.substring(0, idx).trim(); + remn = remn.substring(idx).trim(); + + /* + * Check there isn't a reader already bound to this name. + */ + if(stat.readers.containsKey(blockName)) { + LOGGER.warning(com.warn("Shadowing existing reader named %s\n", blockName)); + } + + /* + * Get the reader name. + */ + idx = remn.indexOf(' '); + if(idx == -1) { + LOGGER.severe(com.error("No reader-name argument for def-filtered.\n")); + return FAIL; + } + String readerName = remn.substring(0, idx).trim(); + remn = remn.substring(idx).trim(); + + /* + * Check there is a reader bound to that name. + */ + if(!stat.readers.containsKey(readerName)) { + LOGGER.severe(com.error("No source named %s\n", readerName)); + return FAIL; + } + + /* + * Get the pattern. + */ + if(remn.equals("")) { + LOGGER.severe(com.error("No filter argument for def-filtered\n")); + return FAIL; + } + + String filter = remn; + + try { + Pattern pat = Pattern.compile(filter); + + Predicate<Block> pred = (block) -> { + Matcher mat = pat.matcher(block.contents); + + return mat.matches(); + }; + + BlockReader reader = new FilteredBlockReader(stat.readers.get(readerName), pred); + + stat.readers.put(blockName, reader); + } catch (PatternSyntaxException psex) { + LOGGER.severe(com.error("Invalid regular expression '%s' for filter. (%s)\n", filter, psex.getMessage())); + return FAIL; + } + + return SUCCESS; + } + + private CommandStatus defPushback(Command com) { + String[] parts = com.remnCommand.split(" "); + + if(parts.length != 2) { + LOGGER.severe(com.error("Incorrect number of arguments to def-pushback. Requires a block name and a reader name\n")); + return FAIL; + } + + String blockName = parts[0]; + if(stat.readers.containsKey(blockName)) { + LOGGER.warning(com.warn("Shadowing existing reader %s\n", blockName)); + return FAIL; + } + + String readerName = parts[1]; + if(!stat.readers.containsKey(readerName)) { + LOGGER.severe(com.error("No reader named %s\n", readerName)); + return FAIL; + } + + BlockReader reader = new PushbackBlockReader(stat.readers.get(readerName)); + stat.readers.put(blockName, reader); + + return SUCCESS; + } + + private CommandStatus defToggled(Command com) { + String[] parts = com.remnCommand.split(" "); + + if(parts.length != 3) { + LOGGER.severe(com.error("Incorrect number of arguments to def-toggled. Requires a block name and two reader names\n")); + return FAIL; + } + + /* + * Get the block name. + */ + String blockName = parts[0]; + if(stat.readers.containsKey(blockName)) { + LOGGER.warning(com.warn("Shadowing existing reader named %s\n", blockName)); + } + + /* + * Make sure the component readers exist. + */ + if(!stat.readers.containsKey(parts[1])) { + LOGGER.severe(com.error("No reader named %s\n", parts[1])); + return FAIL; + } + + if(!stat.readers.containsKey(parts[2])) { + LOGGER.severe(com.error("No reader named %s\n", parts[2])); + return FAIL; + } + + BlockReader reader = new ToggledBlockReader(stat.readers.get(parts[1]), stat.readers.get(parts[2])); + stat.readers.put(blockName, reader); + + return SUCCESS; + } + + private CommandStatus defLayered(Command com) { + String[] parts = com.remnCommand.split(" "); + + if(parts.length != 3) { + LOGGER.severe(com.error("Incorrect number of arguments to def-layered. Requires a block name and two reader names\n")); + return FAIL; + } + + /* + * Get the block name. + */ + String blockName = parts[0]; + if(stat.readers.containsKey(blockName)) { + LOGGER.warning(com.warn("Shadowing existing reader named %s\n", blockName)); + } + + /* + * Make sure the component readers exist. + */ + if(!stat.readers.containsKey(parts[1])) { + LOGGER.severe(com.error("No reader named %s\n", parts[1])); + return FAIL; + } + + if(!stat.readers.containsKey(parts[2])) { + LOGGER.severe(com.error("No reader named %s\n", parts[2])); + return FAIL; + } + + BlockReader reader = new LayeredBlockReader(stat.readers.get(parts[1]), stat.readers.get(parts[2])); + stat.readers.put(blockName, reader); + + return SUCCESS; + } + + private CommandStatus defSerial(Command com) { + String[] parts = com.remnCommand.split(" "); + + if(parts.length < 2) { + LOGGER.severe(com.error("Not enough arguments to def-serial. Requires at least a block name and at least one reader name\n")); + return FAIL; + } + + /* + * Get the name for this BlockReader. + */ + String blockName = parts[0]; + /* + * Check there isn't a reader already bound to this name. + */ + if(stat.readers.containsKey(blockName)) { + LOGGER.warning(com.warn("Shadowing existing reader named %s\n", blockName)); + } + + /* + * Get all of the component readers. + */ + BlockReader[] readerArr = new BlockReader[parts.length - 1]; + for(int i = 1; i < parts.length; i++) { + String readerName = parts[i]; + + /* + * Check there is a reader bound to that name. + */ + if(!stat.readers.containsKey(readerName)) { + LOGGER.severe(com.error("No reader named %s\n", readerName)); + return FAIL; + } + + readerArr[i] = stat.readers.get(readerName); + } + + BlockReader reader = new SerialBlockReader(readerArr); + + stat.readers.put(blockName, reader); + + return SUCCESS; + } + + private CommandStatus defSimple(Command com) { + String remn = com.remnCommand; + + /* + * Get the block name. + */ + int idx = remn.indexOf(' '); + if(idx == -1) { + LOGGER.severe(com.error("No name argument for def-simple.\n")); + return FAIL; + } + String blockName = remn.substring(0, idx).trim(); + remn = remn.substring(idx).trim(); + + /* + * Check there isn't a reader already bound to this name. + */ + if(stat.readers.containsKey(blockName)) { + LOGGER.warning(com.warn("Shadowing existing reader named %s\n", blockName)); + } + + /* + * Get the source name. + */ + idx = remn.indexOf(' '); + if(idx == -1) { + LOGGER.severe(com.error("No source-name argument for def-simple.\n")); + return FAIL; + } + String sourceName = remn.substring(0, idx).trim(); + remn = remn.substring(idx).trim(); + + /* + * Check there is a source bound to that name. + */ + if(!stat.sources.containsKey(sourceName)) { + LOGGER.severe(com.error("No source named %s\n", sourceName)); + return FAIL; + } + + /* + * Get the pattern. + */ + if(remn.equals("")) { + LOGGER.severe(com.error("No delimiter argument for def-simple\n")); + return FAIL; + } + + String delim = remn; + + try { + BlockReader reader = new SimpleBlockReader(delim, stat.sources.get(sourceName)); + + stat.readers.put(blockName, reader); + } catch (PatternSyntaxException psex) { + LOGGER.severe(com.error("Invalid regular expression '%s' for delimiter. (%s)\n", delim, psex.getMessage())); + return FAIL; + } + + return SUCCESS; + } +} diff --git a/base/src/main/java/bjc/utils/cli/objects/Command.java b/base/src/main/java/bjc/utils/cli/objects/Command.java new file mode 100644 index 0000000..e605a2b --- /dev/null +++ b/base/src/main/java/bjc/utils/cli/objects/Command.java @@ -0,0 +1,87 @@ +package bjc.utils.cli.objects; + +public class Command { + /** + * Command status values. + */ + public static enum CommandStatus { + /** + * The command succeded. + */ + SUCCESS, + /** + * The command failed non-fatally. + */ + FAIL, + /** + * The command failed fatally. + */ + ERROR, + /** + * The command was the last one. + */ + FINISH, + } + + public final int lineNo; + + public final String fullCommand; + public final String remnCommand; + public final String nameCommand; + + public final String ioSource; + + /** + * Create a new command. + * + * @param ln + * The line to get the command from. + * @param lno + * The number of the line the command came from. + * @param ioSrc + * The name of where the I/O came from. + */ + public Command(String ln, int lno, String ioSrc) { + int idx = ln.indexOf(' '); + + if(idx == -1) idx = ln.length(); + + fullCommand = ln; + nameCommand = ln.substring(0, idx).trim(); + remnCommand = ln.substring(idx).trim(); + + lineNo = lno; + + ioSource = ioSrc; + } + + public static Command fromString(String ln, int lno, String ioSource) { + /* + * Ignore blank lines and comments. + */ + if(ln.equals("")) return null; + if(ln.startsWith("#")) return null; + + /* + * Trim off comments part-way through the line. + */ + int idxHash = ln.indexOf('#'); + if(idxHash != -1) { + ln = ln.substring(0, idxHash).trim(); + } + + return new Command(ln, lno, ioSource); + } + + public String warn(String warning, Object... parms) { + String msg = String.format(warning, parms); + + return String.format("WARNING (%s:%d): %s", ioSource, lineNo, msg); + } + + public String error(String err, Object... parms) { + String msg = String.format(err, parms); + + return String.format("ERROR (%s:%d): %s", ioSource, lineNo, msg); + } +} diff --git a/base/src/main/java/bjc/utils/cli/objects/DefineCLI.java b/base/src/main/java/bjc/utils/cli/objects/DefineCLI.java new file mode 100644 index 0000000..bb2733f --- /dev/null +++ b/base/src/main/java/bjc/utils/cli/objects/DefineCLI.java @@ -0,0 +1,133 @@ +package bjc.utils.cli.objects; + +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; +import java.util.function.UnaryOperator; +import java.util.logging.Logger; +import java.util.regex.Pattern; + +import static bjc.utils.cli.objects.Command.CommandStatus; +import static bjc.utils.cli.objects.Command.CommandStatus.*; + +public class DefineCLI { + private final Logger LOGGER = Logger.getLogger(DefineCLI.class.getName()); + + public static class DefineState { + public final Map<String, UnaryOperator<String>> defines; + + public final Map<String, String> strings; + public final Map<String, String> formats; + + public final Map<String, Pattern> patterns; + + public DefineState() { + this(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>()); + } + + public DefineState(Map<String, UnaryOperator<String>> defines, + Map<String, String> strings, Map<String, String> formats, + Map<String, Pattern> patterns) { + this.defines = defines; + + this.strings = strings; + this.formats = formats; + + this.patterns = patterns; + } + } + + private DefineState stat; + + public DefineCLI() { + stat = new DefineState(); + } + + public static void main(String[] args) { + DefineCLI defin = new DefineCLI(); + } + + /** + * Run the CLI on an input source. + * + * @param input + * The place to read input from. + * @param ioSource + * The name of the place to read input from. + * @param interactive + * Whether or not the source is interactive + */ + public void run(Scanner input, String ioSource, boolean interactive) { + int lno = 0; + while(input.hasNextLine()) { + if(interactive) + System.out.printf("define-conf(%d)>", lno); + + String ln = input.nextLine(); + + lno += 1; + + Command com = Command.fromString(ln, lno, ioSource); + if(com == null) continue; + + handleCommand(com, interactive); + } + + input.close(); + } + + public void handleCommand(Command com, boolean interactive) { + switch(com.nameCommand) { + case "def-string": + default: + LOGGER.severe(com.error("Unknown command %s\n", com.nameCommand)); + break; + } + } + + private CommandStatus defString(Command com) { + String remn = com.remnCommand; + + int idx = remn.indexOf(' '); + if(idx == -1) { + LOGGER.warning(com.warn("Binding empty string to name '%s'\n", remn)); + idx = remn.length(); + } + String name = remn.substring(0, idx); + String strang = remn.substring(idx); + + if(stat.strings.containsKey(name)) { + LOGGER.warning(com.warn("Shadowing string '%s'\n", name)); + } + + stat.strings.put(name, strang); + + return SUCCESS; + } + + private CommandStatus defFormat(Command com) { + String remn = com.remnCommand; + + int idx = remn.indexOf(' '); + if(idx == -1) { + LOGGER.warning(com.warn("Binding empty format to name '%s'\n", remn)); + idx = remn.length(); + } + String name = remn.substring(0, idx); + String fmt = remn.substring(idx); + + if(stat.formats.containsKey(name)) { + LOGGER.warning(com.warn("Shadowing format '%s'\n", name)); + } + + stat.formats.put(name, fmt); + + return SUCCESS; + } + + private CommandStatus bindFormat(Command com) { + String[] parts = com.remnCommand.split(" "); + + return SUCCESS; + } +} |
