DIRECTORY Basics, IO, Rope, Process, UXStrings, SimpleStreams; SimpleStreamsOnBridgeImpl: CEDAR MONITOR LOCKS hh USING hh: REF MyRec IMPORTS IO, Process, Rope, UXStrings, SimpleStreams SHARES SimpleStreams = BEGIN SPPEmu: TYPE = POINTER; --TO SPPEmuRep BridgeConnect: PROC [cmd: UXStrings.CString] RETURNS [SPPEmu] = TRUSTED MACHINE CODE { "XR_BridgeConnect" }; BridgeDisconnect: PROC [sppe: SPPEmu] = TRUSTED MACHINE CODE { "XR_BridgeDisconnect" }; SPPEWrite: PROC [sppe: SPPEmu, buf: POINTER, nBytes: INT, setEM: INT] RETURNS [bytesWritten: INT] = TRUSTED MACHINE CODE { "XR_SPPEWrite" }; SPPERead: PROC [sppe: SPPEmu, buf: POINTER, nWanted: INT] RETURNS [bytesRead: INT] = TRUSTED MACHINE CODE { "XR_SPPERead" }; buffSize: INT = 100; MyRec: TYPE = MONITORED RECORD [ sppe: SPPEmu ¬ NIL, alive: BOOL ¬ TRUE, lastCh: CHAR ¬ 0c, cond: CONDITION, readerOn: BOOL ¬ FALSE, --monitored in, out: INT ¬ 0, buff: PACKED ARRAY [0..buffSize) OF CHAR, connectCmd: UXStrings.CString ]; BCreateSimpleStreams: SimpleStreams.CreateProcType = { hh: REF MyRec ¬ NEW[MyRec]; hh.connectCmd ¬ UXStrings.Create["ERTTY\r foo\r"]; hh.sppe ¬ BridgeConnect[hh.connectCmd]; IF hh.sppe=NIL THEN ERROR; out ¬ IO.CreateStream[outputStreamProcs, hh]; in ¬ IO.CreateStream[inputStreamProcs, hh]; IF ~Rope.IsEmpty[header] THEN {IO.PutRope[out, header]; IO.PutChar[out, '\n]}; }; inputStreamProcs: REF IO.StreamProcs ¬ IO.CreateStreamProcs[ variety: $input, class: $BridgeSimpleStreamsInput, charsAvail: MyCharsAvail, getChar: MyGetChar, close: MyCloseBoth ]; outputStreamProcs: REF IO.StreamProcs ¬ IO.CreateStreamProcs[ variety: $output, class: $BridgeSimpleStreamsOutput, unsafePutBlock: MyUnsafePutBlock, putChar: MyPutChar, eraseChar: MyEraseChar, close: MyCloseBoth ]; MyPutChar: PROC [self: IO.STREAM, char: CHAR] = TRUSTED { IF char#0C THEN { buff: PACKED ARRAY [0..BYTES[WORD]) OF CHAR; hh: REF MyRec = NARROW[self.streamData]; written: INT; buff[0] ¬ char; written ¬ SPPEWrite[hh.sppe, @buff, 1, 1]; IF written#1 THEN { MyCloseBoth[self, FALSE]; ERROR IO.Error[Failure, self]; }; }; }; MyEraseChar: PROC [self: IO.STREAM, char: CHAR] = { MyPutChar[self, '\b]; }; MyUnsafePutBlock: PROC [self: IO.STREAM, block: Basics.UnsafeBlock] = TRUSTED { hh: REF MyRec = NARROW[self.streamData]; WHILE block.count>0 DO written: INT ¬ SPPEWrite[hh.sppe, LOOPHOLE[LOOPHOLE[block.base, CARD]+block.startIndex, POINTER], block.count, 1]; IF written<=0 THEN { MyCloseBoth[self, FALSE]; ERROR IO.Error[Failure, self]; }; block.count ¬ block.count-written; block.startIndex ¬ block.startIndex+written; ENDLOOP; }; ReadBuffer: PROC [hh: REF MyRec] = TRUSTED { MsgBufferFilled: ENTRY UNSAFE PROC [hh: REF MyRec, n: INT] = { ENABLE UNWIND => NULL; IF n>0 THEN { hh.readerOn ¬ FALSE; hh.out ¬ buffSize; --order, so hh.in and hh.out can be compared unmonitored hh.in ¬ n; hh.out ¬ 0; BROADCAST hh.cond }; }; bytesRead: INT; WHILE (bytesRead ¬ SPPERead[hh.sppe, @hh.buff, buffSize])=0 DO Process.Pause[1]; ENDLOOP; IF bytesRead<0 THEN {hh.buff[0] ¬ 4c; bytesRead ¬ 1}; MsgBufferFilled[hh, bytesRead]; }; InternalTickleReader: INTERNAL PROC [hh: REF MyRec] = { IF ~hh.readerOn THEN { hh.readerOn ¬ TRUE; Process.Detach[FORK ReadBuffer[hh]] }; }; MyGetChar: PROC [self: IO.STREAM] RETURNS [ch: CHAR] = { kill: BOOL ¬ FALSE; EntryGetChar: ENTRY PROC [hh: REF MyRec] RETURNS [ch: CHAR] = { ENABLE UNWIND => NULL; IF hh.lastCh=4C THEN {kill¬TRUE; ch ¬ 4c; RETURN}; WHILE hh.out>=hh.in DO InternalTickleReader[hh]; WAIT hh.cond ENDLOOP; IF hh.out>=hh.in THEN ERROR; hh.lastCh ¬ ch ¬ hh.buff[hh.out]; hh.out¬hh.out+1; }; hh: REF MyRec = NARROW[self.streamData]; ch ¬ EntryGetChar[hh]; IF ch='\r THEN ch ¬ '\n; IF kill THEN {MyCloseBoth[self]; ERROR IO.Error[Failure, self]}; }; MyCharsAvail: PROC [self: IO.STREAM, wait: BOOL] RETURNS [n: INT] = { EntryCharsavail: ENTRY PROC [hh: REF MyRec, wait: BOOL] RETURNS [n: INT] = { ENABLE UNWIND => NULL; n ¬ hh.in-hh.out; IF n>0 THEN RETURN; InternalTickleReader[hh]; IF ~wait THEN RETURN [0]; DO n ¬ hh.in-hh.out; IF n>0 THEN RETURN [n]; InternalTickleReader[hh]; WAIT hh.cond ENDLOOP; }; hh: REF MyRec = NARROW[self.streamData]; IF ~hh.alive OR hh.lastCh=4C THEN RETURN [LAST[INT]]; n ¬ EntryCharsavail[hh, wait]; }; MyCloseBoth: PROC [self: IO.STREAM, abort: BOOL ¬ FALSE] = { SetDead: ENTRY PROC [hh: REF MyRec] RETURNS [was: BOOL¬FALSE] = { ENABLE UNWIND => NULL; IF hh#NIL THEN {was ¬ hh.alive; hh.alive ¬ FALSE}; }; hh: REF MyRec = NARROW[self.streamData]; wasAlive: BOOL ¬ SetDead[hh]; IF wasAlive THEN BridgeDisconnect[hh.sppe]; }; SimpleStreams.ImplementCreate[$bridge, BCreateSimpleStreams]; END. " SimpleStreamsOnBridgeImpl.mesa Copyright Σ 1988, 1989, 1992 by Xerox Corporation. All rights reserved. Christian Jacobi, September 2, 1988 2:18:47 pm PDT Christian Jacobi, March 27, 1992 4:46 pm PST --monitors for input only No more necessary... IncludeSPPEmu: PROC = TRUSTED MACHINE CODE { --call this to get the necessary include files. "%=threads/UIO\n=threads/SPPEmu." }; --Connect to Bridge. --The cmd is e.g. "ERTTY\r-h foo\r" --Return XR_SPPEmu or NIL with errno set on failure. --Disconnect Bridge session. --Errors are dealt with silently. --Write to SPPEmulator stream. --Writes nBytes of data from the buffer buf to the descriptor sppe. --If setEM==TRUE, the end of the logical record is set. --If successful the procedure returns the number of bytes --actually written, which will be `nBytes'; on failure it --returns -1 with an error code in errno. --Read from SPPEmulator stream. --Reads up to nWanted bytes of data into the buffer buf, --from the descriptor sppe, returning the number of bytes actually read. --The value of errno is always significant; usually it's 0, but it --may be XR_ESPPENDREC if the end of a logical record was encountered. --May return fewer bytes than requested, but won't return 0 bytes except --at the end of a logical record. --inputBuffer IncludeSPPEmu[]; Κ ‰–(cedarcode) style•NewlineDelimiter ™code™Kšœ Οeœ=™HKšœ2™2K™,K˜—šΟk œ˜ Kšœžœ*˜4K˜—š Οnœžœžœžœžœžœ˜EKšΟc™Kšžœžœ)˜3Kšžœ˜—šžœ˜K˜—Kšœžœžœ ˜&K˜KšŸ™š Ÿ œžœžœžœžœ™,Kš /™/Kšœ!™!K™K™—š Ÿ œžœžœ žœžœžœ˜VJšΠcf™Kš‘#™#Kš‘4™4K˜K˜—K˜š Ÿœžœžœžœžœ˜>K– "ascii" styleš‘™K– "ascii" styleš‘!™!K˜K˜—K˜šŸ œžœžœ žœ žœžœžœžœžœžœ˜zK– "ascii" styleš‘™K– "ascii" styleš‘C™CK– "ascii" styleš‘7™7K– "ascii" styleš‘:™:K– "ascii" styleš‘:™:K– "ascii" styleš‘)™)K˜K˜—K˜šŸœžœžœ žœžœ žœžœžœžœ˜kK– "ascii" styleš‘™K– "ascii" styleš‘8™8K– "ascii" styleš‘H™HK– "ascii" styleš‘C™CK– "ascii" styleš‘F™FK– "ascii" styleš‘I™IK– "ascii" styleš‘!™!Kšœ ˜ K˜—K˜Kšœ žœ˜šœžœžœ˜ Kšœžœ˜Kšœžœžœ˜Kš  ™ Kšœžœ˜Kšœž œ˜Kšœ žœžœ  ˜#Kšœ žœ˜Kšœžœžœžœž˜)K˜Kšœ˜—K˜šŸœ"˜6Kšœžœ žœ˜K˜2K˜'Kšžœ žœžœžœ˜Kšœžœ%˜-Kšœžœ$˜+Kšžœžœžœžœ˜NK˜—K– "cedar" style˜– "cedar" stylešœžœžœžœ˜Kšžœžœžœ˜šžœžœ˜ Kšœžœ˜Kšœ 8˜LK˜ K˜ Kšž œ˜K˜—K˜—Kšœ žœ˜šžœ7ž˜>Kšœ˜Kšžœ˜—Kšžœ žœ"˜5Kšœ˜K˜—K˜šŸœžœžœžœ ˜7šžœžœ˜Kšœžœ˜Kšœžœ˜#K˜—K˜—K˜š Ÿ œžœžœžœžœžœ˜8Kšœžœžœ˜š Ÿ œžœžœžœžœžœ˜?Kšžœžœžœ˜Kšžœžœžœ žœ˜2šžœžœ˜Kšœ˜Kšžœ ˜ Kšžœ˜—Kšžœžœžœ˜K˜2K˜—Kšœžœ žœ˜)K˜Kšžœžœ ˜Kšžœžœžœžœ˜@K˜—K˜šŸ œžœžœžœžœžœžœ˜Eš Ÿœž œžœžœžœžœ˜LKšžœžœžœ˜K˜Kšžœžœžœ˜Kšœ˜Kšžœžœžœ˜šžœ˜K˜Kšžœžœžœ˜Kšœ˜Kšžœ ˜ Kšžœ˜—K˜—Kšœžœ žœ˜)Kš žœ žœžœžœžœžœ˜5K˜K˜—K˜š Ÿ œžœžœžœ žœžœ˜=šŸœžœžœžœžœžœžœ˜AKšžœžœžœ˜Kšžœžœžœžœ˜2Kšœ˜—Kšœžœ žœ˜)Kšœ žœ˜Kšžœ žœ˜+K˜—K˜Kšœ™Kšœ=˜=Kšžœ˜K˜K˜—…—!Η