001: /*
002: * ConcatenatedStream.java
003: *
004: * Copyright (C) 2004 Peter Graves
005: * $Id: ConcatenatedStream.java,v 1.4 2004/06/22 23:07:46 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.lisp;
023:
024: public final class ConcatenatedStream extends Stream {
025: private LispObject streams;
026:
027: private ConcatenatedStream(LispObject streams)
028: throws ConditionThrowable {
029: this .streams = streams;
030: isInputStream = true;
031: }
032:
033: public boolean isCharacterInputStream() throws ConditionThrowable {
034: if (streams == NIL)
035: return true;
036: return ((Stream) streams.car()).isCharacterInputStream();
037: }
038:
039: public boolean isBinaryInputStream() throws ConditionThrowable {
040: if (streams == NIL)
041: return true;
042: return ((Stream) streams.car()).isBinaryInputStream();
043: }
044:
045: public boolean isCharacterOutputStream() throws ConditionThrowable {
046: return false;
047: }
048:
049: public boolean isBinaryOutputStream() throws ConditionThrowable {
050: return false;
051: }
052:
053: public LispObject typeOf() {
054: return Symbol.CONCATENATED_STREAM;
055: }
056:
057: public LispClass classOf() {
058: return BuiltInClass.CONCATENATED_STREAM;
059: }
060:
061: public LispObject typep(LispObject typeSpecifier)
062: throws ConditionThrowable {
063: if (typeSpecifier == Symbol.CONCATENATED_STREAM)
064: return T;
065: if (typeSpecifier == BuiltInClass.CONCATENATED_STREAM)
066: return T;
067: return super .typep(typeSpecifier);
068: }
069:
070: public LispObject getElementType() throws ConditionThrowable {
071: if (streams == NIL)
072: return NIL;
073: return ((Stream) streams.car()).getElementType();
074: }
075:
076: public LispObject readCharNoHang(boolean eofError,
077: LispObject eofValue) throws ConditionThrowable {
078: if (streams == NIL) {
079: if (eofError)
080: return signal(new EndOfFile(this ));
081: else
082: return eofValue;
083: }
084: return _charReady() ? readChar(eofError, eofValue) : NIL;
085: }
086:
087: public LispObject listen() throws ConditionThrowable {
088: if (unreadChar >= 0)
089: return T;
090: if (streams == NIL)
091: return NIL;
092: Stream stream = (Stream) streams.car();
093: LispObject obj = readCharNoHang(false, this );
094: if (obj == this )
095: return NIL;
096: unreadChar = ((LispCharacter) obj).getValue();
097: return T;
098: }
099:
100: private int unreadChar = -1;
101:
102: // Returns -1 at end of file.
103: protected int _readChar() throws ConditionThrowable {
104: int n;
105: if (unreadChar >= 0) {
106: n = unreadChar;
107: unreadChar = -1;
108: return n;
109: }
110: if (streams == NIL)
111: return -1;
112: Stream stream = (Stream) streams.car();
113: n = stream._readChar();
114: if (n >= 0)
115: return n;
116: streams = streams.cdr();
117: return _readChar();
118: }
119:
120: protected void _unreadChar(int n) throws ConditionThrowable {
121: if (unreadChar >= 0)
122: signal(new StreamError(
123: this ,
124: "UNREAD-CHAR was invoked twice consecutively without an intervening call to READ-CHAR."));
125: unreadChar = n;
126: }
127:
128: protected boolean _charReady() throws ConditionThrowable {
129: if (unreadChar >= 0)
130: return true;
131: if (streams == NIL)
132: return false;
133: Stream stream = (Stream) streams.car();
134: if (stream._charReady())
135: return true;
136: LispObject remainingStreams = streams.cdr();
137: while (remainingStreams != NIL) {
138: stream = (Stream) remainingStreams.car();
139: if (stream._charReady())
140: return true;
141: remainingStreams = remainingStreams.cdr();
142: }
143: return false;
144: }
145:
146: public void _writeChar(char c) throws ConditionThrowable {
147: outputStreamError();
148: }
149:
150: public void _writeChars(char[] chars, int start, int end)
151: throws ConditionThrowable {
152: outputStreamError();
153: }
154:
155: public void _writeString(String s) throws ConditionThrowable {
156: outputStreamError();
157: }
158:
159: public void _writeLine(String s) throws ConditionThrowable {
160: outputStreamError();
161: }
162:
163: // Reads an 8-bit byte.
164: public int _readByte() throws ConditionThrowable {
165: if (streams == NIL)
166: return -1;
167: Stream stream = (Stream) streams.car();
168: int n = stream._readByte();
169: if (n >= 0)
170: return n;
171: streams = streams.cdr();
172: return _readByte();
173: }
174:
175: // Writes an 8-bit byte.
176: public void _writeByte(int n) throws ConditionThrowable {
177: outputStreamError();
178: }
179:
180: public void _finishOutput() throws ConditionThrowable {
181: outputStreamError();
182: }
183:
184: public void _clearInput() throws ConditionThrowable {
185: // FIXME
186: }
187:
188: private void outputStreamError() throws ConditionThrowable {
189: signal(new StreamError(this , String.valueOf(this )
190: + " is not an output stream."));
191: }
192:
193: // ### make-concatenated-stream &rest streams => concatenated-stream
194: private static final Primitive MAKE_CONCATENATED_STREAM = new Primitive(
195: "make-concatenated-stream", "&rest streams") {
196: public LispObject execute(LispObject[] args)
197: throws ConditionThrowable {
198: LispObject streams = NIL;
199: for (int i = 0; i < args.length; i++) {
200: if (args[i] instanceof Stream) {
201: Stream stream = (Stream) args[i];
202: if (stream.isInputStream()) {
203: // streams[i] = (Stream) args[i];
204: streams = new Cons(stream, streams);
205: continue;
206: }
207: }
208: signal(new TypeError(String.valueOf(args[i])
209: + " is not an input stream."));
210: }
211: return new ConcatenatedStream(streams.nreverse());
212: }
213: };
214:
215: // ### concatenated-stream-streams concatenated-stream => streams
216: private static final Primitive1 CONCATENATED_STREAM_STREAMS = new Primitive1(
217: "concatenated-stream-streams", "concatenated-stream") {
218: public LispObject execute(LispObject arg)
219: throws ConditionThrowable {
220: try {
221: return ((ConcatenatedStream) arg).streams;
222: } catch (ClassCastException e) {
223: return signal(new TypeError(arg,
224: Symbol.CONCATENATED_STREAM));
225: }
226: }
227: };
228: }
|