source: trunk/abcl/src/org/armedbear/lisp/EchoStream.java

Last change on this file was 15692, checked in by Mark Evenson, 12 months ago

Create a proxy Stream class for CLOS streams

Attempts to address <https://github.com/armedbear/abcl/issues/512>.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.7 KB
Line 
1/*
2 * EchoStream.java
3 *
4 * Copyright (C) 2004-2005 Peter Graves
5 * $Id: EchoStream.java 15692 2023-05-14 14:41:52Z mevenson $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38public final class EchoStream extends Stream
39{
40    private final Stream in;
41    private final Stream out;
42
43    private int unreadChar = -1;
44
45    public EchoStream(Stream in, Stream out)
46    {
47        super(Symbol.ECHO_STREAM);
48        this.in = in;
49        this.out = out;
50    }
51
52    public EchoStream(Stream in, Stream out, boolean interactive)
53    {
54        super(Symbol.ECHO_STREAM);
55        this.in = in;
56        this.out = out;
57        setInteractive(interactive);
58    }
59
60    @Override
61    public LispObject getElementType()
62    {
63        LispObject itype = in.getElementType();
64        LispObject otype = out.getElementType();
65        if (itype.equal(otype))
66            return itype;
67        return Symbol.NULL; // FIXME
68    }
69
70    public Stream getInputStream()
71    {
72        return in;
73    }
74
75    public Stream getOutputStream()
76    {
77        return out;
78    }
79
80    @Override
81    public LispObject typeOf()
82    {
83        return Symbol.ECHO_STREAM;
84    }
85
86    @Override
87    public LispObject classOf()
88    {
89        return BuiltInClass.ECHO_STREAM;
90    }
91
92    @Override
93    public LispObject typep(LispObject type)
94    {
95        if (type == Symbol.ECHO_STREAM)
96            return T;
97        if (type == BuiltInClass.ECHO_STREAM)
98            return T;
99        return super.typep(type);
100    }
101
102    @Override
103    public boolean isInputStream()
104    {
105        return true;
106    }
107
108    @Override
109    public boolean isOutputStream()
110    {
111        return true;
112    }
113
114    @Override
115    public boolean isCharacterInputStream()
116    {
117        return in.isCharacterInputStream();
118    }
119
120    @Override
121    public boolean isBinaryInputStream()
122    {
123        return in.isBinaryInputStream();
124    }
125
126    @Override
127    public boolean isCharacterOutputStream()
128    {
129        return out.isCharacterOutputStream();
130    }
131
132    @Override
133    public boolean isBinaryOutputStream()
134    {
135        return out.isBinaryOutputStream();
136    }
137
138    // Returns -1 at end of file.
139    @Override
140    protected int _readChar() throws java.io.IOException
141    {
142        int n = in._readChar();
143        if (n >= 0) {
144            // Not at end of file.
145            if (unreadChar < 0)
146                out._writeChar((char)n);
147            else
148                unreadChar = -1;
149        }
150        return n;
151    }
152
153    @Override
154    protected void _unreadChar(int n) throws java.io.IOException
155    {
156        in._unreadChar(n);
157        unreadChar = n;
158    }
159
160    @Override
161    protected boolean _charReady() throws java.io.IOException
162    {
163        return in._charReady();
164    }
165
166    @Override
167    public void _writeChar(char c)
168    {
169        out._writeChar(c);
170    }
171
172    @Override
173    public void _writeChars(char[] chars, int start, int end)
174
175    {
176        out._writeChars(chars, start, end);
177    }
178
179    @Override
180    public void _writeString(String s)
181    {
182        out._writeString(s);
183    }
184
185    @Override
186    public void _writeLine(String s)
187    {
188        out._writeLine(s);
189    }
190
191    // Reads an 8-bit byte.
192    @Override
193    public int _readByte()
194    {
195        int n = in._readByte();
196        if (n >= 0)
197            out._writeByte(n);
198        return n;
199    }
200
201    // Writes an 8-bit byte.
202    @Override
203    public void _writeByte(int n)
204    {
205        out._writeByte(n);
206    }
207
208    @Override
209    public void _finishOutput()
210    {
211        out._finishOutput();
212    }
213
214    @Override
215    public void _clearInput()
216    {
217        in._clearInput();
218    }
219
220    @Override
221    public LispObject close(LispObject abort)
222    {
223        // "The effect of CLOSE on a constructed stream is to close the
224        // argument stream only. There is no effect on the constituents of
225        // composite streams."
226        setOpen(false);
227        return T;
228    }
229
230    @Override
231    public LispObject listen()
232    {
233        return in.listen();
234    }
235
236    @Override
237    public LispObject freshLine()
238    {
239        return out.freshLine();
240    }
241
242    // ### make-echo-stream
243    // input-stream output-stream => echo-stream
244    private static final Primitive MAKE_ECHO_STREAM =
245        new Primitive("make-echo-stream", "input-stream output-stream")
246    {
247        @Override
248        public LispObject execute(LispObject first, LispObject second)
249
250        {
251            Stream input = checkStream(first);
252            Stream output = checkStream(second);
253            return new EchoStream(input, output);
254        }
255    };
256
257    // ### echo-stream-input-stream
258    // echo-stream => input-stream
259    private static final Primitive ECHO_STREAM_INPUT_STREAM =
260        new Primitive("echo-stream-input-stream", "echo-stream")
261    {
262        @Override
263        public LispObject execute(LispObject arg)
264        {
265            if (arg instanceof EchoStream)
266                return ((EchoStream)arg).getInputStream();
267            return type_error(arg, Symbol.ECHO_STREAM);
268        }
269    };
270
271    // ### echo-stream-output-stream
272    // echo-stream => output-stream
273    private static final Primitive ECHO_STREAM_OUTPUT_STREAM =
274        new Primitive("echo-stream-output-stream", "echo-stream")
275    {
276        @Override
277        public LispObject execute(LispObject arg)
278        {
279            if (arg instanceof EchoStream)
280                return ((EchoStream)arg).getOutputStream();
281            return type_error(arg, Symbol.ECHO_STREAM);
282        }
283    };
284}
Note: See TracBrowser for help on using the repository browser.