1 21 22 package org.armedbear.lisp; 23 24 import java.io.BufferedInputStream ; 25 import java.io.BufferedOutputStream ; 26 import java.io.BufferedReader ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.InputStreamReader ; 30 import java.io.OutputStream ; 31 import java.io.OutputStreamWriter ; 32 import java.io.PrintWriter ; 33 import java.io.PushbackReader ; 34 import java.io.StringWriter ; 35 import java.io.Writer ; 36 import java.math.BigInteger ; 37 import java.util.BitSet ; 38 39 public class Stream extends LispObject 40 { 41 protected LispObject elementType; 42 protected boolean isInputStream; 43 protected boolean isOutputStream; 44 protected boolean isCharacterStream; 45 protected boolean isBinaryStream; 46 47 private boolean interactive; 48 private boolean open = true; 49 50 private PushbackReader reader; 52 protected int offset; 53 protected int lineNumber; 54 55 private Writer writer; 57 58 protected int charPos; 60 61 private BufferedInputStream in; 63 64 private BufferedOutputStream out; 66 67 protected Stream() 68 { 69 } 70 71 public Stream(InputStream inputStream, LispObject elementType) 73 { 74 this.elementType = elementType; 75 if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR) { 76 isCharacterStream = true; 77 InputStreamReader inputStreamReader; 78 try { 79 inputStreamReader = 80 new InputStreamReader (inputStream, "ISO-8859-1"); 81 } 82 catch (java.io.UnsupportedEncodingException e) { 83 Debug.trace(e); 84 inputStreamReader = 85 new InputStreamReader (inputStream); 86 } 87 reader = new PushbackReader (new BufferedReader (inputStreamReader), 88 2); 89 } else { 90 isBinaryStream = true; 91 in = new BufferedInputStream (inputStream); 92 } 93 isInputStream = true; 94 isOutputStream = false; 95 } 96 97 public Stream(InputStream inputStream, LispObject elementType, boolean interactive) 98 { 99 this(inputStream, elementType); 100 setInteractive(interactive); 101 } 102 103 public Stream(OutputStream outputStream, LispObject elementType) 105 { 106 this.elementType = elementType; 107 if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR) { 108 isCharacterStream = true; 109 try { 110 writer = new OutputStreamWriter (outputStream, "ISO-8859-1"); 111 } 112 catch (java.io.UnsupportedEncodingException e) { 113 Debug.trace(e); 114 writer = new OutputStreamWriter (outputStream); 115 } 116 } else { 117 isBinaryStream = true; 118 out = new BufferedOutputStream (outputStream); 119 } 120 isInputStream = false; 121 isOutputStream = true; 122 } 123 124 public Stream(OutputStream outputStream, LispObject elementType, 125 boolean interactive) 126 { 127 this(outputStream, elementType); 128 setInteractive(interactive); 129 } 130 131 public boolean isInputStream() throws ConditionThrowable 132 { 133 return isInputStream; 134 } 135 136 public boolean isOutputStream() throws ConditionThrowable 137 { 138 return isOutputStream; 139 } 140 141 public boolean isCharacterInputStream() throws ConditionThrowable 142 { 143 return isCharacterStream && isInputStream; 144 } 145 146 public boolean isBinaryInputStream() throws ConditionThrowable 147 { 148 return isBinaryStream && isInputStream; 149 } 150 151 public boolean isCharacterOutputStream() throws ConditionThrowable 152 { 153 return isCharacterStream && isOutputStream; 154 } 155 156 public boolean isBinaryOutputStream() throws ConditionThrowable 157 { 158 return isBinaryStream && isOutputStream; 159 } 160 161 public boolean isInteractive() 162 { 163 return interactive; 164 } 165 166 public void setInteractive(boolean b) 167 { 168 interactive = b; 169 } 170 171 public boolean isOpen() 172 { 173 return open; 174 } 175 176 public void setOpen(boolean b) 177 { 178 open = b; 179 } 180 181 public LispObject typeOf() 182 { 183 return Symbol.STREAM; 184 } 185 186 public LispClass classOf() 187 { 188 return BuiltInClass.STREAM; 189 } 190 191 public LispObject typep(LispObject typeSpecifier) throws ConditionThrowable 192 { 193 if (typeSpecifier == Symbol.STREAM) 194 return T; 195 if (typeSpecifier == BuiltInClass.STREAM) 196 return T; 197 return super.typep(typeSpecifier); 198 } 199 200 public LispObject getElementType() throws ConditionThrowable 201 { 202 return elementType; 203 } 204 205 public int getOffset() 207 { 208 return offset; 209 } 210 211 public int getLineNumber() 213 { 214 return lineNumber; 215 } 216 217 protected void setWriter(Writer writer) 218 { 219 this.writer = writer; 220 } 221 222 public int getCharPos() 224 { 225 return charPos; 226 } 227 228 public void setCharPos(int n) 230 { 231 charPos = n; 232 } 233 234 public LispObject read(boolean eofError, LispObject eofValue, 235 boolean recursive) 236 throws ConditionThrowable 237 { 238 LispObject result = readPreservingWhitespace(eofError, eofValue, 239 recursive); 240 if (result != eofValue && !recursive) { 241 if (_charReady()) { 242 int n = _readChar(); 243 if (n >= 0) { 244 char c = (char) n; 245 if (!currentReadtable().isWhitespace(c)) 246 _unreadChar(c); 247 } 248 } 249 } 250 if (_READ_SUPPRESS_.symbolValueNoThrow() != NIL) 251 return NIL; 252 else 253 return result; 254 } 255 256 public LispObject readPreservingWhitespace(boolean eofError, 257 LispObject eofValue, 258 boolean recursive) 259 throws ConditionThrowable 260 { 261 final Readtable rt = currentReadtable(); 262 while (true) { 263 int n = _readChar(); 264 if (n < 0) { 265 if (eofError) 266 return signal(new EndOfFile(this)); 267 else 268 return eofValue; 269 } 270 char c = (char) n; 271 if (rt.isWhitespace(c)) 272 continue; 273 LispObject result = processChar(c); 274 if (result != null) 275 return result; 276 } 277 } 278 279 private LispObject processChar(char c) throws ConditionThrowable 280 { 281 LispObject handler = currentReadtable().getReaderMacroFunction(c); 282 if (handler instanceof ReaderMacroFunction) 283 return ((ReaderMacroFunction)handler).execute(this, c); 284 if (handler != null && handler != NIL) 285 return handler.execute(this, LispCharacter.getInstance(c)); 286 return readToken(c); 287 } 288 289 public LispObject readPathname() throws ConditionThrowable 290 { 291 LispObject obj = read(true, NIL, false); 292 if (obj instanceof AbstractString) 293 return new Pathname(obj.getStringValue()); 294 if (obj.listp()) 295 return Pathname.makePathname(obj); 296 return signal(new TypeError("#p requires a string or list argument.")); 297 } 298 299 public LispObject readSymbol() throws ConditionThrowable 300 { 301 StringBuffer sb = new StringBuffer (); 302 _readToken(sb, LispThread.currentThread()); 303 return new Symbol(sb.toString()); 304 } 305 306 public LispObject readStructure() throws ConditionThrowable 307 { 308 LispObject obj = read(true, NIL, false); 309 if (_READ_SUPPRESS_.symbolValueNoThrow() != NIL) 310 return NIL; 311 if (obj.listp()) { 312 Symbol structure = checkSymbol(obj.car()); 313 LispClass c = LispClass.findClass(structure); 314 if (!(c instanceof StructureClass)) { 315 return signal(new ReaderError(structure.getName() + 316 " is not a defined structure type.")); 317 } 318 LispObject args = obj.cdr(); 319 Package pkg = checkPackage(structure.getPackage()); 320 Symbol constructor = pkg.intern("MAKE-" + structure.getName()); 321 return funcall(constructor.getSymbolFunctionOrDie(), 322 args.copyToArray(), LispThread.currentThread()); 323 } 324 return signal(new ReaderError("Non-list following #S: " + obj)); 325 } 326 327 public LispObject readList() throws ConditionThrowable 328 { 329 Cons first = null; 330 Cons last = null; 331 while (true) { 332 char c = flushWhitespace(); 333 if (c == ')') { 334 return first == null ? NIL : first; 335 } 336 if (c == '.') { 337 int n = _readChar(); 338 if (n < 0) 339 return signal(new EndOfFile(this)); 340 char nextChar = (char) n; 341 if (nextChar == ',') { 342 LispObject obj = readComma(); 343 last.setCdr(obj); 344 continue; 345 } else if (isTokenDelimiter(nextChar)) { 346 if (last == null) 347 return signal(new ReaderError("Nothing appears before . in list.")); 348 LispObject obj = read(true, NIL, true); 349 last.setCdr(obj); 350 continue; 351 } else { 352 _unreadChar(nextChar); 354 } 355 } 356 LispObject obj = processChar(c); 357 if (obj == null) { 358 continue; 360 } 361 if (first == null) { 362 first = new Cons(obj); 363 last = first; 364 } else { 365 Cons newCons = new Cons(obj); 366 last.setCdr(newCons); 367 last = newCons; 368 } 369 } 370 } 371 372 private static final boolean isTokenDelimiter(char c) 373 throws ConditionThrowable 374 { 375 switch (c) { 376 case '"': 377 case '\'': 378 case '(': 379 case ')': 380 case ',': 381 case ';': 382 case '`': 383 return true; 384 default: 385 return currentReadtable().isWhitespace(c); 386 } 387 } 388 389 public LispObject readComma() throws ConditionThrowable 390 { 391 int n = _readChar(); 392 if (n < 0) 393 return signal(new EndOfFile(this)); 394 char c = (char) n; 395 switch (c) { 396 case '@': 397 return new Cons(Symbol.COMMA_ATSIGN, 398 new Cons(read(true, NIL, true), NIL)); 399 case '.': 400 return new Cons(Symbol.COMMA_DOT, 401 new Cons(read(true, NIL, true), NIL)); 402 default: 403 _unreadChar(c); 404 return new Cons(Symbol.COMMA, 405 new Cons(read(true, NIL, true), NIL)); 406 } 407 } 408 409 public LispObject readDispatchChar(char ignored) throws ConditionThrowable 410 { 411 int numArg = -1; 412 char c; 413 while (true) { 414 int n = _readChar(); 415 if (n < 0) 416 return signal(new EndOfFile(this)); 417 c = (char) n; 418 if (c < '0' || c > '9') 419 break; 420 if (numArg < 0) 421 numArg = 0; 422 numArg = numArg * 10 + c - '0'; 423 } 424 LispObject fun = 425 currentReadtable().getDispatchMacroCharacter('#', c); 426 if (fun instanceof DispatchMacroFunction) 427 return ((DispatchMacroFunction)fun).execute(this, c, numArg); 428 if (fun != NIL) { 429 final LispThread thread = LispThread.currentThread(); 430 LispObject result = funcall3(fun, 431 this, 432 LispCharacter.getInstance(c), 433 (numArg < 0) ? NIL : new Fixnum(numArg), 434 thread); 435 LispObject[] values = thread.getValues(); 436 if (values != null && values.length == 0) 437 result = null; 438 thread.clearValues(); 439 return result; 440 } 441 return null; 442 } 443 444 public LispObject readCharacterLiteral() throws ConditionThrowable 445 { 446 int n = _readChar(); 447 if (n < 0) 448 return signal(new EndOfFile(this)); 449 char c = (char) n; 450 StringBuffer sb = new StringBuffer (); 451 sb.append(c); 452 Readtable rt = currentReadtable(); 453 while (true) { 454 n = _readChar(); 455 if (n < 0) 456 break; 457 c = (char) n; 458 if (rt.isWhitespace(c)) 459 break; 460 if (c == '(' || c == ')') { 461 _unreadChar(c); 462 break; 463 } 464 sb.append(c); 465 } 466 if (_READ_SUPPRESS_.symbolValueNoThrow() != NIL) 467 return NIL; 468 String token = sb.toString(); 469 if (token.length() == 1) 470 return LispCharacter.getInstance(token.charAt(0)); 471 n = LispCharacter.nameToChar(token); 472 if (n >= 0) 473 return LispCharacter.getInstance((char)n); 474 return signal(new LispError("Unrecognized character name: \"" + token + '"')); 475 } 476 477 public void skipBalancedComment() throws ConditionThrowable 478 { 479 while (true) { 480 int n = _readChar(); 481 if (n < 0) 482 return; 483 if (n == '|') { 484 n = _readChar(); 485 if (n == '#') 486 return; 487 else 488 _unreadChar(n); 489 } else if (n == '#') { 490 n = _readChar(); 491 if (n == '|') 492 skipBalancedComment(); else 494 _unreadChar(n); 495 } 496 } 497 } 498 499 public LispObject readBitVector() throws ConditionThrowable 500 { 501 StringBuffer sb = new StringBuffer (); 502 while (true) { 503 int n = _readChar(); 504 if (n < 0) 505 break; 506 char c = (char) n; 507 if (c == '0' || c == '1') 508 sb.append(c); 509 else { 510 _unreadChar(c); 511 break; 512 } 513 } 514 return new SimpleBitVector(sb.toString()); 515 } 516 517 public LispObject readArray(int rank) throws ConditionThrowable 518 { 519 LispObject obj = read(true, NIL, true); 520 switch (rank) { 521 case -1: 522 return signal(new ReaderError("No dimensions argument to #A.")); 523 case 0: 524 return new ZeroRankArray(T, obj, false); 525 case 1: 526 return new SimpleVector(obj); 527 default: 528 return new SimpleArray(rank, obj); 529 } 530 } 531 532 public LispObject readComplex() throws ConditionThrowable 533 { 534 LispObject obj = read(true, NIL, true); 535 if (_READ_SUPPRESS_.symbolValue() != NIL) 536 return NIL; 537 if (obj instanceof Cons && obj.length() == 2) 538 return Complex.getInstance(obj.car(), obj.cadr()); 539 StringBuffer sb = new StringBuffer ("Invalid complex number format"); 541 if (this instanceof FileStream) { 542 Pathname p = ((FileStream)this).getPathname(); 543 if (p != null) { 544 String namestring = p.getNamestring(); 545 if (namestring != null) { 546 sb.append(" in #P\""); 547 sb.append(namestring); 548 sb.append('"'); 549 } 550 } 551 sb.append(" at offset "); 552 sb.append(_getFilePosition()); 553 } 554 sb.append(": #C"); 555 sb.append(obj.writeToString()); 556 return signal(new ReaderError(sb.toString())); 557 } 558 559 private String readMultipleEscape() throws ConditionThrowable 560 { 561 StringBuffer sb = new StringBuffer (); 562 while (true) { 563 int n = _readChar(); 564 if (n < 0) 565 break; 566 char c = (char) n; 567 if (c == '\\') { 568 n = _readChar(); 569 if (n < 0) { 570 signal(new EndOfFile(this)); 571 return null; 573 } 574 sb.append((char)n); 575 continue; 576 } 577 if (c == '|') 578 break; 579 sb.append(c); 580 } 581 return sb.toString(); 582 } 583 584 private static final int findUnescapedSingleColon(String s, BitSet flags) 585 { 586 if (flags == null) 587 return s.indexOf(':'); 588 final int limit = s.length(); 589 for (int i = 0; i < limit; i++) { 590 if (s.charAt(i) == ':' && !flags.get(i)) { 591 return i; 592 } 593 } 594 return -1; 595 } 596 597 private static final int findUnescapedDoubleColon(String s, BitSet flags) 598 { 599 if (flags == null) 600 return s.indexOf("::"); 601 final int limit = s.length() - 1; 602 for (int i = 0; i < limit; i++) { 603 if (s.charAt(i) == ':' && !flags.get(i)) { 604 if (s.charAt(i + 1) == ':' && !flags.get(i + 1)) { 605 return i; 606 } 607 } 608 } 609 return -1; 610 } 611 612 private final LispObject readToken(char c) throws ConditionThrowable 613 { 614 StringBuffer sb = new StringBuffer (); 615 sb.append(c); 616 final LispThread thread = LispThread.currentThread(); 617 BitSet flags = _readToken(sb, thread); 618 boolean escaped = (flags != null); 619 if (_READ_SUPPRESS_.symbolValue(thread) != NIL) 620 return NIL; 621 final String token = sb.toString(); 622 final int length = token.length(); 623 if (length > 0) { 624 final char firstChar = token.charAt(0); 625 if (flags == null) { 626 if (firstChar == '.') { 627 boolean ok = false; 634 for (int i = length; i-- > 1;) { 635 if (token.charAt(i) != '.') { 636 ok = true; 637 break; 638 } 639 } 640 if (!ok) { 641 final String message; 642 if (length > 1) 643 message = "Too many dots."; 644 else 645 message = "Dot context error."; 646 return signal(new ReaderError(message)); 647 } 648 } 649 final int radix = getReadBase(thread); 650 if ("-+0123456789".indexOf(firstChar) >= 0) { 651 LispObject number = makeNumber(token, length, radix); 652 if (number != null) 653 return number; 654 } else if (Character.digit(firstChar, radix) >= 0) { 655 LispObject number = makeNumber(token, length, radix); 656 if (number != null) 657 return number; 658 } 659 } 660 if (firstChar == ':') 661 return PACKAGE_KEYWORD.intern(token.substring(1)); 662 int index = findUnescapedDoubleColon(token, flags); 663 if (index > 0) { 664 String packageName = token.substring(0, index); 665 String symbolName = token.substring(index + 2); 666 Package pkg = Packages.findPackage(packageName); 667 if (pkg == null) 668 return signal(new LispError("Package \"" + packageName + 669 "\" not found.")); 670 return pkg.intern(symbolName); 671 } 672 index = findUnescapedSingleColon(token, flags); 673 if (index > 0) { 674 String packageName = token.substring(0, index); 675 String symbolName = token.substring(index + 1); 676 Package pkg = Packages.findPackage(packageName); 677 if (pkg == null) 678 return signal(new PackageError("Package \"" + packageName + 679 "\" not found.")); 680 Symbol symbol = pkg.findExternalSymbol(symbolName); 681 if (symbol != null) 682 return symbol; 683 if (pkg.findInternalSymbol(symbolName) != null) 685 return signal(new LispError("The symbol \"" + symbolName + 686 "\" is not external in package " + 687 packageName + '.')); 688 else 689 return signal(new LispError("The symbol \"" + symbolName + 690 "\" was not found in package " + 691 packageName + '.')); 692 } 693 } 694 return ((Package )_PACKAGE_.symbolValue(thread)).intern(token); 696 } 697 698 private final BitSet _readToken(StringBuffer sb, LispThread thread) 699 throws ConditionThrowable 700 { 701 BitSet flags = null; 702 final Readtable rt = currentReadtable(thread); 703 final LispObject readtableCase = rt.getReadtableCase(); 704 if (sb.length() > 0) { 705 Debug.assertTrue(sb.length() == 1); 706 char c = sb.charAt(0); 707 if (c == '|') { 708 sb.setLength(0); 709 sb.append(readMultipleEscape()); 710 flags = new BitSet (sb.length()); 711 for (int i = sb.length(); i-- > 0;) 712 flags.set(i); 713 } else if (c == '\\') { 714 int n = _readChar(); 715 if (n < 0) { 716 signal(new EndOfFile(this)); 717 return flags; 719 } 720 sb.setCharAt(0, (char) n); 721 flags = new BitSet (1); 722 flags.set(0); 723 } else if (readtableCase == Keyword.UPCASE) { 724 sb.setCharAt(0, Utilities.toUpperCase(c)); 725 } else if (readtableCase == Keyword.DOWNCASE) { 726 sb.setCharAt(0, Utilities.toLowerCase(c)); 727 } 728 } 729 loop: 730 while (true) { 731 int n = _readChar(); 732 if (n < 0) 733 break; 734 char c = (char) n; 735 if (rt.isWhitespace(c)) 736 break; 737 if (rt.getAttribute(c) == Readtable.ATTR_TERMINATING_MACRO) { 738 _unreadChar(c); 739 break; 740 } 741 switch (c) { 742 case '\\': 743 n = _readChar(); 744 if (n < 0) 745 break loop; 746 sb.append((char)n); 747 if (flags == null) 748 flags = new BitSet (sb.length()); 749 flags.set(sb.length() - 1); 750 break; 751 case '|': { 752 int begin = sb.length(); 753 sb.append(readMultipleEscape()); 754 int end = sb.length(); 755 if (flags == null) 756 flags = new BitSet (sb.length()); 757 for (int i = begin; i < end; i++) 758 flags.set(i); 759 break; 760 } 761 default: 762 if (readtableCase == Keyword.UPCASE) 763 c = Utilities.toUpperCase(c); 764 else if (readtableCase == Keyword.DOWNCASE) 765 c = Utilities.toLowerCase(c); 766 sb.append(c); 767 } 768 } 769 if (readtableCase == Keyword.INVERT) { 770 String s = invert(sb.toString()); 772 sb.setLength(0); 773 sb.append(s); 774 } 775 return flags; 776 } 777 778 private static final int getReadBase(LispThread thread) 779 throws ConditionThrowable 780 { 781 final int readBase; 782 try { 783 readBase = ((Fixnum)_READ_BASE_.symbolValue(thread)).value; 784 } 785 catch (ClassCastException e) { 786 signal(new LispError("The value of *READ-BASE* is not of type '(INTEGER 2 36).")); 788 return 10; 790 } 791 if (readBase < 2 || readBase > 36) { 792 signal(new LispError("The value of *READ-BASE* is not of type '(INTEGER 2 36).")); 793 return 10; 795 } 796 return readBase; 797 } 798 799 private static final LispObject makeNumber(String token, 800 int length, 801 int radix) 802 throws ConditionThrowable 803 { 804 if (length == 0) 805 return null; 806 if (token.indexOf('/') >= 0) 807 return makeRatio(token, radix); 808 if (token.charAt(length - 1) == '.') { 809 radix = 10; 810 token = token.substring(0, --length); 811 } 812 boolean numeric = true; 813 if (radix == 10) { 814 for (int i = length; i-- > 0;) { 815 char c = token.charAt(i); 816 if (c < '0' || c > '9') { 817 if (i > 0 || (c != '-' && c != '+')) { 818 numeric = false; 819 break; 820 } 821 } 822 } 823 } else { 824 for (int i = length; i-- > 0;) { 825 char c = token.charAt(i); 826 if (Character.digit(c, radix) < 0) { 827 if (i > 0 || (c != '-' && c != '+')) { 828 numeric = false; 829 break; 830 } 831 } 832 } 833 } 834 if (!numeric) return makeFloat(token, length); 836 if (token.charAt(0) == '+') 837 token = token.substring(1); 838 try { 839 return new Fixnum(Integer.parseInt(token, radix)); 840 } 841 catch (NumberFormatException e) {} 842 try { 844 return new Bignum(new BigInteger (token, radix)); 845 } 846 catch (NumberFormatException e) {} 847 return null; 849 } 850 851 private static final LispObject makeRatio(String token, int radix) 852 throws ConditionThrowable 853 { 854 final int index = token.indexOf('/'); 855 if (index < 0) 856 return null; 857 try { 858 BigInteger numerator = 859 new BigInteger (token.substring(0, index), radix); 860 BigInteger denominator = 861 new BigInteger (token.substring(index + 1), radix); 862 return number(numerator, denominator); 863 } 864 catch (NumberFormatException e) {} 865 return null; 866 } 867 868 private static final LispObject makeFloat(final String token, 869 final int length) 870 throws ConditionThrowable 871 { 872 if (length == 0) 873 return null; 874 StringBuffer sb = new StringBuffer (); 875 int i = 0; 876 boolean maybe = false; 877 char c = token.charAt(i); 878 if (c == '-' || c == '+') { 879 sb.append(c); 880 ++i; 881 } 882 while (i < length) { 883 c = token.charAt(i); 884 if (c == '.' || (c >= '0' && c <= '9')) { 885 if (c == '.') 886 maybe = true; 887 sb.append(c); 888 ++i; 889 } else 890 break; 891 } 892 if (i < length) { 893 if ("esfdlESFDL".indexOf(token.charAt(i)) >= 0) { 894 maybe = true; 896 sb.append('E'); 897 ++i; 898 } 899 } 900 if (!maybe) 901 return null; 902 sb.append(token.substring(i)); 904 try { 905 return new LispFloat(Double.parseDouble(sb.toString())); 906 } 907 catch (NumberFormatException e) { 908 return null; 909 } 910 } 911 912 public LispObject readRadix(int radix) throws ConditionThrowable 913 { 914 StringBuffer sb = new StringBuffer (); 915 boolean escaped = (_readToken(sb, LispThread.currentThread()) != null); 916 if (escaped) 917 return signal(new ReaderError("Illegal syntax for number.")); 918 String s = sb.toString(); 919 if (s.indexOf('/') >= 0) 920 return makeRatio(s, radix); 921 try { 922 return new Fixnum(Integer.parseInt(s, radix)); 923 } 924 catch (NumberFormatException e) {} 925 try { 927 return new Bignum(new BigInteger (s, radix)); 928 } 929 catch (NumberFormatException e) {} 930 return signal(new LispError()); 932 } 933 934 private char flushWhitespace() throws ConditionThrowable 935 { 936 final Readtable rt = currentReadtable(); 937 while (true) { 938 int n = _readChar(); 939 if (n < 0) { 940 signal(new EndOfFile(this)); 941 return 0; 943 } 944 char c = (char) n; 945 if (!rt.isWhitespace(c)) 946 return c; 947 } 948 } 949 950 public LispObject readDelimitedList(char delimiter) 951 throws ConditionThrowable 952 { 953 LispObject result = NIL; 954 while (true) { 955 char c = flushWhitespace(); 956 if (c == delimiter) 957 break; 958 LispObject obj = processChar(c); 959 if (obj != null) 960 result = new Cons(obj, result); 961 } 962 return result.nreverse(); 963 } 964 965 public LispObject readLine(boolean eofError, LispObject eofValue) 969 throws ConditionThrowable 970 { 971 final LispThread thread = LispThread.currentThread(); 972 StringBuffer sb = new StringBuffer (); 973 while (true) { 974 int n = _readChar(); 975 if (n < 0) { 976 if (sb.length() == 0) { 977 if (eofError) 978 return signal(new EndOfFile(this)); 979 return thread.setValues(eofValue, T); 980 } 981 return thread.setValues(new SimpleString(sb), T); 982 } 983 if (n == '\n') 984 return thread.setValues(new SimpleString(sb), NIL); 985 else 986 sb.append((char)n); 987 } 988 } 989 990 public LispObject readChar(boolean eofError, LispObject eofValue) 993 throws ConditionThrowable 994 { 995 int n = _readChar(); 996 if (n < 0) { 997 if (eofError) 998 return signal(new EndOfFile(this)); 999 else 1000 return eofValue; 1001 } 1002 return LispCharacter.getInstance((char)n); 1003 } 1004 1005 public LispObject readCharNoHang(boolean eofError, LispObject eofValue) 1008 throws ConditionThrowable 1009 { 1010 return _charReady() ? readChar(eofError, eofValue) : NIL; 1011 } 1012 1013 public LispObject unreadChar(LispCharacter c) throws ConditionThrowable 1015 { 1016 _unreadChar(c.getValue()); 1017 return NIL; 1018 } 1019 1020 public LispObject finishOutput() throws ConditionThrowable 1021 { 1022 _finishOutput(); 1023 return NIL; 1024 } 1025 1026 public LispObject clearInput() throws ConditionThrowable 1028 { 1029 _clearInput(); 1030 return NIL; 1031 } 1032 1033 public LispObject getFilePosition() throws ConditionThrowable 1034 { 1035 long pos = _getFilePosition(); 1036 return pos >= 0 ? number(pos) : NIL; 1037 } 1038 1039 public LispObject setFilePosition(LispObject arg) throws ConditionThrowable 1040 { 1041 return _setFilePosition(arg) ? T : NIL; 1042 } 1043 1044 public LispObject close(LispObject abort) throws ConditionThrowable 1047 { 1048 _close(); 1049 return T; 1050 } 1051 1052 public String toString() 1053 { 1054 return unreadableString("STREAM"); 1055 } 1056 1057 public LispObject readByte(boolean eofError, LispObject eofValue) 1060 throws ConditionThrowable 1061 { 1062 int n = _readByte(); 1063 if (n < 0) { 1064 if (eofError) 1065 return signal(new EndOfFile(this)); 1066 else 1067 return eofValue; 1068 } 1069 return new Fixnum(n); 1070 } 1071 1072 public LispObject terpri() throws ConditionThrowable 1073 { 1074 _writeChar('\n'); 1075 return NIL; 1076 } 1077 1078 public LispObject freshLine() throws ConditionThrowable 1079 { 1080 if (charPos == 0) 1081 return NIL; 1082 _writeChar('\n'); 1083 return T; 1084 } 1085 1086 public void print(char c) throws ConditionThrowable 1087 { 1088 _writeChar(c); 1089 } 1090 1091 public void prin1(LispObject obj) throws ConditionThrowable 1094 { 1095 LispThread thread = LispThread.currentThread(); 1096 Environment oldDynEnv = thread.getDynamicEnvironment(); 1097 thread.bindSpecial(_PRINT_ESCAPE_, T); 1098 String s = obj.writeToString(); 1099 thread.setDynamicEnvironment(oldDynEnv); 1100 _writeString(s); 1101 } 1102 1103 public LispObject listen() throws ConditionThrowable 1104 { 1105 return _charReady() ? T : NIL; 1106 } 1107 1108 public LispObject fileLength() throws ConditionThrowable 1109 { 1110 return signal(new TypeError("Stream is not associated with a file.")); 1111 } 1112 1113 public LispObject fileStringLength(LispObject arg) throws ConditionThrowable 1114 { 1115 if (arg instanceof LispCharacter) 1116 return Fixnum.ONE; 1117 else if (arg instanceof AbstractString) 1118 return number(arg.length()); 1119 else 1120 return signal(new TypeError(String.valueOf(arg) + 1121 " is neither a string nor a character.")); 1122 } 1123 1124 protected int _readChar() throws ConditionThrowable 1126 { 1127 try { 1128 int n = reader.read(); 1129 ++offset; 1130 if (n == '\r') { 1131 if (interactive && Utilities.isPlatformWindows()) 1132 return _readChar(); 1133 } 1134 if (n == '\n') 1135 ++lineNumber; 1136 return n; 1137 } 1138 catch (IOException e) { 1139 signal(new StreamError(this, e)); 1140 return -1; 1142 } 1143 } 1144 1145 protected void _unreadChar(int n) throws ConditionThrowable 1146 { 1147 try { 1148 reader.unread(n); 1149 --offset; 1150 if (n == '\n') 1151 --lineNumber; 1152 } 1153 catch (IOException e) { 1154 signal(new StreamError(this, e)); 1155 } 1156 } 1157 1158 protected boolean _charReady() throws ConditionThrowable 1159 { 1160 try { 1161 return reader.ready(); 1162 } 1163 catch (IOException e) { 1164 signal(new StreamError(this, e)); 1165 return false; 1167 } 1168 } 1169 1170 public void _writeChar(char c) throws ConditionThrowable 1171 { 1172 try { 1173 writer.write(c); 1174 if (c == '\n') { 1175 writer.flush(); 1176 charPos = 0; 1177 } else 1178 ++charPos; 1179 } 1180 catch (IOException e) { 1181 signal(new StreamError(this, e)); 1182 } 1183 } 1184 1185 public void _writeChars(char[] chars, int start, int end) 1186 throws ConditionThrowable 1187 { 1188 try { 1189 writer.write(chars, start, end - start); 1190 int index = -1; 1191 for (int i = end; i-- > start;) { 1192 if (chars[i] == '\n') { 1193 index = i; 1194 break; 1195 } 1196 } 1197 if (index < 0) { 1198 charPos += (end - start); 1200 } else { 1201 charPos = end - (index + 1); 1202 writer.flush(); 1203 } 1204 } 1205 catch (IOException e) { 1206 signal(new StreamError(this, e)); 1207 } 1208 } 1209 1210 public void _writeString(String s) throws ConditionThrowable 1211 { 1212 try { 1213 writer.write(s); 1214 int index = s.lastIndexOf('\n'); 1215 if (index < 0) 1216 charPos += s.length(); 1217 else { 1218 charPos = s.length() - (index + 1); 1219 writer.flush(); 1220 } 1221 } 1222 catch (IOException e) { 1223 signal(new StreamError(this, e)); 1224 } 1225 } 1226 1227 public void _writeLine(String s) throws ConditionThrowable 1228 { 1229 try { 1230 writer.write(s); 1231 writer.write('\n'); 1232 writer.flush(); 1233 charPos = 0; 1234 } 1235 catch (IOException e) { 1236 signal(new StreamError(this, e)); 1237 } 1238 } 1239 1240 public int _readByte() throws ConditionThrowable 1242 { 1243 try { 1244 return in.read(); } 1246 catch (IOException e) { 1247 signal(new StreamError(this, e)); 1248 return -1; 1250 } 1251 } 1252 1253 public void _writeByte(int n) throws ConditionThrowable 1255 { 1256 try { 1257 out.write(n); } 1259 catch (IOException e) { 1260 signal(new StreamError(this, e)); 1261 } 1262 } 1263 1264 public void _finishOutput() throws ConditionThrowable 1265 { 1266 try { 1267 if (writer != null) 1268 writer.flush(); 1269 if (out != null) 1270 out.flush(); 1271 } 1272 catch (IOException e) { 1273 signal(new StreamError(this, e)); 1274 } 1275 } 1276 1277 public void _clearInput() throws ConditionThrowable 1278 { 1279 if (reader != null) { 1280 while (_charReady()) 1281 _readChar(); 1282 } else if (in != null) { 1283 try { 1284 while (in.available() > 0) 1285 in.read(); 1286 } 1287 catch (IOException e) { 1288 signal(new StreamError(this, e)); 1289 } 1290 } 1291 } 1292 1293 protected long _getFilePosition() throws ConditionThrowable 1294 { 1295 return -1; 1296 } 1297 1298 protected boolean _setFilePosition(LispObject arg) throws ConditionThrowable 1299 { 1300 return false; 1301 } 1302 1303 public void _close() throws ConditionThrowable 1304 { 1305 try { 1306 if (reader != null) 1307 reader.close(); 1308 if (in != null) 1309 in.close(); 1310 if (writer != null) 1311 writer.close(); 1312 if (out != null) 1313 out.close(); 1314 setOpen(false); 1315 } 1316 catch (IOException e) { 1317 signal(new StreamError(this, e)); 1318 } 1319 } 1320 1321 public void printStackTrace(Throwable t) throws ConditionThrowable 1322 { 1323 StringWriter sw = new StringWriter (); 1324 PrintWriter pw = new PrintWriter (sw); 1325 t.printStackTrace(pw); 1326 try { 1327 writer.write(sw.toString()); 1328 writer.write('\n'); 1329 writer.flush(); 1330 charPos = 0; 1331 } 1332 catch (IOException e) { 1333 signal(new StreamError(this, e)); 1334 } 1335 } 1336 1337 private static final Primitive FILE_POSITION = 1339 new Primitive("file-position", "stream &optional position-spec") 1340 { 1341 public LispObject execute(LispObject arg) throws ConditionThrowable 1342 { 1343 return checkStream(arg).getFilePosition(); 1344 } 1345 public LispObject execute(LispObject first, LispObject second) 1346 throws ConditionThrowable 1347 { 1348 return checkStream(first).setFilePosition(second); 1349 } 1350 }; 1351 1352 private static final Primitive1 STREAM_LINE_NUMBER = 1354 new Primitive1("stream-line-number", PACKAGE_SYS, false, "stream") 1355 { 1356 public LispObject execute(LispObject arg) throws ConditionThrowable 1357 { 1358 Stream stream = checkStream(arg); 1359 return number(stream.getLineNumber() + 1); 1360 } 1361 }; 1362 1363 private static final Primitive1 STREAM_OFFSET = 1365 new Primitive1("stream-offset", PACKAGE_SYS, false, "stream") 1366 { 1367 public LispObject execute(LispObject arg) throws ConditionThrowable 1368 { 1369 Stream stream = checkStream(arg); 1370 return number(stream.getOffset()); 1371 } 1372 }; 1373} 1374 | Popular Tags |