1 21 22 package org.armedbear.lisp; 23 24 import java.io.File ; 25 import java.io.FileNotFoundException ; 26 import java.io.IOException ; 27 import java.io.RandomAccessFile ; 28 29 public final class FileStream extends Stream 30 { 31 private static final int BUFSIZE = 4096; 32 33 private final RandomAccessFile raf; 34 private final Pathname pathname; 35 private final int bytesPerUnit; 36 private final byte[] outputBuffer; 37 38 private int outputBufferOffset; 39 40 public FileStream(Pathname pathname, String namestring, 41 LispObject elementType, LispObject direction, 42 LispObject ifExists) 43 throws IOException 44 { 45 File file = new File (namestring); 46 String mode = null; 47 if (direction == Keyword.INPUT) { 48 mode = "r"; 49 isInputStream = true; 50 } else if (direction == Keyword.OUTPUT) { 51 mode = "rw"; 52 isOutputStream = true; 53 } else if (direction == Keyword.IO) { 54 mode = "rw"; 55 isInputStream = true; 56 isOutputStream = true; 57 } 58 Debug.assertTrue(mode != null); 59 raf = new RandomAccessFile (file, mode); 60 if (isOutputStream) { 62 if (ifExists == Keyword.OVERWRITE) 63 raf.seek(0); 64 else if (ifExists == Keyword.APPEND) 65 raf.seek(raf.length()); 66 else 67 raf.setLength(0); 68 } 69 this.pathname = pathname; 70 this.elementType = elementType; 71 if (elementType == Symbol.CHARACTER || elementType == Symbol.BASE_CHAR) { 72 isCharacterStream = true; 73 bytesPerUnit = 1; 74 } else { 75 isBinaryStream = true; 76 int width; 77 try { 78 width = Fixnum.getValue(elementType.cadr()); 79 } 80 catch (ConditionThrowable t) { 81 width = 8; 82 } 83 bytesPerUnit = width / 8; 84 } 85 if (isBinaryStream && isOutputStream && !isInputStream && bytesPerUnit == 1) 86 outputBuffer = new byte[BUFSIZE]; 87 else 88 outputBuffer = null; 89 } 90 91 public LispObject typeOf() 92 { 93 return Symbol.FILE_STREAM; 94 } 95 96 public LispClass classOf() 97 { 98 return BuiltInClass.FILE_STREAM; 99 } 100 101 public LispObject typep(LispObject typeSpecifier) throws ConditionThrowable 102 { 103 if (typeSpecifier == Symbol.FILE_STREAM) 104 return T; 105 if (typeSpecifier == BuiltInClass.FILE_STREAM) 106 return T; 107 return super.typep(typeSpecifier); 108 } 109 110 public Pathname getPathname() 111 { 112 return pathname; 113 } 114 115 public LispObject listen() throws ConditionThrowable 116 { 117 try { 118 return raf.getFilePointer() < raf.length() ? T : NIL; 119 } 120 catch (IOException e) { 121 signal(new StreamError(this, e)); 122 return NIL; 124 } 125 } 126 127 public LispObject fileLength() throws ConditionThrowable 128 { 129 final long length; 130 if (isOpen()) { 131 try { 132 length = raf.length(); 133 } 134 catch (IOException e) { 135 signal(new StreamError(this, e)); 136 return NIL; 138 } 139 } else { 140 String namestring = pathname.getNamestring(); 141 if (namestring == null) 142 return signal(new SimpleError("Pathname has no namestring: " + 143 pathname.writeToString())); 144 File file = new File (namestring); 145 length = file.length(); } 147 if (isCharacterStream) 148 return number(length); 149 return number(length / bytesPerUnit); 152 } 153 154 protected int _readChar() throws ConditionThrowable 156 { 157 try { 158 return raf.read(); 159 } 160 catch (IOException e) { 161 signal(new StreamError(this, e)); 162 return -1; 164 } 165 } 166 167 protected void _unreadChar(int n) throws ConditionThrowable 168 { 169 try { 170 long pos = raf.getFilePointer(); 171 if (pos > 0) 172 raf.seek(pos - 1); 173 } 174 catch (IOException e) { 175 signal(new StreamError(this, e)); 176 } 177 } 178 179 protected boolean _charReady() throws ConditionThrowable 180 { 181 return true; 182 } 183 184 public void _writeChar(char c) throws ConditionThrowable 185 { 186 try { 187 raf.write((byte)c); 188 if (c == '\n') 189 charPos = 0; 190 else 191 ++charPos; 192 } 193 catch (IOException e) { 194 signal(new StreamError(this, e)); 195 } 196 } 197 198 public void _writeChars(char[] chars, int start, int end) 199 throws ConditionThrowable 200 { 201 _writeString(new String (chars, start, end - start)); 202 } 203 204 public void _writeString(String s) throws ConditionThrowable 205 { 206 try { 207 raf.writeBytes(s); 208 int index = s.lastIndexOf('\n'); 209 if (index < 0) 210 charPos += s.length(); 211 else 212 charPos = s.length() - (index + 1); 213 } 214 catch (IOException e) { 215 signal(new StreamError(this, e)); 216 } 217 } 218 219 public void _writeLine(String s) throws ConditionThrowable 220 { 221 try { 222 raf.writeBytes(s); 223 raf.write((byte)'\n'); 224 charPos = 0; 225 } 226 catch (IOException e) { 227 signal(new StreamError(this, e)); 228 } 229 } 230 231 public int _readByte() throws ConditionThrowable 233 { 234 try { 235 return raf.read(); } 237 catch (IOException e) { 238 signal(new StreamError(this, e)); 239 return -1; 241 } 242 } 243 244 public void _writeByte(int n) throws ConditionThrowable 246 { 247 if (outputBuffer != null) { 248 writeByteToBuffer((byte)n); 249 } else { 250 try { 251 raf.write((byte)n); } 253 catch (IOException e) { 254 signal(new StreamError(this, e)); 255 } 256 } 257 } 258 259 public void _finishOutput() throws ConditionThrowable 260 { 261 if (outputBuffer != null) 262 flushOutputBuffer(); 263 } 264 265 public void _clearInput() throws ConditionThrowable 266 { 267 try { 268 raf.seek(raf.length()); 269 } 270 catch (IOException e) { 271 signal(new StreamError(this, e)); 272 } 273 } 274 275 protected long _getFilePosition() throws ConditionThrowable 276 { 277 if (outputBuffer != null) 278 flushOutputBuffer(); 279 try { 280 long pos = raf.getFilePointer(); 281 return pos / bytesPerUnit; 282 } 283 catch (IOException e) { 284 signal(new StreamError(this, e)); 285 return -1; 287 } 288 } 289 290 protected boolean _setFilePosition(LispObject arg) throws ConditionThrowable 291 { 292 if (outputBuffer != null) 293 flushOutputBuffer(); 294 try { 295 long pos; 296 if (arg == Keyword.START) 297 pos = 0; 298 else if (arg == Keyword.END) 299 pos = raf.length(); 300 else { 301 long n = Fixnum.getValue(arg); pos = n * bytesPerUnit; 303 } 304 raf.seek(pos); 305 } 306 catch (IOException e) { 307 signal(new StreamError(this, e)); 308 } 309 return true; 310 } 311 312 public void _close() throws ConditionThrowable 313 { 314 if (outputBuffer != null) 315 flushOutputBuffer(); 316 try { 317 raf.close(); 318 setOpen(false); 319 } 320 catch (IOException e) { 321 signal(new StreamError(this, e)); 322 } 323 } 324 325 private void writeByteToBuffer(byte b) throws ConditionThrowable 326 { 327 if (outputBufferOffset == BUFSIZE) 328 flushOutputBuffer(); 329 outputBuffer[outputBufferOffset++] = b; 330 } 331 332 private void flushOutputBuffer() throws ConditionThrowable 333 { 334 if (outputBufferOffset > 0) { 335 try { 336 raf.write(outputBuffer, 0, outputBufferOffset); 337 outputBufferOffset = 0; 338 } 339 catch (IOException e) { 340 signal(new StreamError(this, e)); 341 } 342 } 343 } 344 345 public String toString() 346 { 347 return unreadableString("FILE-STREAM"); 348 } 349 350 private static final Primitive MAKE_FILE_STREAM = 352 new Primitive("make-file-stream", PACKAGE_SYS, false, 353 "pathname element-type direction if-exists") 354 { 355 public LispObject execute(LispObject first, LispObject second, 356 LispObject third, LispObject fourth) 357 throws ConditionThrowable 358 { 359 Pathname pathname = Pathname.coerceToPathname(first); 360 LispObject elementType = second; 361 LispObject direction = third; 362 LispObject ifExists = fourth; 363 if (direction != Keyword.INPUT && direction != Keyword.OUTPUT && 364 direction != Keyword.IO) 365 signal(new LispError("Direction must be :INPUT, :OUTPUT, or :IO.")); 366 String namestring = pathname.getNamestring(); 367 if (namestring == null) 368 return NIL; 369 try { 370 return new FileStream(pathname, namestring, elementType, 371 direction, ifExists); 372 } 373 catch (FileNotFoundException e) { 374 return NIL; 375 } 376 catch (IOException e) { 377 return signal(new StreamError(null, e)); 378 } 379 } 380 }; 381 } 382 | Popular Tags |