admin.scala: Start on understanding the administration protocol.
[tripe-android] / admin.scala
1 package uk.org.distorted.tripe;
2
3 import scala.collection.mutable.ArrayBuffer;
4
5 object Admin {
6 val RX_ORDINARY = "^[^\\\\'\"\\s]+$".r;
7 val RX_WEIRD = "[\\\\'\"]".r;
8
9 def quote(v: Seq[String]) = {
10 val b = new StringBuilder;
11 var sep = false;
12 for (s <- v) {
13 if (!sep) sep = true;
14 else b.append(' ');
15 s match {
16 case RX_ORDINARY() => b.append(s);
17 case _ =>
18 b.append('"');
19 b.append(RX_WEIRD.replaceAllIn(s, "\\\\$0"));
20 b.append('"');
21 }
22 }
23 b.mkString
24 }
25
26 class InvalidQuotingException(msg: String) extends Exception(msg);
27
28 def split(s: String): Array[String] = {
29 val ab = new ArrayBuffer[String]();
30 val sb = new StringBuilder;
31
32 object State extends Enumeration {
33 val BETWEEN, WORD, SQUOTE, DQUOTE = Value;
34 }
35 import State.{Value => _, _};
36
37 val n = s.length;
38
39 def scan(pos: Int, st: State.Value, bs: Boolean)
40 {
41 if (pos >= n) {
42 if (bs)
43 throw new InvalidQuotingException("trailing `\\'");
44 else if (st == SQUOTE || st == DQUOTE)
45 throw new InvalidQuotingException("unmatched quote");
46 if (st != BETWEEN) ab += sb.mkString;
47 } else (st, bs, s(pos)) match {
48 case (BETWEEN, false, '\\') => scan(pos + 1, WORD, true);
49 case (_, false, '\\') => scan(pos + 1, st, true);
50 case (SQUOTE, false, ''') | (DQUOTE, false, '"') =>
51 scan(pos + 1, WORD, false);
52 case (BETWEEN | WORD, false, ''') => scan(pos + 1, SQUOTE, false);
53 case (BETWEEN | WORD, false, '"') => scan(pos + 1, DQUOTE, false);
54 case (BETWEEN, false, ch) if ch.isWhitespace =>
55 scan(pos + 1, st, false);
56 case (WORD, false, ch) if ch.isWhitespace =>
57 ab += sb.mkString; sb.clear();
58 scan(pos + 1, BETWEEN, false);
59 case (BETWEEN, _, ch) => sb.append(ch); scan(pos + 1, WORD, false);
60 case (_, _, ch) => sb.append(ch); scan(pos + 1, st, false);
61 }
62 }
63 scan(0, BETWEEN, false);
64 ab.toArray
65 }
66
67 def main(args: Array[String])
68 {
69 if (args.length != 1) println(quote(args));
70 else for (s <- split(args(0))) println(s);
71 }
72 }