1 /* 2 * BroadcastStream.java 3 * 4 * Copyright (C) 2004-2005 Peter Graves 5 * $Id$ 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 34 package org.armedbear.lisp; 35 36 import static org.armedbear.lisp.Lisp.*; 37 38 public final class BroadcastStream extends Stream 39 { 40 final Stream[] streams; 41 BroadcastStream(Stream[] streams)42 BroadcastStream(Stream[] streams) 43 { 44 super(Symbol.BROADCAST_STREAM); 45 this.streams = streams; 46 isOutputStream = true; 47 if (streams.length == 0) { 48 elementType = T; 49 isBinaryStream = true; 50 isCharacterStream = true; 51 } else { 52 elementType = streams[streams.length-1].getElementType(); 53 if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR) 54 isCharacterStream = true; 55 else 56 isBinaryStream = true; 57 } 58 } 59 getStreams()60 public Stream[] getStreams() 61 { 62 return streams; 63 } 64 65 @Override typeOf()66 public LispObject typeOf() 67 { 68 return Symbol.BROADCAST_STREAM; 69 } 70 71 @Override classOf()72 public LispObject classOf() 73 { 74 return BuiltInClass.BROADCAST_STREAM; 75 } 76 77 @Override typep(LispObject typeSpecifier)78 public LispObject typep(LispObject typeSpecifier) 79 { 80 if (typeSpecifier == Symbol.BROADCAST_STREAM) 81 return T; 82 if (typeSpecifier == BuiltInClass.BROADCAST_STREAM) 83 return T; 84 return super.typep(typeSpecifier); 85 } 86 87 @Override listen()88 public LispObject listen() 89 { 90 notSupported(); 91 // Not reached. 92 return NIL; 93 } 94 95 @Override fileLength()96 public LispObject fileLength() 97 { 98 if (streams.length > 0) 99 return streams[streams.length - 1].fileLength(); 100 else 101 return Fixnum.ZERO; 102 } 103 104 @Override fileStringLength(LispObject arg)105 public LispObject fileStringLength(LispObject arg) 106 { 107 if (streams.length > 0) 108 return streams[streams.length - 1].fileStringLength(arg); 109 else 110 return Fixnum.ONE; 111 } 112 113 // Returns -1 at end of file. 114 @Override _readChar()115 protected int _readChar() 116 { 117 notSupported(); 118 // Not reached. 119 return -1; 120 } 121 122 @Override _unreadChar(int n)123 protected void _unreadChar(int n) 124 { 125 notSupported(); 126 } 127 128 @Override _charReady()129 protected boolean _charReady() 130 { 131 notSupported(); 132 // Not reached. 133 return false; 134 } 135 136 @Override _writeChar(char c)137 public void _writeChar(char c) 138 { 139 for (int i = 0; i < streams.length; i++) 140 streams[i]._writeChar(c); 141 } 142 143 @Override _writeChars(char[] chars, int start, int end)144 public void _writeChars(char[] chars, int start, int end) 145 146 { 147 for (int i = 0; i < streams.length; i++) 148 streams[i]._writeChars(chars, start, end); 149 } 150 151 @Override _writeString(String s)152 public void _writeString(String s) 153 { 154 for (int i = 0; i < streams.length; i++) 155 streams[i]._writeString(s); 156 } 157 158 @Override _writeLine(String s)159 public void _writeLine(String s) 160 { 161 for (int i = 0; i < streams.length; i++) 162 streams[i]._writeLine(s); 163 } 164 165 // Reads an 8-bit byte. 166 @Override _readByte()167 public int _readByte() 168 { 169 notSupported(); 170 // Not reached. 171 return -1; 172 } 173 174 // Writes an 8-bit byte. 175 @Override _writeByte(int n)176 public void _writeByte(int n) 177 { 178 for (int i = 0; i < streams.length; i++) 179 streams[i]._writeByte(n); 180 } 181 182 @Override _finishOutput()183 public void _finishOutput() 184 { 185 for (int i = 0; i < streams.length; i++) 186 streams[i]._finishOutput(); 187 } 188 189 @Override _clearInput()190 public void _clearInput() 191 { 192 notSupported(); 193 } 194 195 @Override _getFilePosition()196 protected long _getFilePosition() 197 { 198 if (streams.length == 0) 199 return 0; 200 else 201 return streams[streams.length-1]._getFilePosition(); 202 } 203 204 @Override _setFilePosition(LispObject arg)205 protected boolean _setFilePosition(LispObject arg) 206 { 207 return false; 208 } 209 210 @Override _close()211 public void _close() 212 { 213 setOpen(false); 214 } 215 notSupported()216 private void notSupported() 217 { 218 error(new TypeError("Operation is not supported for streams of type BROADCAST-STREAM.")); 219 } 220 221 @Override printObject()222 public String printObject() 223 { 224 return unreadableString("BROADCAST-STREAM"); 225 } 226 227 // ### make-broadcast-stream &rest streams => broadcast-stream 228 private static final Primitive MAKE_BROADCAST_STREAM = 229 new Primitive("make-broadcast-stream", "&rest streams") 230 { 231 @Override 232 public LispObject execute() 233 { 234 return new BroadcastStream(new Stream[0]); 235 } 236 @Override 237 public LispObject execute(LispObject[] args) 238 { 239 Stream[] streams = new Stream[args.length]; 240 for (int i = 0; i < args.length; i++) { 241 if (args[i] instanceof Stream) { 242 if (((Stream)args[i]).isOutputStream()) { 243 streams[i] = (Stream) args[i]; 244 continue; 245 } else 246 return type_error(args[i], 247 list(Symbol.SATISFIES, Symbol.OUTPUT_STREAM_P)); 248 } else 249 return type_error(args[i], Symbol.STREAM); 250 } 251 // All is well. 252 return new BroadcastStream(streams); 253 } 254 }; 255 256 // ### broadcast-stream-streams broadcast-stream => streams 257 private static final Primitive BROADCAST_STREAM_STREAMS = 258 new Primitive("broadcast-stream-streams", "broadcast-stream") 259 { 260 @Override 261 public LispObject execute(LispObject arg) 262 { 263 if (arg instanceof BroadcastStream) { 264 BroadcastStream stream = (BroadcastStream) arg; 265 Stream[] streams = stream.streams; 266 LispObject result = NIL; 267 for (int i = streams.length; i-- > 0;) 268 result = new Cons(streams[i], result); 269 return result; 270 } 271 return type_error(arg, Symbol.BROADCAST_STREAM); 272 } 273 }; 274 } 275