// ChatDisBSP.BCPL - Bob Sproull - Stuff requiring BSP definitions
// Copyright Xerox Corporation 1979
// modified: April 13, 1979 6:04 PM (E. Taft)
get "Chat.d"
get "ChatBSP.d"
external
[
// outgoing procedures
ChatDIS; AwaitDisplayConnection
// incoming procedures
DisReset; DisClose; DisWs
CheckShiftSwat; BigStack; SmallStack
OpenLevel1Socket; SetAllocation; ReleasePBI
OpenRTPSocket; CreateBSPStream
CallContextList; Block; InitializeContext
SetTimer; TimerHasExpired
Enqueue; Unqueue
Closes
SetBlock
GotoLabel
// incoming statics
TTYStr; TTYSoc; DISStr; DISSoc
disTypeInCtx; disTypeOutCtx; disDisplayCtx; disEventCtx
DisErrStack; DisErr; DisMarkCount; staticErrCode
Running; ChatZone; ConnectionOpen
ctxQ
lvUserFinishProc
]
static [
disSavedUFP
]
//Come here with communications going (TTYSoc, TTYStr ok)
// ChatZone set up
// ScreenBuffer => region for screen +DCB
// ScreenBufferLength = length of both
let ChatDIS() be
[
DisReset()
// Set up the various kinds of error handling (too many!)
TTYStr>>ST.error=DisHandleBSPError
TTYSoc>>BSPSoc.bspOtherPupProc=DisHandlePup
disSavedUFP = @lvUserFinishProc
@lvUserFinishProc=DisHandleFinish
//Now start everything up:
Running=1
[
CallContextList(ctxQ!0)
CheckShiftSwat()
] repeat
]
and AwaitDisplayConnection() be
[
if DISStr then Closes(DISStr)
DISStr=0
let lclPort=vec lenPort
SetBlock(lclPort, 0, lenPort)
lclPort>>Port.socket↑2=#66 //Socket number #66
OpenLevel1Socket(DISSoc, lclPort)
SetAllocation(DISSoc, nDisplayPBI, nDisplayPBI-1, nDisplayPBI-1)
until OpenRTPSocket(DISSoc, ctxQ, modeListenAndWait, 0,0,0, ChatZone)
do loop
DISStr=CreateBSPStream(DISSoc)
DISStr>>ST.error=DisHandleBSPError
DISSoc>>BSPSoc.bspOtherPupProc=DisHandlePup
DisReset()
ConnectionOpen=true
]
// Various error and finishing code.
and DisHandleFinish(code) be
[
@lvUserFinishProc=disSavedUFP
@#420=0 //Let display finish during networking
let tim=nil
SetTimer(lv tim, 3000) // Thirty seconds
if Running then Running=2 //Flag to stop everything
Unqueue(ctxQ, disTypeInCtx)
Unqueue(ctxQ, disTypeOutCtx)
Unqueue(ctxQ, disDisplayCtx)
Unqueue(ctxQ, disEventCtx)
Enqueue(ctxQ, InitializeContext(disEventCtx, 200, DisClose))
until Running eq 0 % TimerHasExpired(lv tim) do
CallContextList(ctxQ!0)
]
// Stream Errors: simply arrange to return a flag value that indicates
// what has happened:
// -1: Mark
// -2: Interrupt (not yet implementable!)
// -3: Grounds for closing connection (bad state)
and DisHandleBSPError(str, ec) = valof
[
staticErrCode=valof [
switchon ec into
[
case ecMarkEncountered:
resultis -1
default: //Bad status -- connection to close
Block() //Give other guy chance to run
resultis -3
]
]
if str eq DISStr then GotoLabel(DisErrStack, DisErr)
resultis staticErrCode
]
//Called when an error, interrupt, or abort pup is received, and handed
// the very pup.
and DisHandlePup(PBI) be
[CPE
if PBI>>PBI.pup.type eq typeError then
[
let C=lv PBI>>PBI.pup.bytes
let sl=PBI>>PBI.pup.length+(-22-24+1) //Text length+1
let fp=C+11
@fp=(sl lshift 8)+#40 //Length,,space
fp=BigStack(fp)
DisWs("*n*l")
DisWs(fp) //Print message if any
DisWs(" [Error PUP]*n*l")
SmallStack()
if C!10 eq 2 then //The only fatal one for now.
[
finish //No point in continuing.
]
]
// Should really check socket, but not easy....
if PBI>>PBI.pup.type eq typeInterrupt then
[
DisMarkCount=DisMarkCount+1 //Grumble.....
]
ReleasePBI(PBI)
]CPE