admin.scala: Start on understanding the administration protocol.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 17 May 2018 09:45:49 +0000 (10:45 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 17 May 2018 09:48:34 +0000 (10:48 +0100)
Makefile
admin.scala [new file with mode: 0644]

index 873380a..cd8e4a4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -53,6 +53,8 @@ TARGETS                       += jni.stamp
 TARGETS                        += sock.stamp
 sock.stamp: jni.stamp
 
+TARGETS                        += admin.stamp
+
 TARGETS                        += main.stamp
 main.stamp: jni.stamp sock.stamp
 
diff --git a/admin.scala b/admin.scala
new file mode 100644 (file)
index 0000000..85978fe
--- /dev/null
@@ -0,0 +1,72 @@
+package uk.org.distorted.tripe;
+
+import scala.collection.mutable.ArrayBuffer;
+
+object Admin {
+  val RX_ORDINARY = "^[^\\\\'\"\\s]+$".r;
+  val RX_WEIRD = "[\\\\'\"]".r;
+
+  def quote(v: Seq[String]) = {
+    val b = new StringBuilder;
+    var sep = false;
+    for (s <- v) {
+      if (!sep) sep = true;
+      else b.append(' ');
+      s match {
+       case RX_ORDINARY() => b.append(s);
+       case _ =>
+         b.append('"');
+         b.append(RX_WEIRD.replaceAllIn(s, "\\\\$0"));
+         b.append('"');
+      }
+    }
+    b.mkString
+  }
+
+  class InvalidQuotingException(msg: String) extends Exception(msg);
+
+  def split(s: String): Array[String] = {
+    val ab = new ArrayBuffer[String]();
+    val sb = new StringBuilder;
+
+    object State extends Enumeration {
+      val BETWEEN, WORD, SQUOTE, DQUOTE = Value;
+    }
+    import State.{Value => _, _};
+
+    val n = s.length;
+
+    def scan(pos: Int, st: State.Value, bs: Boolean)
+    {
+      if (pos >= n) {
+       if (bs)
+         throw new InvalidQuotingException("trailing `\\'");
+       else if (st == SQUOTE || st == DQUOTE)
+         throw new InvalidQuotingException("unmatched quote");
+       if (st != BETWEEN) ab += sb.mkString;
+      } else (st, bs, s(pos)) match {
+       case (BETWEEN, false, '\\') => scan(pos + 1, WORD, true);
+       case (_, false, '\\') => scan(pos + 1, st, true);
+       case (SQUOTE, false, ''') | (DQUOTE, false, '"') =>
+         scan(pos + 1, WORD, false);
+       case (BETWEEN | WORD, false, ''') => scan(pos + 1, SQUOTE, false);
+       case (BETWEEN | WORD, false, '"') => scan(pos + 1, DQUOTE, false);
+       case (BETWEEN, false, ch) if ch.isWhitespace =>
+         scan(pos + 1, st, false);
+       case (WORD, false, ch) if ch.isWhitespace =>
+         ab += sb.mkString; sb.clear();
+         scan(pos + 1, BETWEEN, false);
+       case (BETWEEN, _, ch) => sb.append(ch); scan(pos + 1, WORD, false);
+       case (_, _, ch) => sb.append(ch); scan(pos + 1, st, false);
+      }
+    }
+    scan(0, BETWEEN, false);
+    ab.toArray
+  }
+
+  def main(args: Array[String])
+  {
+    if (args.length != 1) println(quote(args));
+    else for (s <- split(args(0))) println(s);
+  }
+}