--- /dev/null
+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);
+ }
+}