summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils
diff options
context:
space:
mode:
Diffstat (limited to 'BJC-Utils2/src/main/java/bjc/utils')
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java89
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/cli/objects/Command.java22
-rw-r--r--BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDescaper.java242
3 files changed, 319 insertions, 34 deletions
diff --git a/BJC-Utils2/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java b/BJC-Utils2/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java
index ae5cff8..ec66fe2 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/objects/BlockReaderCLI.java
@@ -15,6 +15,9 @@ 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());
@@ -75,7 +78,10 @@ public class BlockReaderCLI {
Command com = Command.fromString(ln, lno, ioSource);
if(com == null) continue;
- handleCommand(com, interactive);
+ CommandStatus stat = handleCommand(com, interactive);
+ if(stat == FINISH || stat == ERROR) {
+ return;
+ }
}
input.close();
@@ -84,26 +90,20 @@ public class BlockReaderCLI {
/*
* Handle a command.
*/
- public void handleCommand(Command com, boolean interactive) {
+ public CommandStatus handleCommand(Command com, boolean interactive) {
switch(com.nameCommand) {
case "def-filtered":
- defFiltered(com);
- break;
+ return defFiltered(com);
case "def-layered":
- defLayered(com);
- break;
+ return defLayered(com);
case "def-pushback":
- defPushback(com);
- break;
+ return defPushback(com);
case "def-simple":
- defSimple(com);
- break;
+ return defSimple(com);
case "def-serial":
- defSerial(com);
- break;
+ return defSerial(com);
case "def-toggled":
- defToggled(com);
- break;
+ return defToggled(com);
case "}":
case "end":
case "exit":
@@ -111,14 +111,14 @@ public class BlockReaderCLI {
if(interactive)
System.out.printf("Exiting reader-conf, %d readers configured in %d commands\n",
stat.readers.size(), com.lineNo);
- break;
+ return FINISH;
default:
LOGGER.severe(com.error("Unknown command '%s'\n", com.nameCommand));
- break;
+ return FAIL;
}
}
- private void defFiltered(Command com) {
+ private CommandStatus defFiltered(Command com) {
String remn = com.remnCommand;
/*
@@ -127,6 +127,7 @@ public class BlockReaderCLI {
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();
@@ -144,6 +145,7 @@ public class BlockReaderCLI {
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();
@@ -153,7 +155,7 @@ public class BlockReaderCLI {
*/
if(!stat.readers.containsKey(readerName)) {
LOGGER.severe(com.error("No source named %s\n", readerName));
- return;
+ return FAIL;
}
/*
@@ -161,6 +163,7 @@ public class BlockReaderCLI {
*/
if(remn.equals("")) {
LOGGER.severe(com.error("No filter argument for def-filtered\n"));
+ return FAIL;
}
String filter = remn;
@@ -179,38 +182,44 @@ public class BlockReaderCLI {
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 void defPushback(Command com) {
+ 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;
+ 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;
+ return FAIL;
}
BlockReader reader = new PushbackBlockReader(stat.readers.get(readerName));
stat.readers.put(blockName, reader);
+
+ return SUCCESS;
}
- private void defToggled(Command com) {
+ 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;
+ return FAIL;
}
/*
@@ -226,24 +235,26 @@ public class BlockReaderCLI {
*/
if(!stat.readers.containsKey(parts[1])) {
LOGGER.severe(com.error("No reader named %s\n", parts[1]));
- return;
+ return FAIL;
}
if(!stat.readers.containsKey(parts[2])) {
LOGGER.severe(com.error("No reader named %s\n", parts[2]));
- return;
+ return FAIL;
}
BlockReader reader = new ToggledBlockReader(stat.readers.get(parts[1]), stat.readers.get(parts[2]));
stat.readers.put(blockName, reader);
+
+ return SUCCESS;
}
- private void defLayered(Command com) {
+ 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;
+ return FAIL;
}
/*
@@ -259,24 +270,26 @@ public class BlockReaderCLI {
*/
if(!stat.readers.containsKey(parts[1])) {
LOGGER.severe(com.error("No reader named %s\n", parts[1]));
- return;
+ return FAIL;
}
if(!stat.readers.containsKey(parts[2])) {
LOGGER.severe(com.error("No reader named %s\n", parts[2]));
- return;
+ return FAIL;
}
BlockReader reader = new LayeredBlockReader(stat.readers.get(parts[1]), stat.readers.get(parts[2]));
stat.readers.put(blockName, reader);
+
+ return SUCCESS;
}
- private void defSerial(Command com) {
+ 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;
+ return FAIL;
}
/*
@@ -302,7 +315,7 @@ public class BlockReaderCLI {
*/
if(!stat.readers.containsKey(readerName)) {
LOGGER.severe(com.error("No reader named %s\n", readerName));
- return;
+ return FAIL;
}
readerArr[i] = stat.readers.get(readerName);
@@ -311,9 +324,11 @@ public class BlockReaderCLI {
BlockReader reader = new SerialBlockReader(readerArr);
stat.readers.put(blockName, reader);
+
+ return SUCCESS;
}
- private void defSimple(Command com) {
+ private CommandStatus defSimple(Command com) {
String remn = com.remnCommand;
/*
@@ -322,6 +337,7 @@ public class BlockReaderCLI {
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();
@@ -339,6 +355,7 @@ public class BlockReaderCLI {
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();
@@ -348,7 +365,7 @@ public class BlockReaderCLI {
*/
if(!stat.sources.containsKey(sourceName)) {
LOGGER.severe(com.error("No source named %s\n", sourceName));
- return;
+ return FAIL;
}
/*
@@ -356,6 +373,7 @@ public class BlockReaderCLI {
*/
if(remn.equals("")) {
LOGGER.severe(com.error("No delimiter argument for def-simple\n"));
+ return FAIL;
}
String delim = remn;
@@ -366,6 +384,9 @@ public class BlockReaderCLI {
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/BJC-Utils2/src/main/java/bjc/utils/cli/objects/Command.java b/BJC-Utils2/src/main/java/bjc/utils/cli/objects/Command.java
index a0d4493..e605a2b 100644
--- a/BJC-Utils2/src/main/java/bjc/utils/cli/objects/Command.java
+++ b/BJC-Utils2/src/main/java/bjc/utils/cli/objects/Command.java
@@ -1,6 +1,28 @@
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;
diff --git a/BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDescaper.java b/BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDescaper.java
new file mode 100644
index 0000000..096656a
--- /dev/null
+++ b/BJC-Utils2/src/main/java/bjc/utils/parserutils/StringDescaper.java
@@ -0,0 +1,242 @@
+package bjc.utils.parserutils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.UnaryOperator;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import static java.util.Map.Entry;
+
+import static bjc.utils.PropertyDB.applyFormat;
+import static bjc.utils.PropertyDB.getCompiledRegex;
+import static bjc.utils.PropertyDB.getRegex;
+
+public class StringDescaper {
+ private Logger LOGGER = Logger.getLogger(StringDescaper.class.getName());
+
+ /*
+ * Patterns and pattern parts.
+ */
+ private static String rPossibleEscapeString = getRegex("possibleStringEscape");
+ private static Pattern possibleEscapePatt = Pattern.compile(rPossibleEscapeString);
+
+ private static String rShortEscape = getRegex("shortFormStringEscape");
+ private static String rOctalEscape = getRegex("octalStringEscape");
+ private static String rUnicodeEscape = getRegex("unicodeStringEscape");
+
+ private String rEscapeString;
+ private Pattern escapePatt;
+
+ private static String rDoubleQuoteString = applyFormat("doubleQuotes", getRegex("nonStringEscape"), rPossibleEscapeString);
+ private static Pattern doubleQuotePatt = Pattern.compile(rDoubleQuoteString);
+
+ private static Pattern quotePatt = getCompiledRegex("unescapedQuote");
+
+ private Map<String, String> literalEscapes;
+ private Map<Pattern, UnaryOperator<String>> specialEscapes;
+
+ public StringDescaper() {
+ literalEscapes = new HashMap<>();
+ specialEscapes = new HashMap<>();
+
+ rEscapeString = String.format("\\\\(%1$s|%2$s|%3$s)");
+ escapePatt = Pattern.compile(rEscapeString);
+ }
+
+ public void addLiteralEscape(String escape, String val) {
+ if(literalEscapes.containsKey(escape)) {
+ LOGGER.warning(String.format("Shadowing literal escape '%s'\n", escape));
+ }
+
+ literalEscapes.put(escape, val);
+ }
+
+ public void addSpecialEscape(String escape, UnaryOperator<String> val) {
+ if(specialEscapes.containsKey(escape)) {
+ LOGGER.warning(String.format("Shadowing special escape '%s'\n", escape));
+ }
+
+ /*
+ * Make sure this special escape is a valid regex.
+ */
+
+ Pattern patt = null;
+ try {
+ patt = Pattern.compile(escape);
+ } catch (PatternSyntaxException psex) {
+ String msg = String.format("Invalid special escape '%s'", escape);
+
+ IllegalArgumentException iaex = new IllegalArgumentException(msg);
+ iaex.initCause(psex);
+
+ throw psex;
+ }
+
+ specialEscapes.put(patt, val);
+ }
+
+ public void compileEscapes() {
+ StringBuilder work = new StringBuilder();
+
+ for(String litEscape : literalEscapes.keySet()) {
+ work.append("|(?:");
+ work.append(Pattern.quote(litEscape));
+ work.append(")");
+ }
+
+ for(Pattern specEscape : specialEscapes.keySet()) {
+ work.append("|(?:");
+ work.append(specEscape.toString());
+ work.append(")");
+ }
+
+ /*
+ * Convert user-defined escapes to a regex for matching.
+ * We don't need a bar before %4 because the string has it.
+ */
+ rEscapeString = String.format("\\(%1$s|%2$s|%3$s%4$s)", rShortEscape, rOctalEscape, rUnicodeEscape, work.toString());
+ escapePatt = Pattern.compile(rEscapeString);
+ }
+
+ /**
+ * Replace escape characters with their actual equivalents.
+ *
+ * @param inp
+ * The string to replace escape sequences in.
+ *
+ * @return The string with escape sequences replaced by their equivalent
+ * characters.
+ */
+ public String descapeString(final String inp) {
+ if (inp == null) {
+ throw new NullPointerException("Input to descapeString must not be null");
+ }
+
+ /*
+ * Prepare the buffer and escape finder.
+ */
+ final StringBuffer work = new StringBuffer();
+ final Matcher possibleEscapeFinder = possibleEscapePatt.matcher(inp);
+ final Matcher escapeFinder = escapePatt.matcher(inp);
+
+ while (possibleEscapeFinder.find()) {
+ if (!escapeFinder.find()) {
+ /*
+ * Found a possible escape that isn't actually an
+ * escape.
+ */
+ final String msg = String.format("Illegal escape sequence '%s' at position %d of string '%s'",
+ possibleEscapeFinder.group(), possibleEscapeFinder.start(), inp);
+ throw new IllegalArgumentException(msg);
+ }
+
+ final String escapeSeq = escapeFinder.group();
+
+ /*
+ * Convert the escape to a string.
+ */
+ String escapeRep = "";
+ switch (escapeSeq) {
+ case "\\b":
+ escapeRep = "\b";
+ break;
+ case "\\t":
+ escapeRep = "\t";
+ break;
+ case "\\n":
+ escapeRep = "\n";
+ break;
+ case "\\f":
+ escapeRep = "\f";
+ break;
+ case "\\r":
+ escapeRep = "\r";
+ break;
+ case "\\\"":
+ escapeRep = "\"";
+ break;
+ case "\\'":
+ escapeRep = "'";
+ break;
+ case "\\\\":
+ /*
+ * Skip past the second slash.
+ */
+ possibleEscapeFinder.find();
+ escapeRep = "\\";
+ break;
+ default:
+ if (escapeSeq.startsWith("u")) {
+ escapeRep = handleUnicodeEscape(escapeSeq.substring(1));
+ } else if(escapeSeq.startsWith("O")) {
+ escapeRep = handleOctalEscape(escapeSeq.substring(1));
+ } else if(literalEscapes.containsKey(escapeSeq)) {
+ escapeRep = literalEscapes.get(escapeSeq);
+ } else {
+ for(Entry<Pattern, UnaryOperator<String>> ent : specialEscapes.entrySet()) {
+ Pattern pat = ent.getKey();
+
+ Matcher mat = pat.matcher(escapeSeq);
+ if(mat.matches()) {
+ escapeRep = ent.getValue().apply(escapeSeq);
+ break;
+ }
+ }
+ }
+ }
+
+ escapeFinder.appendReplacement(work, escapeRep);
+ }
+
+ escapeFinder.appendTail(work);
+
+ return work.toString();
+ }
+
+ /*
+ * Handle a unicode codepoint.
+ */
+ private static String handleUnicodeEscape(final String seq) {
+ try {
+ final int codepoint = Integer.parseInt(seq, 16);
+
+ return new String(Character.toChars(codepoint));
+ } catch (final IllegalArgumentException iaex) {
+ final String msg = String.format("'%s' is not a valid Unicode escape sequence'", seq);
+
+ final IllegalArgumentException reiaex = new IllegalArgumentException(msg);
+
+ reiaex.initCause(iaex);
+
+ throw reiaex;
+ }
+ }
+
+ /*
+ * Handle a octal codepoint.
+ */
+ private static String handleOctalEscape(final String seq) {
+ try {
+ final int codepoint = Integer.parseInt(seq, 8);
+
+ if (codepoint > 255) {
+ final String msg = String.format("'%d' is outside the range of octal escapes', codepoint");
+
+ throw new IllegalArgumentException(msg);
+ }
+
+ return new String(Character.toChars(codepoint));
+ } catch (final IllegalArgumentException iaex) {
+ final String msg = String.format("'%s' is not a valid octal escape sequence'", seq);
+
+ final IllegalArgumentException reiaex = new IllegalArgumentException(msg);
+
+ reiaex.initCause(iaex);
+
+ throw reiaex;
+ }
+ }
+}