# Copyright 2005-2007 Kevin Reid, under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ................ pragma.syntax("0.9") pragma.enable("accumulator") def Range := EIO.getRange() def ALL := EIO.getALL() def InStream :DeepFrozen := def Element := int # XXX should be int8 (0..255) def makeFDInStreamAuthor implements ExitViaHere { to run(lisp) { # XXX reduce the amount of lisp stuff this emaker uses def DeepFrozenStamp := lisp["E.ELIB", "+DEEP-FROZEN-STAMP+"][] def read := lisp["CL", "READ-FROM-STRING"].getFunction() def intern := lisp["CL", "INTERN"].getFunction() def l__quasiParser { to valueMaker(t :String) { return def vm { to substitute(values) { return read(simple__quasiParser.valueMaker(t).substitute(values)) } } } } def fooAddReceiveHandler := lisp["E.STREAMS", "FOO-ADD-RECEIVE-HANDLER"].getFunction() def fooRemoveReceiveHandler := lisp["E.STREAMS", "FOO-REMOVE-RECEIVE-HANDLER"].getFunction() /** Make an InStream that reads from a non-blocking-POSIX-read()-style data source. */ def makeFDInStream implements DeepFrozenStamp { /** 'nameObj' is used for printing the stream. */ to run(nameObj :any, fdRef, bufferLimit :(int >= 1)) { def inStream implements InStream { to __printOn(out :TextWriter) { out.write("<-") out.printSame(nameObj) } to takeAtMost(var maximum :Range) { if (maximum == ALL) { maximum := bufferLimit } if (maximum.isZero()) { return [] } def chunk #trace(`$inStream: adding handler for $maximum`) def inFDHandler := fooAddReceiveHandler(fdRef, def fdReactor() { bind chunk := try { #trace(`$inStream: removing handler for $maximum`) fooRemoveReceiveHandler(inFDHandler) escape error { escape eofExit { fdRef.read(maximum, error, eofExit) } catch _ { #trace(`$inStream: eof from $fdRef`) null } } catch p { Ref.broken(p) } } catch p { #trace(`$inStream: crashed $p`) Ref.broken(p) } }) return chunk } to close() { # XXX handle ENOTSOCK specifically escape ignore { fdRef.shutdown(l`:input`, def shutdownError(error) { trace(`error from shutdown for $inStream: $error`) ignore() }) } } to fail(_) { inStream.close() } } return inStream } } return makeFDInStream } }