chiark / gitweb /
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 }