commit 3af8336b60521908f64928dadaf98d9cbc088361
parent f22acd567ef54aad9c760414829868806b0f983f
Author: Commit-Bot <unknown>
Date:   Wed, 10 Nov 2010 19:21:50 +0000
Automatic commit from picoLisp.tgz, From: Wed, 10 Nov 2010 19:21:50 GMT
Diffstat:
5 files changed, 624 insertions(+), 177 deletions(-)
diff --git a/ersatz/PicoLisp.java b/ersatz/PicoLisp.java
@@ -1,4 +1,4 @@
-// 09nov10abu
+// 10nov10abu
 // (c) Software Lab. Alexander Burger
 
 import java.util.*;
@@ -16,7 +16,7 @@ public class PicoLisp {
    final static HashMap<String,Symbol> Intern = new HashMap<String,Symbol>();
    final static HashMap<String,Symbol> Transient = new HashMap<String,Symbol>();
    final static byte MonLen[] = new byte[] {31,31,28,31,30,31,30,31,31,30,31,30,31};
-   final static byte Version[] = new byte[] {3,0,4,4};
+   final static byte Version[] = new byte[] {3,0,4,5};
 
    final static Number Zero = new Number(0);
    final static Number One = new Number(1);
@@ -339,25 +339,35 @@ public class PicoLisp {
       mkSymbol(new Number("273"), "path", Intern);
       mkSymbol(new Number("274"), "read", Intern);
       mkSymbol(new Number("275"), "wait", Intern);
-      mkSymbol(new Number("276"), "char", Intern);
-      mkSymbol(new Number("277"), "skip", Intern);
-      mkSymbol(new Number("278"), "line", Intern);
-      mkSymbol(new Number("279"), "load", Intern);
-      mkSymbol(new Number("280"), "in", Intern);
-      mkSymbol(new Number("281"), "out", Intern);
-      mkSymbol(new Number("282"), "open", Intern);
-      mkSymbol(new Number("283"), "close", Intern);
-      mkSymbol(new Number("284"), "prin", Intern);
-      mkSymbol(new Number("285"), "prinl", Intern);
-      mkSymbol(new Number("286"), "space", Intern);
-      mkSymbol(new Number("287"), "print", Intern);
-      mkSymbol(new Number("288"), "printsp", Intern);
-      mkSymbol(new Number("289"), "println", Intern);
-      mkSymbol(new Number("290"), "flush", Intern);
-      mkSymbol(new Number("291"), "port", Intern);
-      mkSymbol(new Number("292"), "accept", Intern);
-      mkSymbol(new Number("293"), "connect", Intern);
-      MaxFun = 293;
+      mkSymbol(new Number("276"), "poll", Intern);
+      mkSymbol(new Number("277"), "peek", Intern);
+      mkSymbol(new Number("278"), "char", Intern);
+      mkSymbol(new Number("279"), "skip", Intern);
+      mkSymbol(new Number("280"), "eol", Intern);
+      mkSymbol(new Number("281"), "eof", Intern);
+      mkSymbol(new Number("282"), "from", Intern);
+      mkSymbol(new Number("283"), "till", Intern);
+      mkSymbol(new Number("284"), "line", Intern);
+      mkSymbol(new Number("285"), "any", Intern);
+      mkSymbol(new Number("286"), "sym", Intern);
+      mkSymbol(new Number("287"), "str", Intern);
+      mkSymbol(new Number("288"), "load", Intern);
+      mkSymbol(new Number("289"), "in", Intern);
+      mkSymbol(new Number("290"), "out", Intern);
+      mkSymbol(new Number("291"), "open", Intern);
+      mkSymbol(new Number("292"), "close", Intern);
+      mkSymbol(new Number("293"), "echo", Intern);
+      mkSymbol(new Number("294"), "prin", Intern);
+      mkSymbol(new Number("295"), "prinl", Intern);
+      mkSymbol(new Number("296"), "space", Intern);
+      mkSymbol(new Number("297"), "print", Intern);
+      mkSymbol(new Number("298"), "printsp", Intern);
+      mkSymbol(new Number("299"), "println", Intern);
+      mkSymbol(new Number("300"), "flush", Intern);
+      mkSymbol(new Number("301"), "port", Intern);
+      mkSymbol(new Number("302"), "accept", Intern);
+      mkSymbol(new Number("303"), "connect", Intern);
+      MaxFun = 303;
       init();
       for (boolean first = true; ; first = false) {
          try {
@@ -547,7 +557,7 @@ public class PicoLisp {
       if (s.length() > 0)
          if (s.charAt(0) == '+') {
             if (s.length() > 1 && s.charAt(1) == '@')
-               return "+" + Home + s.substring(1);
+               return '+' + Home + s.substring(1);
          }
          else if (s.charAt(0) == '@')
             return Home + s.substring(1);
@@ -860,50 +870,6 @@ public class PicoLisp {
       catch (NumberFormatException e) {return Nil;}
    }
 
-   final static Any token(Any x, char c) {
-      if (InFile.Chr == 0)
-         InFile.get();
-      if (InFile.skip(c) < 0)
-         return null;
-      if (InFile.Chr == '"') {
-         InFile.get();
-         if (InFile.Chr == '"') {
-            InFile.get();
-            return Nil;
-         }
-         if (!InFile.testEsc())
-            return Nil;
-         StringBuilder sb = new StringBuilder();
-         sb.append((char)InFile.Chr);
-         while (InFile.get() != '"' && InFile.testEsc())
-            sb.append((char)InFile.Chr);
-         InFile.get();
-         return mkStr(sb);
-      }
-      if (InFile.Chr >= '0' && InFile.Chr <= '9') {
-         StringBuilder sb = new StringBuilder();
-         sb.append((char)InFile.Chr);
-         while (InFile.get() >= '0' && InFile.Chr <= '9' || InFile.Chr == '.')
-            sb.append((char)InFile.Chr);
-         return strToAtom(sb.toString());
-      }
-      String s = x.name();
-      if (InFile.Chr >= 'A' && InFile.Chr <= 'Z' || InFile.Chr == '\\' || InFile.Chr >= 'a' && InFile.Chr <= 'z' || s.indexOf(InFile.Chr) >= 0) {
-         if (InFile.Chr == '\\')
-            InFile.get();
-         StringBuilder sb = new StringBuilder();
-         sb.append((char)InFile.Chr);
-         while (InFile.get() >= '0' && InFile.Chr <= '9' || InFile.Chr >= 'A' && InFile.Chr <= 'Z' || InFile.Chr == '\\' || InFile.Chr >= 'a' && InFile.Chr <= 'z' || s.indexOf(InFile.Chr) >= 0) {
-            if (InFile.Chr == '\\')
-               InFile.get();
-            sb.append((char)InFile.Chr);
-         }
-         s = sb.toString();
-         return s.equals("NIL")? Nil : mkSymbol(Nil, s, Intern);
-      }
-      return mkChar((char)InFile.get());
-   }
-
    final static Any fish(Any ex, Any foo, Any[] v, Any res) {
       if (foo.apply(ex, false, v, 1) != Nil)
          return new Cell(v[0], res);
@@ -995,6 +961,7 @@ public class PicoLisp {
 
    final static int xInt(Any x) {return ((Number)x).Cnt;}
    final static int evInt(Any ex) {return ((Number)ex.Car.eval()).Cnt;}
+   final static long xLong(Any x) {return ((Number)x).longValue();}
    final static long evLong(Any ex) {return ((Number)ex.Car.eval()).longValue();}
    final static String evString(Any ex) {return ex.Car.eval().name();}
 
@@ -1645,7 +1612,7 @@ public class PicoLisp {
             }
             return Chr;
          }
-         catch (IOException e) {return -1;}
+         catch (IOException e) {return Chr = -1;}
       }
 
       final boolean eol() {
@@ -1789,8 +1756,8 @@ public class PicoLisp {
                return Nil;
             eofErr();
          }
-         if (top && InFile != null && InFile.Rd instanceof LineNumberReader)
-            InFile.Src = ((LineNumberReader)InFile.Rd).getLineNumber() + 1;
+         if (top && Rd instanceof LineNumberReader)
+            Src = ((LineNumberReader)Rd).getLineNumber() + 1;
          if (Chr == '(') {
             x = rdList();
             if (top  &&  Chr == ']')
@@ -1835,7 +1802,7 @@ public class PicoLisp {
             return mkSymbol(null, sb.toString(), Transient);
          }
          if (Chr == ')' || Chr == ']' || Chr == '~')
-            err(null, null, "Bad input '" + (char)Chr + "' (" + Chr + ")");
+            err(null, null, "Bad input '" + (char)Chr + "' (" + Chr + ')');
          if (Chr == '\\')
             get();
          int i = Chr;
@@ -1853,6 +1820,52 @@ public class PicoLisp {
             get();
          return x;
       }
+
+      final Any token(Any x, char c) {
+         if (Chr == 0)
+            get();
+         if (skip(c) < 0)
+            return null;
+         if (Chr == '"') {
+            get();
+            if (Chr == '"') {
+               get();
+               return Nil;
+            }
+            if (!testEsc())
+               return Nil;
+            StringBuilder sb = new StringBuilder();
+            sb.append((char)Chr);
+            while (get() != '"' && testEsc())
+               sb.append((char)Chr);
+            get();
+            return mkStr(sb);
+         }
+         if (Chr >= '0' && Chr <= '9') {
+            StringBuilder sb = new StringBuilder();
+            sb.append((char)Chr);
+            while (get() >= '0' && Chr <= '9' || Chr == '.')
+               sb.append((char)Chr);
+            return strToAtom(sb.toString());
+         }
+         String s = x.name();
+         if (Chr >= 'A' && Chr <= 'Z' || Chr == '\\' || Chr >= 'a' && Chr <= 'z' || s.indexOf(Chr) >= 0) {
+            if (Chr == '\\')
+               get();
+            StringBuilder sb = new StringBuilder();
+            sb.append((char)Chr);
+            while (get() >= '0' && Chr <= '9' || Chr >= 'A' && Chr <= 'Z' || Chr == '\\' || Chr >= 'a' && Chr <= 'z' || s.indexOf(Chr) >= 0) {
+               if (Chr == '\\')
+                  get();
+               sb.append((char)Chr);
+            }
+            s = sb.toString();
+            return s.equals("NIL")? Nil : mkSymbol(Nil, s, Intern);
+         }
+         c = (char)Chr;
+         get();
+         return mkChar(c);
+      }
    }
 
    /* Ersatz PicoLisp Printer */
@@ -2620,42 +2633,62 @@ public class PicoLisp {
                return do274(ex);
             case 275:  // wait
                return do275(ex);
-            case 276:  // char
+            case 276:  // poll
                return do276(ex);
-            case 277:  // skip
+            case 277:  // peek
                return do277(ex);
-            case 278:  // line
+            case 278:  // char
                return do278(ex);
-            case 279:  // load
+            case 279:  // skip
                return do279(ex);
-            case 280:  // in
+            case 280:  // eol
                return do280(ex);
-            case 281:  // out
+            case 281:  // eof
                return do281(ex);
-            case 282:  // open
+            case 282:  // from
                return do282(ex);
-            case 283:  // close
+            case 283:  // till
                return do283(ex);
-            case 284:  // prin
+            case 284:  // line
                return do284(ex);
-            case 285:  // prinl
+            case 285:  // any
                return do285(ex);
-            case 286:  // space
+            case 286:  // sym
                return do286(ex);
-            case 287:  // print
+            case 287:  // str
                return do287(ex);
-            case 288:  // printsp
+            case 288:  // load
                return do288(ex);
-            case 289:  // println
+            case 289:  // in
                return do289(ex);
-            case 290:  // flush
+            case 290:  // out
                return do290(ex);
-            case 291:  // port
+            case 291:  // open
                return do291(ex);
-            case 292:  // accept
+            case 292:  // close
                return do292(ex);
-            case 293:  // connect
+            case 293:  // echo
                return do293(ex);
+            case 294:  // prin
+               return do294(ex);
+            case 295:  // prinl
+               return do295(ex);
+            case 296:  // space
+               return do296(ex);
+            case 297:  // print
+               return do297(ex);
+            case 298:  // printsp
+               return do298(ex);
+            case 299:  // println
+               return do299(ex);
+            case 300:  // flush
+               return do300(ex);
+            case 301:  // port
+               return do301(ex);
+            case 302:  // accept
+               return do302(ex);
+            case 303:  // connect
+               return do303(ex);
             default:
                return undefined(this, ex);
             }
@@ -2948,7 +2981,7 @@ public class PicoLisp {
          if (ex.Cdr.Car.eval() == Nil) {
             for (i = 0; i < 4; ++i)
                OutFile.Wr.print(Version[i] + (i == 3? "-" : "."));
-            OutFile.Wr.println("J");
+            OutFile.Wr.println('J');
             OutFile.Wr.flush();
          }
          for (x = Nil, i = 4; --i >= 0;)
@@ -5955,7 +5988,7 @@ public class PicoLisp {
             x = InFile.read('\0');
          else {
             y = x.Car.eval();
-            if ((x = token(y, (x = x.Cdr.Car.eval()) == Nil? '\0' : firstChar(x))) == null)
+            if ((x = InFile.token(y, (x = x.Cdr.Car.eval()) == Nil? '\0' : firstChar(x))) == null)
                x = Nil;
          }
          if (InFile.Name == null && InFile.Chr == '\n')
@@ -5973,7 +6006,33 @@ public class PicoLisp {
          return y;
       }
 
-      final static Any do276(Any ex) { // char
+      final static Any do276(Any ex) { // poll
+         int i;
+         Any x;
+         if ((i = xInt(x = ex.Cdr.Car.eval())) < 0 || i >= InFiles.length)
+            badFd(ex,x);
+         if (InFiles[i] == null)
+            return Nil;
+         try {
+            Selector sel = Selector.open();
+            if (InFiles[i].ready(sel))
+               return x;
+            InFiles[i].register(sel);
+            sel.selectNow();
+            if (InFiles[i].ready(sel))
+               return x;
+         }
+         catch (IOException e) {giveup(e);}
+         return Nil;
+      }
+
+      final static Any do277(Any ex) { // peek
+         if (InFile.Chr == 0)
+            InFile.get();
+         return InFile.Chr<0? Nil : mkChar((char)InFile.Chr);
+      }
+
+      final static Any do278(Any ex) { // char
          Any x;
          if (!((ex = ex.Cdr) instanceof Cell)) {
             if (InFile.Chr == 0)
@@ -5987,13 +6046,82 @@ public class PicoLisp {
          return x == T? mkChar((char)0x10000) : new Number(firstChar(x));
       }
 
-      final static Any do277(Any ex) { // skip
+      final static Any do279(Any ex) { // skip
          char c;
          c = firstChar(ex.Cdr.Car.eval());
          return InFile.skip(c) < 0? Nil : mkChar(c);
       }
 
-      final static Any do278(Any ex) { // line
+      final static Any do280(Any ex) { // eol
+         return InFile.Chr=='\n' || InFile.Chr<=0? T : Nil;
+      }
+
+      final static Any do281(Any ex) { // eof
+         if (ex.Cdr.Car.eval() != Nil) {
+            InFile.Chr = -1;
+            return T;
+         }
+         if (InFile.Chr == 0)
+            InFile.get();
+         return InFile.Chr < 0? T : Nil;
+      }
+
+      final static Any do282(Any ex) { // from
+         int i, j, k;
+         Any x;
+         Any[] v;
+         if ((k = (int)(x = ex.Cdr).length()) == 0)
+            return Nil;
+         int[] p = new int[k];
+         String[] av = new String[k];
+         for (v = new Any[k], i = 0; i < k; ++i, x = x.Cdr)
+            av[i] = (v[i] = x.Car.eval()).name();
+         if (InFile.Chr == 0)
+            InFile.get();
+         while (InFile.Chr >= 0) {
+            for (i = 0; i < k; ++i) {
+               for (;;) {
+                  if (av[i].charAt(p[i]) == (char)InFile.Chr) {
+                     if (++p[i] != av[i].length())
+                        break;
+                     InFile.get();
+                     return v[i];
+                  }
+                  if (p[i] == 0)
+                     break;
+                  for (j = 1; --p[i] != 0; ++j)
+                     if (av[i].substring(0, p[i]).equals(av[i].substring(j, j + p[i])))
+                        break;
+               }
+            }
+            InFile.get();
+         }
+         return Nil;
+      }
+
+      final static Any do283(Any ex) { // till
+         Any x, y;
+         String str;
+         StringBuilder sb;
+         str = evString(x = ex.Cdr);
+         if (InFile.Chr == 0)
+            InFile.get();
+         if (InFile.Chr < 0 || str.indexOf((char)InFile.Chr) >= 0)
+            return Nil;
+         if (x.Cdr.Car.eval() == Nil) {
+            y = x = new Cell(mkChar((char)InFile.Chr), Nil);
+            while (InFile.get() > 0 && str.indexOf((char)InFile.Chr) < 0)
+               x = x.Cdr = new Cell(mkChar((char)InFile.Chr), Nil);
+            return y;
+         }
+         sb = new StringBuilder();
+         do
+            sb.append((char)InFile.Chr);
+         while (InFile.get() > 0 && str.indexOf((char)InFile.Chr) < 0);
+         return mkStr(sb);
+      }
+
+      final static Any do284(Any ex) { // line
          int i;
          Any x, y, z;
          StringBuilder sb;
@@ -6017,7 +6145,42 @@ public class PicoLisp {
          }
       }
 
-      final static Any do279(Any ex) { // load
+      final static Any do285(Any ex) { // any
+         Any x;
+         if ((x = ex.Cdr.Car.eval()) == Nil)
+            return Nil;
+         PicoLispReader rd = new PicoLispReader(x.name(), ' ', '\0');
+         rd.get();
+         return rd.read0(true);
+      }
+
+      final static Any do286(Any ex) { // sym
+         StringWriter sw = new StringWriter();
+         PrintWriter wr = new PrintWriter(sw);
+         wr.print(ex.Cdr.Car.eval().toString());
+         return mkStr(sw.toString());
+      }
+
+      final static Any do287(Any ex) { // str
+         Any x, y;
+         if ((y = (x = ex.Cdr).Car.eval()) == Nil)
+            return Nil;
+         if (y instanceof Number)
+            argError(ex, y);
+         if (y instanceof Symbol)
+            return ((Symbol)y).parse(false, (x = x.Cdr) instanceof Cell? x.Car.eval() : null);
+         StringWriter sw = new StringWriter();
+         PrintWriter wr = new PrintWriter(sw);
+         for (;;) {
+            wr.print(y.Car.toString());
+            if (!((y = y.Cdr) instanceof Cell))
+               break;
+            wr.print(' ');
+         }
+         return mkStr(sw.toString());
+      }
+
+      final static Any do288(Any ex) { // load
          Any x, y;
          x = ex.Cdr;
          do {
@@ -6029,7 +6192,7 @@ public class PicoLisp {
          return y;
       }
 
-      final static Any do280(Any ex) { // in
+      final static Any do289(Any ex) { // in
          Any x;
          Env.pushInFile((x = ex.Cdr).Car.eval().rdOpen(ex));
          x = x.Cdr.prog();
@@ -6037,7 +6200,7 @@ public class PicoLisp {
          return x;
       }
 
-      final static Any do281(Any ex) { // out
+      final static Any do290(Any ex) { // out
          Any x;
          Env.pushOutFile((x = ex.Cdr).Car.eval().wrOpen(ex));
          x = x.Cdr.prog();
@@ -6045,7 +6208,7 @@ public class PicoLisp {
          return x;
       }
 
-      final static Any do282(Any ex) { // open
+      final static Any do291(Any ex) { // open
          String str;
          str = evString(ex.Cdr);
          try {return new Number(new PicoLispReader(new FileReader(str), str, allocFd(), null, 0).Fd);}
@@ -6053,7 +6216,7 @@ public class PicoLisp {
          return Nil;
       }
 
-      final static Any do283(Any ex) { // close
+      final static Any do292(Any ex) { // close
          int i;
          Any x;
          if ((i = xInt(x = ex.Cdr.Car.eval())) >= 0 && i < InFiles.length) {
@@ -6071,20 +6234,102 @@ public class PicoLisp {
          return Nil;
       }
 
-      final static Any do284(Any ex) { // prin
+      final static Any do293(Any ex) { // echo
+         int i, j, k;
+         long n;
+         Any x, y;
+         Any[] v;
+         y = (x = ex.Cdr).Car.eval();
+         if (InFile.Chr == 0)
+            InFile.get();
+         if (y == Nil && !(x.Cdr instanceof Cell)) {
+            while (InFile.Chr >= 0) {
+               OutFile.Wr.print((char)InFile.Chr);
+               InFile.get();
+            }
+            return T;
+         }
+         if (y instanceof Symbol) {
+            k = (int)x.length();
+            int[] p = new int[k];
+            String[] av = new String[k];
+            for (v = new Any[k], i = 0; i < k; ++i, y = (x = x.Cdr).Car.eval())
+               av[i] = (v[i] = y).name();
+            int m = -1, d, om, op = 0;  /* Brain-dead Java: 'op' _is_ initialized */
+            while (InFile.Chr >= 0) {
+               if ((om = m) >= 0)
+                  op = p[m];
+               for (i = 0; i < k; ++i) {
+                  for (;;) {
+                     if (av[i].charAt(p[i]) == (char)InFile.Chr) {
+                        if (++p[i] != av[i].length()) {
+                           if (m < 0  ||  p[i] > p[m])
+                              m = i;
+                           break;
+                        }
+                        if (om >= 0)
+                           for (j = 0, d = op-p[i]; j <= d; ++j)
+                              OutFile.Wr.print(av[om].charAt(j));
+                        InFile.Chr = 0;
+                        return v[i];
+                     }
+                     if (p[i] == 0)
+                        break;
+                     for (j = 1; --p[i] != 0; ++j)
+                        if (av[i].substring(0, p[i]).equals(av[i].substring(j, j + p[i])))
+                           break;
+                     if (m == i)
+                        for (m = -1, j = 0; j < k; ++j)
+                           if (p[j] != 0 && (m < 0 || p[j] > p[m]))
+                              m = j;
+                  }
+               }
+               if (m < 0) {
+                  if (om >= 0)
+                     for (i = 0; i < op; ++i)
+                        OutFile.Wr.print(av[om].charAt(i));
+                  OutFile.Wr.print((char)InFile.Chr);
+               }
+               else if (om >= 0)
+                  for (i = 0, d = op-p[m]; i <= d; ++i)
+                     OutFile.Wr.print(av[om].charAt(i));
+               InFile.get();
+            }
+            return Nil;
+         }
+         if ((x = x.Cdr) instanceof Cell) {
+            for (n = xLong(y), y = x.Car.eval(); --n >= 0; InFile.get())
+               if (InFile.Chr < 0)
+                  return Nil;
+         }
+         if ((n = xLong(y)) > 0) {
+            for (;;) {
+               if (InFile.Chr < 0)
+                  return Nil;
+               OutFile.Wr.print((char)InFile.Chr);
+               if (--n == 0)
+                  break;
+               InFile.get();
+            }
+         }
+         InFile.Chr = 0;
+         return T;
+      }
+
+      final static Any do294(Any ex) { // prin
          Any x, y;
          for (y = Nil; (ex = ex.Cdr) instanceof Cell; OutFile.Wr.print((y = ex.Car.eval()).name()));
          return y;
       }
 
-      final static Any do285(Any ex) { // prinl
+      final static Any do295(Any ex) { // prinl
          Any x, y;
          for (y = Nil; (ex = ex.Cdr) instanceof Cell; OutFile.Wr.print((y = ex.Car.eval()).name()));
          OutFile.newline();
          return y;
       }
 
-      final static Any do286(Any ex) { // space
+      final static Any do296(Any ex) { // space
          int i;
          Any x;
          if ((x = ex.Cdr.Car.eval()) == Nil) {
@@ -6096,7 +6341,7 @@ public class PicoLisp {
          return x;
       }
 
-      final static Any do287(Any ex) { // print
+      final static Any do297(Any ex) { // print
          Any x, y;
          OutFile.print(y = (x = ex.Cdr).Car.eval());
          while ((x = x.Cdr) instanceof Cell) {
@@ -6106,7 +6351,7 @@ public class PicoLisp {
          return y;
       }
 
-      final static Any do288(Any ex) { // printsp
+      final static Any do298(Any ex) { // printsp
          Any x, y;
          x = ex.Cdr;
          do {
@@ -6116,7 +6361,7 @@ public class PicoLisp {
          return y;
       }
 
-      final static Any do289(Any ex) { // println
+      final static Any do299(Any ex) { // println
          Any x, y;
          OutFile.print(y = (x = ex.Cdr).Car.eval());
          while ((x = x.Cdr) instanceof Cell) {
@@ -6127,11 +6372,11 @@ public class PicoLisp {
          return y;
       }
 
-      final static Any do290(Any ex) { // flush
+      final static Any do300(Any ex) { // flush
          return OutFile.Wr.checkError()? Nil : T;
       }
 
-      final static Any do291(Any ex) { // port
+      final static Any do301(Any ex) { // port
          ex = ex.Cdr;  // ...
          try {
             ServerSocketChannel chan = ServerSocketChannel.open();;
@@ -6142,7 +6387,7 @@ public class PicoLisp {
          return Nil;
       }
 
-      final static Any do292(Any ex) { // accept
+      final static Any do302(Any ex) { // accept
          int i;
          Any x;
          if ((i = xInt(x = ex.Cdr.Car.eval())) < 0 || i >= InFiles.length || InFiles[i] == null || InFiles[i].Chan == null)
@@ -6152,7 +6397,7 @@ public class PicoLisp {
          return Nil;
       }
 
-      final static Any do293(Any ex) { // connect
+      final static Any do303(Any ex) { // connect
          int i;
          try {
             SocketChannel chan = SocketChannel.open();
@@ -6665,7 +6910,7 @@ public class PicoLisp {
                s = s.substring(i + 1);
             if (s.startsWith("class "))
                s = s.substring(6);
-            return "$" + s;
+            return '$' + s;
 
          }
          if (Intern.get(Name) == this) {
@@ -6697,7 +6942,7 @@ public class PicoLisp {
       }
 
       final Any parse(boolean skp, Any s) {
-         Any x, y;
+         Any x, y, z;
          PicoLispReader rd;
          if (s == null)
             rd = new PicoLispReader(name(), '\n', ']');
@@ -6707,12 +6952,12 @@ public class PicoLisp {
             rd.get();
          if (s == null)
             return rd.rdList();
-         if ((x = token(s, '\0')) == null)
+         if ((x = rd.token(s, '\0')) == null)
             return Nil;
-         y = new Cell(x, Nil);
-         while ((x = token(s, '\0')) != null)
+         z = y = new Cell(x, Nil);
+         while ((x = rd.token(s, '\0')) != null)
             y = y.Cdr = new Cell(x, Nil);
-         return y;
+         return z;
       }
    }
 
@@ -7037,7 +7282,7 @@ public class PicoLisp {
          Any x, y;
          StringBuilder sb;
          if (Car == Quote  &&  this != Cdr)
-            return "'" + Cdr.toString();
+            return '\'' + Cdr.toString();
          x = this;
          sb = new StringBuilder();
          sb.append('(');
diff --git a/ersatz/fun.src b/ersatz/fun.src
@@ -1,4 +1,4 @@
-# 08nov10abu
+# 10nov10abu
 # (c) Software Lab. Alexander Burger
 
 # Ersatz PicoLisp Functions
@@ -260,7 +260,7 @@ version (i x)
    if (ex.Cdr.Car.eval() == Nil) {
       for (i = 0; i < 4; ++i)
          OutFile.Wr.print(Version[i] + (i == 3? "-" : "."));
-      OutFile.Wr.println("J");
+      OutFile.Wr.println('J');
       OutFile.Wr.flush();
    }
    for (x = Nil, i = 4; --i >= 0;)
@@ -2982,7 +2982,7 @@ read (x y)
       x = InFile.read('\0');
    else {
       y = x.Car.eval();
-      if ((x = token(y, (x = x.Cdr.Car.eval()) == Nil? '\0' : firstChar(x))) == null)
+      if ((x = InFile.token(y, (x = x.Cdr.Car.eval()) == Nil? '\0' : firstChar(x))) == null)
          x = Nil;
    }
    if (InFile.Name == null && InFile.Chr == '\n')
@@ -2997,6 +2997,30 @@ wait (i x y)
          return x.prog();
    return y;
 
+# (poll 'cnt) -> cnt | NIL
+poll (i x)
+   if ((i = xInt(x = ex.Cdr.Car.eval())) < 0 || i >= InFiles.length)
+      badFd(ex,x);
+   if (InFiles[i] == null)
+      return Nil;
+   try {
+      Selector sel = Selector.open();
+      if (InFiles[i].ready(sel))
+         return x;
+      InFiles[i].register(sel);
+      sel.selectNow();
+      if (InFiles[i].ready(sel))
+         return x;
+   }
+   catch (IOException e) {giveup(e);}
+   return Nil;
+
+# (peek) -> sym
+peek ()
+   if (InFile.Chr == 0)
+      InFile.get();
+   return InFile.Chr<0? Nil : mkChar((char)InFile.Chr);
+
 # (char) -> sym
 # (char 'cnt) -> sym
 # (char T) -> sym
@@ -3018,6 +3042,69 @@ skip (c)
    c = firstChar(ex.Cdr.Car.eval());
    return InFile.skip(c) < 0? Nil : mkChar(c);
 
+# (eol) -> flg
+eol ()
+   return InFile.Chr=='\n' || InFile.Chr<=0? T : Nil;
+
+# (eof ['flg]) -> flg
+eof ()
+   if (ex.Cdr.Car.eval() != Nil) {
+      InFile.Chr = -1;
+      return T;
+   }
+   if (InFile.Chr == 0)
+      InFile.get();
+   return InFile.Chr < 0? T : Nil;
+
+# (from 'any ..) -> sym
+from (i j k x v)
+   if ((k = (int)(x = ex.Cdr).length()) == 0)
+      return Nil;
+   int[] p = new int[k];
+   String[] av = new String[k];
+   for (v = new Any[k], i = 0; i < k; ++i, x = x.Cdr)
+      av[i] = (v[i] = x.Car.eval()).name();
+   if (InFile.Chr == 0)
+      InFile.get();
+   while (InFile.Chr >= 0) {
+      for (i = 0; i < k; ++i) {
+         for (;;) {
+            if (av[i].charAt(p[i]) == (char)InFile.Chr) {
+               if (++p[i] != av[i].length())
+                  break;
+               InFile.get();
+               return v[i];
+            }
+            if (p[i] == 0)
+               break;
+            for (j = 1; --p[i] != 0; ++j)
+               if (av[i].substring(0, p[i]).equals(av[i].substring(j, j + p[i])))
+                  break;
+         }
+      }
+      InFile.get();
+   }
+   return Nil;
+
+# (till 'any ['flg]) -> lst|sym
+till (x y str sb)
+   str = evString(x = ex.Cdr);
+   if (InFile.Chr == 0)
+      InFile.get();
+   if (InFile.Chr < 0 || str.indexOf((char)InFile.Chr) >= 0)
+      return Nil;
+   if (x.Cdr.Car.eval() == Nil) {
+      y = x = new Cell(mkChar((char)InFile.Chr), Nil);
+      while (InFile.get() > 0 && str.indexOf((char)InFile.Chr) < 0)
+         x = x.Cdr = new Cell(mkChar((char)InFile.Chr), Nil);
+      return y;
+   }
+   sb = new StringBuilder();
+   do
+      sb.append((char)InFile.Chr);
+   while (InFile.get() > 0 && str.indexOf((char)InFile.Chr) < 0);
+   return mkStr(sb);
+
 # (line 'flg) -> lst|sym
 line (i x y z sb)
    if (InFile.Chr == 0)
@@ -3039,6 +3126,40 @@ line (i x y z sb)
       y = y.Cdr = new Cell(mkChar((char)InFile.Chr), Nil);
    }
 
+# (any 'sym) -> any
+any (x)
+   if ((x = ex.Cdr.Car.eval()) == Nil)
+      return Nil;
+   PicoLispReader rd = new PicoLispReader(x.name(), ' ', '\0');
+   rd.get();
+   return rd.read0(true);
+
+# (sym 'any) -> sym
+sym ()
+   StringWriter sw = new StringWriter();
+   PrintWriter wr = new PrintWriter(sw);
+   wr.print(ex.Cdr.Car.eval().toString());
+   return mkStr(sw.toString());
+
+# (str 'sym ['sym1]) -> lst
+# (str 'lst) -> sym
+str (x y)
+   if ((y = (x = ex.Cdr).Car.eval()) == Nil)
+      return Nil;
+   if (y instanceof Number)
+      argError(ex, y);
+   if (y instanceof Symbol)
+      return ((Symbol)y).parse(false, (x = x.Cdr) instanceof Cell? x.Car.eval() : null);
+   StringWriter sw = new StringWriter();
+   PrintWriter wr = new PrintWriter(sw);
+   for (;;) {
+      wr.print(y.Car.toString());
+      if (!((y = y.Cdr) instanceof Cell))
+         break;
+      wr.print(' ');
+   }
+   return mkStr(sw.toString());
+
 # (load 'any ..) -> any
 load (x y)
    x = ex.Cdr;
@@ -3087,6 +3208,84 @@ close (i x)
    }
    return Nil;
 
+# (echo ['cnt ['cnt]] | ['sym ..]) -> sym
+echo (i j k n x y v)
+   y = (x = ex.Cdr).Car.eval();
+   if (InFile.Chr == 0)
+      InFile.get();
+   if (y == Nil && !(x.Cdr instanceof Cell)) {
+      while (InFile.Chr >= 0) {
+         OutFile.Wr.print((char)InFile.Chr);
+         InFile.get();
+      }
+      return T;
+   }
+   if (y instanceof Symbol) {
+      k = (int)x.length();
+      int[] p = new int[k];
+      String[] av = new String[k];
+      for (v = new Any[k], i = 0; i < k; ++i, y = (x = x.Cdr).Car.eval())
+         av[i] = (v[i] = y).name();
+      int m = -1, d, om, op = 0;  /* Brain-dead Java: 'op' _is_ initialized */
+      while (InFile.Chr >= 0) {
+         if ((om = m) >= 0)
+            op = p[m];
+         for (i = 0; i < k; ++i) {
+            for (;;) {
+               if (av[i].charAt(p[i]) == (char)InFile.Chr) {
+                  if (++p[i] != av[i].length()) {
+                     if (m < 0  ||  p[i] > p[m])
+                        m = i;
+                     break;
+                  }
+                  if (om >= 0)
+                     for (j = 0, d = op-p[i]; j <= d; ++j)
+                        OutFile.Wr.print(av[om].charAt(j));
+                  InFile.Chr = 0;
+                  return v[i];
+               }
+               if (p[i] == 0)
+                  break;
+               for (j = 1; --p[i] != 0; ++j)
+                  if (av[i].substring(0, p[i]).equals(av[i].substring(j, j + p[i])))
+                     break;
+               if (m == i)
+                  for (m = -1, j = 0; j < k; ++j)
+                     if (p[j] != 0 && (m < 0 || p[j] > p[m]))
+                        m = j;
+            }
+         }
+         if (m < 0) {
+            if (om >= 0)
+               for (i = 0; i < op; ++i)
+                  OutFile.Wr.print(av[om].charAt(i));
+            OutFile.Wr.print((char)InFile.Chr);
+         }
+         else if (om >= 0)
+            for (i = 0, d = op-p[m]; i <= d; ++i)
+               OutFile.Wr.print(av[om].charAt(i));
+         InFile.get();
+      }
+      return Nil;
+   }
+   if ((x = x.Cdr) instanceof Cell) {
+      for (n = xLong(y), y = x.Car.eval(); --n >= 0; InFile.get())
+         if (InFile.Chr < 0)
+            return Nil;
+   }
+   if ((n = xLong(y)) > 0) {
+      for (;;) {
+         if (InFile.Chr < 0)
+            return Nil;
+         OutFile.Wr.print((char)InFile.Chr);
+         if (--n == 0)
+            break;
+         InFile.get();
+      }
+   }
+   InFile.Chr = 0;
+   return T;
+
 # (prin 'any ..) -> any
 prin (x y)
    for (y = Nil; (ex = ex.Cdr) instanceof Cell; OutFile.Wr.print((y = ex.Car.eval()).name()));
diff --git a/ersatz/picolisp.jar b/ersatz/picolisp.jar
Binary files differ.
diff --git a/ersatz/sys.src b/ersatz/sys.src
@@ -1,4 +1,4 @@
-// 09nov10abu
+// 10nov10abu
 // (c) Software Lab. Alexander Burger
 
 import java.util.*;
@@ -255,7 +255,7 @@ public class PicoLisp {
       if (s.length() > 0)
          if (s.charAt(0) == '+') {
             if (s.length() > 1 && s.charAt(1) == '@')
-               return "+" + Home + s.substring(1);
+               return '+' + Home + s.substring(1);
          }
          else if (s.charAt(0) == '@')
             return Home + s.substring(1);
@@ -568,50 +568,6 @@ public class PicoLisp {
       catch (NumberFormatException e) {return Nil;}
    }
 
-   final static Any token(Any x, char c) {
-      if (InFile.Chr == 0)
-         InFile.get();
-      if (InFile.skip(c) < 0)
-         return null;
-      if (InFile.Chr == '"') {
-         InFile.get();
-         if (InFile.Chr == '"') {
-            InFile.get();
-            return Nil;
-         }
-         if (!InFile.testEsc())
-            return Nil;
-         StringBuilder sb = new StringBuilder();
-         sb.append((char)InFile.Chr);
-         while (InFile.get() != '"' && InFile.testEsc())
-            sb.append((char)InFile.Chr);
-         InFile.get();
-         return mkStr(sb);
-      }
-      if (InFile.Chr >= '0' && InFile.Chr <= '9') {
-         StringBuilder sb = new StringBuilder();
-         sb.append((char)InFile.Chr);
-         while (InFile.get() >= '0' && InFile.Chr <= '9' || InFile.Chr == '.')
-            sb.append((char)InFile.Chr);
-         return strToAtom(sb.toString());
-      }
-      String s = x.name();
-      if (InFile.Chr >= 'A' && InFile.Chr <= 'Z' || InFile.Chr == '\\' || InFile.Chr >= 'a' && InFile.Chr <= 'z' || s.indexOf(InFile.Chr) >= 0) {
-         if (InFile.Chr == '\\')
-            InFile.get();
-         StringBuilder sb = new StringBuilder();
-         sb.append((char)InFile.Chr);
-         while (InFile.get() >= '0' && InFile.Chr <= '9' || InFile.Chr >= 'A' && InFile.Chr <= 'Z' || InFile.Chr == '\\' || InFile.Chr >= 'a' && InFile.Chr <= 'z' || s.indexOf(InFile.Chr) >= 0) {
-            if (InFile.Chr == '\\')
-               InFile.get();
-            sb.append((char)InFile.Chr);
-         }
-         s = sb.toString();
-         return s.equals("NIL")? Nil : mkSymbol(Nil, s, Intern);
-      }
-      return mkChar((char)InFile.get());
-   }
-
    final static Any fish(Any ex, Any foo, Any[] v, Any res) {
       if (foo.apply(ex, false, v, 1) != Nil)
          return new Cell(v[0], res);
@@ -703,6 +659,7 @@ public class PicoLisp {
 
    final static int xInt(Any x) {return ((Number)x).Cnt;}
    final static int evInt(Any ex) {return ((Number)ex.Car.eval()).Cnt;}
+   final static long xLong(Any x) {return ((Number)x).longValue();}
    final static long evLong(Any ex) {return ((Number)ex.Car.eval()).longValue();}
    final static String evString(Any ex) {return ex.Car.eval().name();}
 
@@ -1353,7 +1310,7 @@ public class PicoLisp {
             }
             return Chr;
          }
-         catch (IOException e) {return -1;}
+         catch (IOException e) {return Chr = -1;}
       }
 
       final boolean eol() {
@@ -1497,8 +1454,8 @@ public class PicoLisp {
                return Nil;
             eofErr();
          }
-         if (top && InFile != null && InFile.Rd instanceof LineNumberReader)
-            InFile.Src = ((LineNumberReader)InFile.Rd).getLineNumber() + 1;
+         if (top && Rd instanceof LineNumberReader)
+            Src = ((LineNumberReader)Rd).getLineNumber() + 1;
          if (Chr == '(') {
             x = rdList();
             if (top  &&  Chr == ']')
@@ -1543,7 +1500,7 @@ public class PicoLisp {
             return mkSymbol(null, sb.toString(), Transient);
          }
          if (Chr == ')' || Chr == ']' || Chr == '~')
-            err(null, null, "Bad input '" + (char)Chr + "' (" + Chr + ")");
+            err(null, null, "Bad input '" + (char)Chr + "' (" + Chr + ')');
          if (Chr == '\\')
             get();
          int i = Chr;
@@ -1561,6 +1518,52 @@ public class PicoLisp {
             get();
          return x;
       }
+
+      final Any token(Any x, char c) {
+         if (Chr == 0)
+            get();
+         if (skip(c) < 0)
+            return null;
+         if (Chr == '"') {
+            get();
+            if (Chr == '"') {
+               get();
+               return Nil;
+            }
+            if (!testEsc())
+               return Nil;
+            StringBuilder sb = new StringBuilder();
+            sb.append((char)Chr);
+            while (get() != '"' && testEsc())
+               sb.append((char)Chr);
+            get();
+            return mkStr(sb);
+         }
+         if (Chr >= '0' && Chr <= '9') {
+            StringBuilder sb = new StringBuilder();
+            sb.append((char)Chr);
+            while (get() >= '0' && Chr <= '9' || Chr == '.')
+               sb.append((char)Chr);
+            return strToAtom(sb.toString());
+         }
+         String s = x.name();
+         if (Chr >= 'A' && Chr <= 'Z' || Chr == '\\' || Chr >= 'a' && Chr <= 'z' || s.indexOf(Chr) >= 0) {
+            if (Chr == '\\')
+               get();
+            StringBuilder sb = new StringBuilder();
+            sb.append((char)Chr);
+            while (get() >= '0' && Chr <= '9' || Chr >= 'A' && Chr <= 'Z' || Chr == '\\' || Chr >= 'a' && Chr <= 'z' || s.indexOf(Chr) >= 0) {
+               if (Chr == '\\')
+                  get();
+               sb.append((char)Chr);
+            }
+            s = sb.toString();
+            return s.equals("NIL")? Nil : mkSymbol(Nil, s, Intern);
+         }
+         c = (char)Chr;
+         get();
+         return mkChar(c);
+      }
    }
 
    /* Ersatz PicoLisp Printer */
@@ -2308,7 +2311,7 @@ public class PicoLisp {
                s = s.substring(i + 1);
             if (s.startsWith("class "))
                s = s.substring(6);
-            return "$" + s;
+            return '$' + s;
 
          }
          if (Intern.get(Name) == this) {
@@ -2340,7 +2343,7 @@ public class PicoLisp {
       }
 
       final Any parse(boolean skp, Any s) {
-         Any x, y;
+         Any x, y, z;
          PicoLispReader rd;
          if (s == null)
             rd = new PicoLispReader(name(), '\n', ']');
@@ -2350,12 +2353,12 @@ public class PicoLisp {
             rd.get();
          if (s == null)
             return rd.rdList();
-         if ((x = token(s, '\0')) == null)
+         if ((x = rd.token(s, '\0')) == null)
             return Nil;
-         y = new Cell(x, Nil);
-         while ((x = token(s, '\0')) != null)
+         z = y = new Cell(x, Nil);
+         while ((x = rd.token(s, '\0')) != null)
             y = y.Cdr = new Cell(x, Nil);
-         return y;
+         return z;
       }
    }
 
@@ -2680,7 +2683,7 @@ public class PicoLisp {
          Any x, y;
          StringBuilder sb;
          if (Car == Quote  &&  this != Cdr)
-            return "'" + Cdr.toString();
+            return '\'' + Cdr.toString();
          x = this;
          sb = new StringBuilder();
          sb.append('(');
diff --git a/src64/version.l b/src64/version.l
@@ -1,6 +1,6 @@
-# 01nov10abu
+# 10nov10abu
 # (c) Software Lab. Alexander Burger
 
-(de *Version 3 0 4 4)
+(de *Version 3 0 4 5)
 
 # vi:et:ts=3:sw=3