[armedbear-cvs] r11434 - in trunk/j: . src/org/armedbear/lisp src/org/armedbear/lisp/util
Erik Huelsmann
ehuelsmann at common-lisp.net
Sun Dec 7 23:24:34 UTC 2008
Author: ehuelsmann
Date: Sun Dec 7 23:24:31 2008
New Revision: 11434
Log:
Merge open-external-format branch back to trunk.
Added:
trunk/j/src/org/armedbear/lisp/util/
- copied from r11432, /branches/open-external-format/src/org/armedbear/lisp/util/
Modified:
trunk/j/build.xml
trunk/j/src/org/armedbear/lisp/FileStream.java
trunk/j/src/org/armedbear/lisp/Stream.java
trunk/j/src/org/armedbear/lisp/StringInputStream.java
trunk/j/src/org/armedbear/lisp/StringOutputStream.java
trunk/j/src/org/armedbear/lisp/open.lisp
trunk/j/src/org/armedbear/lisp/socket.lisp
trunk/j/src/org/armedbear/lisp/socket_stream.java
Modified: trunk/j/build.xml
==============================================================================
--- trunk/j/build.xml (original)
+++ trunk/j/build.xml Sun Dec 7 23:24:31 2008
@@ -100,6 +100,7 @@
<patternset id="abcl.source.java">
<include name="org/armedbear/lisp/*.java"/>
+ <include name="org/armedbear/lisp/util/*.java"/>
<include name="org/armedbear/Main.java"/>
</patternset>
@@ -117,6 +118,7 @@
<patternset id="abcl.objects">
<include name="org/armedbear/lisp/*.class"/>
+ <include name="org/armedbear/lisp/util/*.class"/>
<include name="org/armedbear/lisp/*.cls"/>
<include name="org/armedbear/lisp/*.abcl"/>
<patternset refid="abcl.source.lisp.dist"/>
Modified: trunk/j/src/org/armedbear/lisp/FileStream.java
==============================================================================
--- trunk/j/src/org/armedbear/lisp/FileStream.java (original)
+++ trunk/j/src/org/armedbear/lisp/FileStream.java Sun Dec 7 23:24:31 2008
@@ -2,6 +2,7 @@
* FileStream.java
*
* Copyright (C) 2004-2006 Peter Graves
+ * Copyright (C) 2008 Hideo at Yokohama
* $Id$
*
* This program is free software; you can redistribute it and/or
@@ -34,32 +35,39 @@
package org.armedbear.lisp;
import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
+import org.armedbear.lisp.util.RandomAccessCharacterFile;
public final class FileStream extends Stream
{
- private static final int BUFSIZE = 4096;
-
- private final RandomAccessFile raf;
- private final RandomAccessFile in;
- private final RandomAccessFile out;
+ private final RandomAccessCharacterFile racf;
private final Pathname pathname;
private final int bytesPerUnit;
- private final byte[] inputBuffer;
- private final byte[] outputBuffer;
-
- private long inputBufferFilePosition;
- private int inputBufferOffset;
- private int inputBufferCount;
- private int outputBufferOffset;
public FileStream(Pathname pathname, String namestring,
LispObject elementType, LispObject direction,
- LispObject ifExists)
+ LispObject ifExists, LispObject format)
throws IOException
{
+ /* externalFormat is a LispObject of which the first char is a
+ * name of a character encoding (such as :UTF-8 or :ISO-8859-1), used
+ * by ABCL as a string designator, unless the name is :CODE-PAGE.
+ * A real string is (thus) also allowed.
+ *
+ * Then, a property list follows with 3 possible keys:
+ * :ID (values: code page numbers supported by MS-DOS/IBM-DOS/MS-Windows
+ * :EOL-STYLE (values: :CR / :LF / :CRLF [none means native])
+ * :LITTLE-ENDIAN (values: NIL / T)
+ *
+ * These definitions have been taken from FLEXI-STREAMS:
+ * http://www.weitz.de/flexi-streams/#make-external-format
+ */
final File file = new File(namestring);
String mode = null;
if (direction == Keyword.INPUT) {
@@ -73,10 +81,10 @@
isInputStream = true;
isOutputStream = true;
}
+
Debug.assertTrue(mode != null);
- raf = new RandomAccessFile(file, mode);
- in = isInputStream ? raf : null;
- out = isOutputStream ? raf : null;
+ RandomAccessFile raf = new RandomAccessFile(file, mode);
+
// ifExists is ignored unless we have an output stream.
if (isOutputStream) {
final long length = file.isFile() ? file.length() : 0;
@@ -89,11 +97,23 @@
raf.setLength(0);
}
}
+ setExternalFormat(format);
+
+ // don't touch raf directly after passing it to racf.
+ // the state will become inconsistent if you do that.
+ racf = new RandomAccessCharacterFile(raf, encoding);
+
this.pathname = pathname;
this.elementType = elementType;
if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR) {
isCharacterStream = true;
bytesPerUnit = 1;
+ if (isInputStream) {
+ initAsCharacterInputStream(racf.getReader());
+ }
+ if (isOutputStream) {
+ initAsCharacterOutputStream(racf.getWriter());
+ }
} else {
isBinaryStream = true;
int width;
@@ -104,19 +124,13 @@
width = 8;
}
bytesPerUnit = width / 8;
+ if (isInputStream) {
+ initAsBinaryInputStream(racf.getInputStream());
+ }
+ if (isOutputStream) {
+ initAsBinaryOutputStream(racf.getOutputStream());
+ }
}
- if (isBinaryStream && isInputStream && !isOutputStream && bytesPerUnit == 1)
- inputBuffer = new byte[BUFSIZE];
- else if (isCharacterStream && isInputStream && !isOutputStream)
- inputBuffer = new byte[BUFSIZE];
- else
- inputBuffer = null;
- if (isBinaryStream && isOutputStream && !isInputStream && bytesPerUnit == 1)
- outputBuffer = new byte[BUFSIZE];
- else if (isCharacterStream && isOutputStream && !isInputStream)
- outputBuffer = new byte[BUFSIZE];
- else
- outputBuffer = null;
}
@Override
@@ -147,28 +161,12 @@
}
@Override
- public LispObject listen() throws ConditionThrowable
- {
- try {
- return in.getFilePointer() < in.length() ? T : NIL;
- }
- catch (NullPointerException e) {
- streamNotInputStream();
- }
- catch (IOException e) {
- error(new StreamError(this, e));
- }
- // Not reached.
- return NIL;
- }
-
- @Override
public LispObject fileLength() throws ConditionThrowable
{
final long length;
if (isOpen()) {
try {
- length = raf.length();
+ length = racf.length();
}
catch (IOException e) {
error(new StreamError(this, e));
@@ -191,116 +189,10 @@
}
@Override
- public LispObject readLine(boolean eofError, LispObject eofValue)
- throws ConditionThrowable
- {
- if (inputBuffer != null) {
- final LispThread thread = LispThread.currentThread();
- final FastStringBuffer sb = new FastStringBuffer();
- while (true) {
- int n = _readChar();
- if (n < 0) {
- // End of file.
- if (sb.length() == 0) {
- if (eofError)
- return error(new EndOfFile(this));
- return thread.setValues(eofValue, T);
- }
- return thread.setValues(new SimpleString(sb), T);
- }
- char c = (char) n;
- if (c == '\n')
- return thread.setValues(new SimpleString(sb), NIL);
- else
- sb.append(c);
- }
- } else
- return super.readLine(eofError, eofValue);
- }
-
- // Returns -1 at end of file.
- @Override
- protected int _readChar() throws ConditionThrowable
- {
- try {
- int c = _readByte();
- if (Utilities.isPlatformWindows) {
- if (c == '\r') {
- int c2 = _readByte();
- if (c2 == '\n') {
- ++lineNumber;
- return c2;
- }
- // '\r' was not followed by '\n'
- if (inputBuffer != null && inputBufferOffset > 0) {
- --inputBufferOffset;
- } else {
- clearInputBuffer();
- long pos = in.getFilePointer();
- if (pos > 0)
- in.seek(pos - 1);
- }
- }
- return c;
- }
- if (c == '\n') {
- ++lineNumber;
- return c;
- }
- return c;
- }
- catch (NullPointerException e) {
- streamNotInputStream();
- }
- catch (IOException e) {
- error(new StreamError(this, e));
- }
- // Not reached.
- return -1;
- }
-
- @Override
protected void _unreadChar(int n) throws ConditionThrowable
{
- if (inputBuffer != null && inputBufferOffset > 0) {
- --inputBufferOffset;
- if (n != '\n')
- return;
- --lineNumber;
- if (!Utilities.isPlatformWindows)
- return;
- // Check for preceding '\r'.
- if (inputBufferOffset > 0) {
- if (inputBuffer[--inputBufferOffset] != '\r')
- ++inputBufferOffset;
- return;
- }
- // We can't go back far enough in the buffered input. Reset and
- // fall through...
- ++inputBufferOffset;
- }
try {
- long pos;
- if (inputBuffer != null && inputBufferFilePosition >= 0)
- pos = inputBufferFilePosition + inputBufferOffset;
- else
- pos = in.getFilePointer();
- clearInputBuffer();
- if (pos > 0)
- in.seek(pos - 1);
- if (Utilities.isPlatformWindows && n == '\n') {
- // Check for preceding '\r'.
- pos = in.getFilePointer();
- if (pos > 0) {
- in.seek(pos - 1);
- n = in.read();
- if (n == '\r')
- in.seek(pos - 1);
- }
- }
- }
- catch (NullPointerException e) {
- streamNotInputStream();
+ racf.unreadChar((char)n);
}
catch (IOException e) {
error(new StreamError(this, e));
@@ -314,141 +206,14 @@
}
@Override
- public void _writeChar(char c) throws ConditionThrowable
- {
- if (c == '\n') {
- if (Utilities.isPlatformWindows)
- _writeByte((byte)'\r');
- _writeByte((byte)c);
- charPos = 0;
- } else {
- _writeByte((byte)c);
- ++charPos;
- }
- }
-
- @Override
- public void _writeChars(char[] chars, int start, int end)
- throws ConditionThrowable
- {
- if (Utilities.isPlatformWindows) {
- for (int i = start; i < end; i++) {
- char c = chars[i];
- if (c == '\n') {
- _writeByte((byte)'\r');
- _writeByte((byte)c);
- charPos = 0;
- } else {
- _writeByte((byte)c);
- ++charPos;
- }
- }
- } else {
- // We're not on Windows, so no newline conversion is necessary.
- for (int i = start; i < end; i++) {
- char c = chars[i];
- _writeByte((byte)c);
- if (c == '\n')
- charPos = 0;
- else
- ++charPos;
- }
- }
- }
-
- @Override
- public void _writeString(String s) throws ConditionThrowable
- {
- final int length = s.length();
- if (Utilities.isPlatformWindows) {
- for (int i = 0; i < length; i++) {
- char c = s.charAt(i);
- if (c == '\n') {
- _writeByte((byte)'\r');
- _writeByte((byte)c);
- charPos = 0;
- } else {
- _writeByte((byte)c);
- ++charPos;
- }
- }
- } else {
- // We're not on Windows, so no newline conversion is necessary.
- for (int i = 0; i < length; i++) {
- char c = s.charAt(i);
- _writeByte((byte)c);
- if (c == '\n')
- charPos = 0;
- else
- ++charPos;
- }
- }
- }
-
- @Override
- public void _writeLine(String s) throws ConditionThrowable
- {
- _writeString(s);
- if (Utilities.isPlatformWindows)
- _writeByte((byte)'\r');
- _writeByte((byte)'\n');
- charPos = 0;
- }
-
- // Reads an 8-bit byte.
- @Override
- public int _readByte() throws ConditionThrowable
- {
- if (inputBuffer != null)
- return readByteFromBuffer();
- try {
- return in.read(); // Reads an 8-bit byte.
- }
- catch (NullPointerException e) {
- streamNotInputStream();
- }
- catch (IOException e) {
- error(new StreamError(this, e));
- }
- // Not reached.
- return -1;
- }
-
- // Writes an 8-bit byte.
- @Override
- public void _writeByte(int n) throws ConditionThrowable
- {
- if (outputBuffer != null) {
- writeByteToBuffer((byte)n);
- } else {
- try {
- out.write((byte)n); // Writes an 8-bit byte.
- }
- catch (NullPointerException e) {
- streamNotOutputStream();
- }
- catch (IOException e) {
- error(new StreamError(this, e));
- }
- }
- }
-
- @Override
- public void _finishOutput() throws ConditionThrowable
- {
- if (outputBuffer != null)
- flushOutputBuffer();
- }
-
- @Override
public void _clearInput() throws ConditionThrowable
{
try {
- in.seek(in.length());
- clearInputBuffer();
- }
- catch (NullPointerException e) {
- streamNotInputStream();
+ if (isInputStream) {
+ racf.position(racf.length());
+ } else {
+ streamNotInputStream();
+ }
}
catch (IOException e) {
error(new StreamError(this, e));
@@ -458,14 +223,8 @@
@Override
protected long _getFilePosition() throws ConditionThrowable
{
- if (inputBuffer != null) {
- if (inputBufferFilePosition >= 0)
- return inputBufferFilePosition + inputBufferOffset;
- }
- if (outputBuffer != null)
- flushOutputBuffer();
try {
- long pos = raf.getFilePointer();
+ long pos = racf.position();
return pos / bytesPerUnit;
}
catch (IOException e) {
@@ -478,21 +237,17 @@
@Override
protected boolean _setFilePosition(LispObject arg) throws ConditionThrowable
{
- if (outputBuffer != null)
- flushOutputBuffer();
- if (inputBuffer != null)
- clearInputBuffer();
try {
long pos;
if (arg == Keyword.START)
pos = 0;
else if (arg == Keyword.END)
- pos = raf.length();
+ pos = racf.length();
else {
long n = Fixnum.getValue(arg); // FIXME arg might be a bignum
pos = n * bytesPerUnit;
}
- raf.seek(pos);
+ racf.position(pos);
}
catch (IOException e) {
error(new StreamError(this, e));
@@ -503,10 +258,8 @@
@Override
public void _close() throws ConditionThrowable
{
- if (outputBuffer != null)
- flushOutputBuffer();
try {
- raf.close();
+ racf.close();
setOpen(false);
}
catch (IOException e) {
@@ -514,76 +267,21 @@
}
}
- private int readByteFromBuffer() throws ConditionThrowable
- {
- if (inputBufferOffset >= inputBufferCount) {
- fillInputBuffer();
- if (inputBufferCount < 0)
- return -1;
- }
- return inputBuffer[inputBufferOffset++] & 0xff;
- }
-
- private void fillInputBuffer() throws ConditionThrowable
- {
- try {
- inputBufferFilePosition = in.getFilePointer();
- inputBufferOffset = 0;
- inputBufferCount = in.read(inputBuffer, 0, BUFSIZE);
- }
- catch (NullPointerException e) {
- streamNotInputStream();
- }
- catch (IOException e) {
- error(new StreamError(this, e));
- }
- }
-
- private void clearInputBuffer()
- {
- inputBufferFilePosition = -1;
- inputBufferOffset = 0;
- inputBufferCount = 0;
- }
-
- private void writeByteToBuffer(byte b) throws ConditionThrowable
- {
- if (outputBufferOffset == BUFSIZE)
- flushOutputBuffer();
- outputBuffer[outputBufferOffset++] = b;
- }
-
- private void flushOutputBuffer() throws ConditionThrowable
- {
- if (outputBufferOffset > 0) {
- try {
- out.write(outputBuffer, 0, outputBufferOffset);
- outputBufferOffset = 0;
- }
- catch (NullPointerException e) {
- streamNotOutputStream();
- }
- catch (IOException e) {
- error(new StreamError(this, e));
- }
- }
- }
-
@Override
public String writeToString() throws ConditionThrowable
{
return unreadableString(Symbol.FILE_STREAM);
}
- // ### make-file-stream pathname namestring element-type direction if-exists => stream
+ // ### make-file-stream pathname namestring element-type direction if-exists external-format => stream
private static final Primitive MAKE_FILE_STREAM =
new Primitive("make-file-stream", PACKAGE_SYS, true,
- "pathname namestring element-type direction if-exists")
+ "pathname namestring element-type direction if-exists external-format")
{
@Override
public LispObject execute(LispObject first, LispObject second,
LispObject third, LispObject fourth,
- LispObject fifth)
+ LispObject fifth, LispObject sixth)
throws ConditionThrowable
{
final Pathname pathname;
@@ -603,12 +301,15 @@
LispObject elementType = third;
LispObject direction = fourth;
LispObject ifExists = fifth;
+ LispObject externalFormat = sixth;
+
if (direction != Keyword.INPUT && direction != Keyword.OUTPUT &&
direction != Keyword.IO)
error(new LispError("Direction must be :INPUT, :OUTPUT, or :IO."));
try {
return new FileStream(pathname, namestring.getStringValue(),
- elementType, direction, ifExists);
+ elementType, direction, ifExists,
+ externalFormat);
}
catch (FileNotFoundException e) {
return NIL;
Modified: trunk/j/src/org/armedbear/lisp/Stream.java
==============================================================================
--- trunk/j/src/org/armedbear/lisp/Stream.java (original)
+++ trunk/j/src/org/armedbear/lisp/Stream.java Sun Dec 7 23:24:31 2008
@@ -43,6 +43,7 @@
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.PushbackReader;
+import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigInteger;
@@ -62,11 +63,12 @@
protected boolean isCharacterStream;
protected boolean isBinaryStream;
+ private boolean pastEnd = false;
private boolean interactive;
private boolean open = true;
-
+
// Character input.
- private PushbackReader reader;
+ protected PushbackReader reader;
protected int offset;
protected int lineNumber;
@@ -79,29 +81,63 @@
* required when calling FRESH-LINE
*/
protected int charPos;
-
+
+ public enum EolStyle {
+ RAW,
+ CR,
+ CRLF,
+ LF
+ }
+
+ static final protected Symbol keywordDefault = Packages.internKeyword("DEFAULT");
+
+ static final private Symbol keywordCodePage = Packages.internKeyword("CODE-PAGE");
+ static final private Symbol keywordID = Packages.internKeyword("ID");
+
+ static final private Symbol keywordEolStyle = Packages.internKeyword("EOL-STYLE");
+ static final private Symbol keywordCR = Packages.internKeyword("CR");
+ static final private Symbol keywordLF = Packages.internKeyword("LF");
+ static final private Symbol keywordCRLF = Packages.internKeyword("CRLF");
+ static final private Symbol keywordRAW = Packages.internKeyword("RAW");
+
+ public final static EolStyle platformEolStyle = Utilities.isPlatformWindows ? EolStyle.CRLF : EolStyle.LF;
+
+ protected EolStyle eolStyle = platformEolStyle;
+ protected char eolChar = (eolStyle == EolStyle.CR) ? '\r' : '\n';
+ protected LispObject externalFormat = LispObject.NIL;
+ protected String encoding = null;
+ protected char lastChar = 0;
+
// Binary input.
- private BufferedInputStream in;
+ private InputStream in;
// Binary output.
- private BufferedOutputStream out;
+ private OutputStream out;
protected Stream()
{
}
- // Input stream constructors.
public Stream(InputStream inputStream, LispObject elementType)
+ {
+ this(inputStream, elementType, keywordDefault);
+ }
+
+
+ // Input stream constructors.
+ public Stream(InputStream inputStream, LispObject elementType, LispObject format)
{
this.elementType = elementType;
+ setExternalFormat(format);
if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR)
{
- isCharacterStream = true;
InputStreamReader inputStreamReader;
try
{
inputStreamReader =
- new InputStreamReader(inputStream, "ISO-8859-1");
+ (encoding == null) ?
+ new InputStreamReader(inputStream)
+ : new InputStreamReader(inputStream, encoding);
}
catch (java.io.UnsupportedEncodingException e)
{
@@ -109,16 +145,14 @@
inputStreamReader =
new InputStreamReader(inputStream);
}
- reader = new PushbackReader(new BufferedReader(inputStreamReader),
- 2);
+ initAsCharacterInputStream(new BufferedReader(inputStreamReader));
}
else
{
isBinaryStream = true;
- in = new BufferedInputStream(inputStream);
+ InputStream stream = new BufferedInputStream(inputStream);
+ initAsBinaryInputStream(stream);
}
- isInputStream = true;
- isOutputStream = false;
}
public Stream(InputStream inputStream, LispObject elementType, boolean interactive)
@@ -127,30 +161,37 @@
setInteractive(interactive);
}
- // Output stream constructors.
public Stream(OutputStream outputStream, LispObject elementType)
+ {
+ this(outputStream, elementType, keywordDefault);
+ }
+
+ // Output stream constructors.
+ public Stream(OutputStream outputStream, LispObject elementType, LispObject format)
{
this.elementType = elementType;
+ setExternalFormat(format);
if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR)
{
- isCharacterStream = true;
+ Writer w;
try
{
- writer = new OutputStreamWriter(outputStream, "ISO-8859-1");
+ w = (encoding == null) ?
+ new OutputStreamWriter(outputStream)
+ : new OutputStreamWriter(outputStream, encoding);
}
catch (java.io.UnsupportedEncodingException e)
{
Debug.trace(e);
- writer = new OutputStreamWriter(outputStream);
+ w = new OutputStreamWriter(outputStream);
}
+ initAsCharacterOutputStream(w);
}
else
{
- isBinaryStream = true;
- out = new BufferedOutputStream(outputStream);
+ OutputStream stream = new BufferedOutputStream(outputStream);
+ initAsBinaryOutputStream(stream);
}
- isInputStream = false;
- isOutputStream = true;
}
public Stream(OutputStream outputStream, LispObject elementType,
@@ -160,6 +201,35 @@
setInteractive(interactive);
}
+ protected void initAsCharacterInputStream(Reader reader)
+ {
+ if (! (reader instanceof PushbackReader))
+ this.reader = new PushbackReader(reader, 5);
+ else
+ this.reader = (PushbackReader)reader;
+
+ isInputStream = true;
+ isCharacterStream = true;
+ }
+
+ protected void initAsBinaryInputStream(InputStream in) {
+ this.in = in;
+ isInputStream = true;
+ isBinaryStream = true;
+ }
+
+ protected void initAsCharacterOutputStream(Writer writer) {
+ this.writer = writer;
+ isOutputStream = true;
+ isCharacterStream = true;
+ }
+
+ protected void initAsBinaryOutputStream(OutputStream out) {
+ this.out = out;
+ isOutputStream = true;
+ isBinaryStream = true;
+ }
+
public boolean isInputStream() throws ConditionThrowable
{
return isInputStream;
@@ -200,6 +270,76 @@
interactive = b;
}
+ public LispObject getExternalFormat() {
+ return externalFormat;
+ }
+
+ public String getEncoding() {
+ return encoding;
+ }
+
+ public void setExternalFormat(LispObject format) {
+ if (format == keywordDefault) {
+ encoding = null;
+ eolStyle = platformEolStyle;
+ eolChar = (eolStyle == EolStyle.CR) ? '\r' : '\n';
+ externalFormat = format;
+ return;
+ }
+
+ try {
+ LispObject enc;
+ boolean encIsCp = false;
+
+ if (format instanceof Cons) {
+ // meaning a non-empty list
+ enc = format.car();
+
+ if (enc == keywordCodePage) {
+ encIsCp = true;
+
+ enc = LispObject.getf(format.cdr(), keywordID, null);
+ }
+
+ LispObject eol = LispObject.getf(format.cdr(), keywordEolStyle, keywordRAW);
+ if (eol == keywordCR)
+ eolStyle = EolStyle.CR;
+ else if (eol == keywordLF)
+ eolStyle = EolStyle.LF;
+ else if (eol == keywordCRLF)
+ eolStyle = EolStyle.CRLF;
+ else if (eol != keywordRAW)
+ //###FIXME: raise an error
+ ;
+
+ } else
+ enc = format;
+
+ if (enc.numberp())
+ encoding = enc.toString();
+ else if (enc instanceof AbstractString)
+ encoding = enc.getStringValue();
+ else if (enc == keywordDefault)
+ // This allows the user to use the encoding determined by
+ // Java to be the default for the current environment
+ // while still being able to set other stream options
+ // (e.g. :EOL-STYLE)
+ encoding = null;
+ else if (enc instanceof Symbol)
+ encoding = ((Symbol)enc).getName();
+ else
+ //###FIXME: raise an error!
+ ;
+
+ if (encIsCp)
+ encoding = "Cp" + encoding;
+ }
+ catch (ConditionThrowable ct) { }
+
+ eolChar = (eolStyle == EolStyle.CR) ? '\r' : '\n';
+ externalFormat = format;
+ }
+
public boolean isOpen()
{
return open;
@@ -1603,7 +1743,19 @@
public LispObject listen() throws ConditionThrowable
{
- return _charReady() ? T : NIL;
+ if (pastEnd)
+ return NIL;
+
+ if (! _charReady())
+ return NIL;
+
+ int n = _readChar();
+ if (n < 0)
+ return NIL;
+
+ _unreadChar(n);
+
+ return T;
}
public LispObject fileLength() throws ConditionThrowable
@@ -1651,17 +1803,32 @@
*/
protected int _readChar() throws ConditionThrowable
{
+ if (pastEnd)
+ return -1;
+
try
{
int n = reader.read();
+
+ if (n < 0) {
+ pastEnd = true;
+ return -1;
+ }
+
++offset;
- if (n == '\r')
- {
- if (interactive && Utilities.isPlatformWindows)
- return _readChar();
- }
- if (n == '\n')
+ if (eolStyle == EolStyle.CRLF && n == '\r') {
+ n = _readChar();
+ if (n != '\n') {
+ _unreadChar(n);
+ return '\r';
+ }
+ }
+
+ if (n == eolChar) {
++lineNumber;
+ return '\n';
+ }
+
return n;
}
catch (NullPointerException e)
@@ -1688,7 +1855,8 @@
{
reader.unread(n);
--offset;
- if (n == '\n')
+ pastEnd = false;
+ if (n == eolChar)
--lineNumber;
}
catch (NullPointerException e)
@@ -1736,14 +1904,19 @@
{
try
{
- writer.write(c);
- if (c == '\n')
- {
- writer.flush();
- charPos = 0;
- }
- else
+ if (c == '\n') {
+ if (eolStyle == EolStyle.CRLF && lastChar != '\r')
+ writer.write('\r');
+
+ writer.write(eolChar);
+ lastChar = eolChar;
+ writer.flush();
+ charPos = 0;
+ } else {
+ writer.write(c);
+ lastChar = c;
++charPos;
+ }
}
catch (NullPointerException e)
{
@@ -1769,7 +1942,18 @@
{
try
{
+ if (eolStyle != EolStyle.RAW) {
+ for (int i = start; i < end; i++)
+ //###FIXME: the number of writes can be greatly reduced by
+ // writing the space between newlines as chunks.
+ _writeChar(chars[i]);
+ return;
+ }
+
writer.write(chars, start, end - start);
+ if (start < end)
+ lastChar = chars[end-1];
+
int index = -1;
for (int i = end; i-- > start;)
{
@@ -1777,19 +1961,19 @@
{
index = i;
break;
- }
- }
+ }
+ }
if (index < 0)
{
// No newline.
charPos += (end - start);
- }
+ }
else
{
charPos = end - (index + 1);
- writer.flush();
- }
- }
+ writer.flush();
+ }
+ }
catch (NullPointerException e)
{
if (writer == null)
@@ -1813,15 +1997,7 @@
{
try
{
- writer.write(s);
- int index = s.lastIndexOf('\n');
- if (index < 0)
- charPos += s.length();
- else
- {
- charPos = s.length() - (index + 1);
- writer.flush();
- }
+ _writeChars(s.toCharArray(), 0, s.length());
}
catch (NullPointerException e)
{
@@ -1830,10 +2006,6 @@
else
throw e;
}
- catch (IOException e)
- {
- error(new StreamError(this, e));
- }
}
/** Writes a string to the underlying stream, appending
@@ -1846,20 +2018,14 @@
{
try
{
- writer.write(s);
- writer.write('\n');
- writer.flush();
- charPos = 0;
+ _writeString(s);
+ _writeChar('\n');
}
catch (NullPointerException e)
{
// writer is null
streamNotCharacterOutputStream();
}
- catch (IOException e)
- {
- error(new StreamError(this, e));
- }
}
// Reads an 8-bit byte.
@@ -1872,7 +2038,11 @@
{
try
{
- return in.read(); // Reads an 8-bit byte.
+ int n = in.read();
+ if (n < 0)
+ pastEnd = true;
+
+ return n; // Reads an 8-bit byte.
}
catch (IOException e)
{
@@ -1933,15 +2103,20 @@
{
if (reader != null)
{
- while (_charReady())
- _readChar();
+ int c = 0;
+ while (_charReady() && (c >= 0))
+ c = _readChar();
}
else if (in != null)
{
try
{
+ int n = 0;
while (in.available() > 0)
- in.read();
+ n = in.read();
+
+ if (n < 0)
+ pastEnd = true;
}
catch (IOException e)
{
@@ -2006,6 +2181,7 @@
{
writer.write(sw.toString());
writer.write('\n');
+ lastChar = '\n';
writer.flush();
charPos = 0;
}
Modified: trunk/j/src/org/armedbear/lisp/StringInputStream.java
==============================================================================
--- trunk/j/src/org/armedbear/lisp/StringInputStream.java (original)
+++ trunk/j/src/org/armedbear/lisp/StringInputStream.java Sun Dec 7 23:24:31 2008
@@ -33,12 +33,13 @@
package org.armedbear.lisp;
+import java.io.StringReader;
+
public final class StringInputStream extends Stream
{
- final String s;
- final int start;
- final int end;
-
+ private final StringReader stringReader;
+ private final int start;
+
public StringInputStream(String s)
{
this(s, 0, s.length());
@@ -52,26 +53,28 @@
public StringInputStream(String s, int start, int end)
{
elementType = Symbol.CHARACTER;
- isInputStream = true;
- isOutputStream = false;
- isCharacterStream = true;
- isBinaryStream = false;
- this.s = s;
+ setExternalFormat(keywordDefault);
+ eolStyle = EolStyle.RAW;
+
this.start = start;
- this.end = end;
- offset = start;
+
+ stringReader = new StringReader(s.substring(start, end));
+ initAsCharacterInputStream(stringReader);
}
+ @Override
public LispObject typeOf()
{
return Symbol.STRING_INPUT_STREAM;
}
+ @Override
public LispObject classOf()
{
return BuiltInClass.STRING_INPUT_STREAM;
}
+ @Override
public LispObject typep(LispObject type) throws ConditionThrowable
{
if (type == Symbol.STRING_INPUT_STREAM)
@@ -85,57 +88,29 @@
return super.typep(type);
}
- public LispObject close(LispObject abort) throws ConditionThrowable
- {
- setOpen(false);
- return T;
- }
-
- public LispObject listen()
- {
- return offset < end ? T : NIL;
- }
-
- protected int _readChar()
- {
- if (offset >= end)
- return -1;
- int n = s.charAt(offset);
- ++offset;
- if (n == '\n')
- ++lineNumber;
- return n;
- }
-
- protected void _unreadChar(int n)
- {
- if (offset > start) {
- --offset;
- if (n == '\n')
- --lineNumber;
- }
- }
-
- protected boolean _charReady()
- {
- return true;
- }
-
+ @Override
public String toString()
{
return unreadableString("STRING-INPUT-STREAM");
}
+ @Override
+ public int getOffset() {
+ return start + super.getOffset();
+ }
+
// ### make-string-input-stream
// make-string-input-stream string &optional start end => string-stream
private static final Primitive MAKE_STRING_INPUT_STREAM =
new Primitive("make-string-input-stream", "string &optional start end")
{
+ @Override
public LispObject execute(LispObject arg) throws ConditionThrowable
{
return new StringInputStream(arg.getStringValue());
}
+ @Override
public LispObject execute(LispObject first, LispObject second)
throws ConditionThrowable
{
@@ -144,6 +119,7 @@
return new StringInputStream(s, start);
}
+ @Override
public LispObject execute(LispObject first, LispObject second,
LispObject third)
throws ConditionThrowable
@@ -161,6 +137,7 @@
private static final Primitive STRING_INPUT_STREAM_CURRENT =
new Primitive("string-input-stream-current", PACKAGE_EXT, true, "stream")
{
+ @Override
public LispObject execute(LispObject arg) throws ConditionThrowable
{
if (arg instanceof StringInputStream)
Modified: trunk/j/src/org/armedbear/lisp/StringOutputStream.java
==============================================================================
--- trunk/j/src/org/armedbear/lisp/StringOutputStream.java (original)
+++ trunk/j/src/org/armedbear/lisp/StringOutputStream.java Sun Dec 7 23:24:31 2008
@@ -47,23 +47,23 @@
private StringOutputStream(LispObject elementType)
{
this.elementType = elementType;
- isInputStream = false;
- isOutputStream = true;
- isCharacterStream = true;
- isBinaryStream = false;
- setWriter(stringWriter = new StringWriter());
+ this.eolStyle = EolStyle.RAW;
+ initAsCharacterOutputStream(stringWriter = new StringWriter());
}
+ @Override
public LispObject typeOf()
{
return Symbol.STRING_OUTPUT_STREAM;
}
+ @Override
public LispObject classOf()
{
return BuiltInClass.STRING_OUTPUT_STREAM;
}
+ @Override
public LispObject typep(LispObject type) throws ConditionThrowable
{
if (type == Symbol.STRING_OUTPUT_STREAM)
@@ -77,45 +77,12 @@
return super.typep(type);
}
- public void _writeChar(char c) throws ConditionThrowable
- {
- if (elementType == NIL)
- writeError();
- super._writeChar(c);
- }
-
- public void _writeChars(char[] chars, int start, int end)
- throws ConditionThrowable
- {
- if (elementType == NIL)
- writeError();
- super._writeChars(chars, start, end);
- }
-
- public void _writeString(String s) throws ConditionThrowable
- {
- if (elementType == NIL)
- writeError();
- super._writeString(s);
- }
-
- public void _writeLine(String s) throws ConditionThrowable
- {
- if (elementType == NIL)
- writeError();
- super._writeLine(s);
- }
-
- private void writeError() throws ConditionThrowable
- {
- error(new TypeError("Attempt to write to a string output stream of element type NIL."));
- }
-
+ @Override
protected long _getFilePosition() throws ConditionThrowable
{
if (elementType == NIL)
return 0;
- return stringWriter.toString().length();
+ return stringWriter.getBuffer().length();
}
public LispObject getString() throws ConditionThrowable
@@ -128,6 +95,7 @@
return s;
}
+ @Override
public String toString()
{
return unreadableString("STRING-OUTPUT-STREAM");
@@ -139,6 +107,7 @@
new Primitive("%make-string-output-stream", PACKAGE_SYS, false,
"element-type")
{
+ @Override
public LispObject execute(LispObject arg) throws ConditionThrowable
{
return new StringOutputStream(arg);
@@ -150,6 +119,7 @@
private static final Primitive GET_OUTPUT_STREAM_STRING =
new Primitive("get-output-stream-string", "string-output-stream")
{
+ @Override
public LispObject execute(LispObject arg) throws ConditionThrowable
{
try {
Modified: trunk/j/src/org/armedbear/lisp/open.lisp
==============================================================================
--- trunk/j/src/org/armedbear/lisp/open.lisp (original)
+++ trunk/j/src/org/armedbear/lisp/open.lisp Sun Dec 7 23:24:31 2008
@@ -106,7 +106,7 @@
(if-exists nil if-exists-given)
(if-does-not-exist nil if-does-not-exist-given)
(external-format :default))
- (declare (ignore external-format)) ; FIXME
+; (declare (ignore external-format)) ; FIXME
(setf element-type (case element-type
((character base-char)
'character)
@@ -143,7 +143,7 @@
:pathname pathname
:format-control "The file ~S does not exist."
:format-arguments (list namestring)))))
- (make-file-stream pathname namestring element-type :input nil))
+ (make-file-stream pathname namestring element-type :input nil external-format))
(:probe
(case if-does-not-exist
(:error
@@ -157,7 +157,8 @@
;; this abstract pathname if and only if a file with this name does
;; not yet exist." See java.io.File.createNewFile().
(create-new-file namestring)))
- (let ((stream (make-file-stream pathname namestring element-type :input nil)))
+ (let ((stream (make-file-stream pathname namestring element-type
+ :input nil external-format)))
(when stream
(close stream))
stream))
@@ -204,7 +205,8 @@
(error 'simple-error
:format-control "Option not supported: ~S."
:format-arguments (list if-exists))))
- (let ((stream (make-file-stream pathname namestring element-type direction if-exists)))
+ (let ((stream (make-file-stream pathname namestring element-type
+ direction if-exists external-format)))
(unless stream
(error 'file-error
:pathname pathname
Modified: trunk/j/src/org/armedbear/lisp/socket.lisp
==============================================================================
--- trunk/j/src/org/armedbear/lisp/socket.lisp (original)
+++ trunk/j/src/org/armedbear/lisp/socket.lisp Sun Dec 7 23:24:31 2008
@@ -31,15 +31,16 @@
(in-package "SYSTEM")
-(defun get-socket-stream (socket &key (element-type 'character))
- ":ELEMENT-TYPE must be CHARACTER or (UNSIGNED-BYTE 8); the default is CHARACTER."
+(defun get-socket-stream (socket &key (element-type 'character) (external-format :default))
+ ":ELEMENT-TYPE must be CHARACTER or (UNSIGNED-BYTE 8); the default is CHARACTER.
+EXTERNAL-FORMAT must be of the same format as specified for OPEN."
(cond ((eq element-type 'character))
((equal element-type '(unsigned-byte 8)))
(t
(error 'simple-type-error
:format-control
":ELEMENT-TYPE must be CHARACTER or (UNSIGNED-BYTE 8).")))
- (%socket-stream socket element-type))
+ (%socket-stream socket element-type external-format))
(defun make-socket (host port)
(%make-socket host port))
Modified: trunk/j/src/org/armedbear/lisp/socket_stream.java
==============================================================================
--- trunk/j/src/org/armedbear/lisp/socket_stream.java (original)
+++ trunk/j/src/org/armedbear/lisp/socket_stream.java Sun Dec 7 23:24:31 2008
@@ -40,19 +40,19 @@
{
private socket_stream()
{
- super("%socket-stream", PACKAGE_SYS, false, "socket element-type");
+ super("%socket-stream", PACKAGE_SYS, false, "socket element-type external-format");
}
- public LispObject execute(LispObject first, LispObject second)
+ public LispObject execute(LispObject first, LispObject second, LispObject third)
throws ConditionThrowable
{
Socket socket = (Socket) ((JavaObject)first).getObject();
LispObject elementType = second; // Checked by caller.
try {
Stream in =
- new Stream(socket.getInputStream(), elementType);
+ new Stream(socket.getInputStream(), elementType, third);
Stream out =
- new Stream(socket.getOutputStream(), elementType);
+ new Stream(socket.getOutputStream(), elementType, third);
return new SocketStream(socket, in, out);
}
catch (Exception e) {
More information about the armedbear-cvs
mailing list