-- File: ExecIO.mesa
-- edited by Levin, April 27, 1981 4:12 PM.
-- edited by Brotz, June 15, 1982 1:15 PM.
-- edited by Schroeder, January 19, 1981 3:45 PM.

DIRECTORY
Ascii USING [BS, CR, TAB],
dsD: FROM "DisplayDefs" USING [DCBptr, GetCharRightX, PutCharInBitMap,
ScreenXCoord, ScreenYCoord],
Editor USING [MakeCharIndexVisible, RefreshFromFirstChange, shiftedSelectionFlag],
inD: FROM "InteractorDefs" USING [CRWidth, KeyboardInputAcceptor,
keyboardInputAcceptorPtr, leftMargin, LinePtr, MessageTextNbrPtr, realTimeClock,
rightMargin, ScreenXCoord, ScreenYCoord, SetCaretBlinking, StartBlinkingCaret,
StopBlinkingCaret],
Inline USING [BITAND],
intCommon USING [CMRegion, keystream, target, user],
IODefs USING [GetInputStream],
LaurelExecDefs USING [],
LaurelExecImpDefs USING [FlushSourceSelection, GetFromSourceSelection,
InitSourceSelection, ioState, IOState, realKeyStream, RefreshCaret, ShortenTypeScript,
SpliceExecutiveIntoEditor, SpliceExecutiveOutOfEditor, takeFromSecondaryChar],
ovD: FROM "OverviewDefs" USING [CharMask, LineBreakValue],
ProcessDefs USING [DisableTimeout],
StreamDefs USING [StreamError, StreamHandle],
String USING [AppendString, StringBoundsFault],
vmD: FROM "VirtualMgrDefs" USING [AppendMessageChar, ComposedMessage,
ComposedMessagePtr, GetMessageSize, UnAppendMessageChar];

ExecIO: MONITOR LOCKS lock
IMPORTS dsD, Editor, inD, Inline, intC: intCommon, IODefs, LaurelExecImpDefs,
ProcessDefs, StreamDefs, String, vmD
EXPORTS LaurelExecDefs, LaurelExecImpDefs =

BEGIN

OPEN StreamDefs;

cmMnp: PUBLIC inD.MessageTextNbrPtr;

lock: PUBLIC MONITORLOCK;
ioState: PUBLIC LaurelExecImpDefs.IOState;
caretIsOn: BOOLEAN;

realInputAcceptor: inD.KeyboardInputAcceptor;


-- Initialization/Finalization --

InitializeExecIO: PUBLIC ENTRY PROCEDURE =
BEGIN
realKeyStream ← intC.keystream;
realInputAcceptor ← inD.keyboardInputAcceptorPtr↑;
inD.keyboardInputAcceptorPtr↑ ← InputAcceptor;
caretIsOn ← FALSE;
ioState ← originalScreen;
ProcessDefs.DisableTimeout[@charsAvailable];
ProcessDefs.DisableTimeout[@inputAcceptorCanRun];
END; -- of InitializeExecIO --


FinalizeExecIO: PUBLIC ENTRY PROCEDURE =
BEGIN
ks: StreamHandle = IODefs.GetInputStream[];
inD.keyboardInputAcceptorPtr↑ ← realInputAcceptor;
IF ioState = typescriptActive THEN LaurelExecImpDefs.SpliceExecutiveOutOfEditor[];
ks.reset[ks];
ioState ← goingAway;
NOTIFY inputAcceptorCanRun;
END; -- of FinalizeExecIO --


-- Key Stream Implementation Procedures --

charsAvailable, inputAcceptorCanRun: CONDITION;
realKeyStream: PUBLIC StreamHandle;


ResetKS: PUBLIC PROCEDURE[stream: StreamHandle] =
BEGIN
WITH s: stream SELECT FROM
Keyboard =>
BEGIN
realKeyStream.reset[realKeyStream];
LaurelExecImpDefs.FlushSourceSelection[]
END;
ENDCASE => ERROR StreamError[stream, StreamType];
END; -- of ResetKS --


PutBackKS: PUBLIC PROCEDURE[stream: StreamHandle, char: UNSPECIFIED] =
BEGIN
WITH s: stream SELECT FROM
Keyboard => realKeyStream.putback[realKeyStream, char];
ENDCASE => ERROR StreamError[stream, StreamType];
END; -- of PutBackKS --


PutKS: PUBLIC PROCEDURE[stream: StreamHandle, char: UNSPECIFIED] =
BEGIN
ERROR StreamError[stream, StreamAccess];
END; -- of PutKS --


GetKS: PUBLIC ENTRY PROCEDURE [stream: StreamHandle] RETURNS [UNSPECIFIED] =
BEGIN
char: CHARACTER;
WITH s: stream SELECT FROM
Keyboard =>
BEGIN
OPEN LaurelExecImpDefs;
WHILE realKeyStream.endof[realKeyStream] DO
NOTIFY inputAcceptorCanRun;
caretIsOn ← TRUE;
IF ioState ~= originalScreen THEN RefreshCaret[FALSE];
WAIT charsAvailable [ ! UNWIND => NULL ];
ENDLOOP;
char ← realKeyStream.get[realKeyStream ! UNWIND => NULL];
-- assert: char cannot be Editor.shiftedSelectionFlag
IF char = takeFromSecondaryChar AND
(char ← GetFromSourceSelection[]) < ovD.LineBreakValue THEN
realKeyStream.putback[realKeyStream, takeFromSecondaryChar];
inD.StopBlinkingCaret[]; caretIsOn ← FALSE;
END;
ENDCASE => RETURN WITH ERROR StreamError[stream, StreamType];
RETURN[Inline.BITAND[char, ovD.CharMask]]
END; -- of GetKS --



InputAcceptor: PUBLIC ENTRY inD.KeyboardInputAcceptor =
BEGIN
IF char = Editor.shiftedSelectionFlag THEN LaurelExecImpDefs.InitSourceSelection[]
ELSE realKeyStream.putback[realKeyStream, char];
UNTIL realKeyStream.endof[realKeyStream] OR ioState = goingAway DO
NOTIFY charsAvailable;
WAIT inputAcceptorCanRun;
ENDLOOP;
END; -- of InputAcceptor --


EndOfKS: PUBLIC ENTRY PROCEDURE [stream: StreamHandle] RETURNS [BOOLEAN] =
BEGIN
WITH s: stream SELECT FROM
Keyboard => RETURN[realKeyStream.endof[realKeyStream]];
ENDCASE => RETURN WITH ERROR StreamError[stream, StreamType];
END; -- of EndOfKS --


DestroyKS: PUBLIC PROCEDURE[stream: StreamHandle] =
BEGIN
WITH s: stream SELECT FROM
Keyboard => NULL;
ENDCASE => ERROR StreamError[stream, StreamType];
END; -- of DestroyKS --


-- Display Stream Implementation Procedures --


ResetDS: PUBLIC PROCEDURE[stream: StreamHandle] =
BEGIN
ERROR StreamError[stream, StreamType];
END; -- of ResetDS --


GetDS: PUBLIC PROCEDURE[stream: StreamHandle] RETURNS[UNSPECIFIED] =
BEGIN
ERROR StreamError[stream, StreamAccess];
END; -- of GetDS --


PutBackDS: PUBLIC PROCEDURE[stream: StreamHandle, char: UNSPECIFIED] =
BEGIN
ERROR StreamError[stream, StreamAccess];
END; -- of PutBackDS --


PutDS: PUBLIC ENTRY PROCEDURE[stream: StreamHandle, char: UNSPECIFIED] =
BEGIN
IF ioState = originalScreen THEN
{ioState ← typescriptActive; LaurelExecImpDefs.SpliceExecutiveIntoEditor[]};
WITH s: stream SELECT FROM
Display => AppendCharToMessage[Inline.BITAND[char, ovD.CharMask]];
ENDCASE => ERROR StreamError[stream, StreamType ! UNWIND => NULL];
END; -- of PutDS --


EndOfDS: PUBLIC PROCEDURE[stream: StreamHandle] RETURNS[empty: BOOLEAN] =
BEGIN
SIGNAL StreamError[stream, StreamType];
RETURN[FALSE]
END; -- of PutDS --


DestroyDS: PUBLIC PROCEDURE[stream: StreamHandle] =
BEGIN
ERROR StreamError[stream, StreamAccess];
END; -- of DestroyDS --


ClearCurrentLineDS: PUBLIC PROCEDURE[stream: StreamHandle] =
BEGIN
stream.put[stream, ’?];
stream.put[stream, Ascii.CR];
END; -- of ClearCurrentLineDS --


ClearLineDS: PUBLIC PROCEDURE[stream: StreamHandle, line: CARDINAL] =
BEGIN
ERROR StreamError[stream, StreamAccess]; -- this should never be called
END; -- of ClearLineDS --


ClearCharDS: PUBLIC PROCEDURE[stream: StreamHandle, char: CHARACTER] =
BEGIN
AppendCharToMessage[Ascii.BS];
END; -- of ClearCharDS --


caretX: inD.ScreenXCoord;
caretY: inD.ScreenYCoord;


RefreshCaret: PUBLIC -- INTERNAL -- PROCEDURE [knowCaretPosition: BOOLEAN] =
-- inside monitor to protect caretIsOn
BEGIN
IF caretIsOn THEN
BEGIN
IF knowCaretPosition THEN inD.StartBlinkingCaret[caretX, caretY]
ELSE inD.SetCaretBlinking[intC.target.point, cmMnp ! UNWIND => NULL];
END;
END; -- of RefreshCaret --



AppendCharToMessage: PROCEDURE [char: CHARACTER] =
BEGIN
OPEN intC;
composedMessage: vmD.ComposedMessagePtr = vmD.ComposedMessage[cmMnp.message];
line: inD.LinePtr;
knowCaretPosition: BOOLEAN ← FALSE;

inD.StopBlinkingCaret[];
line ← Editor.MakeCharIndexVisible[target.point, cmMnp];
IF char = Ascii.BS THEN
BEGIN
IF target.point = 0 THEN RETURN;
vmD.UnAppendMessageChar[composedMessage];
target.point ← vmD.GetMessageSize[composedMessage];
Editor.RefreshFromFirstChange[target.point, 1, 0, cmMnp];
END
ELSE BEGIN
rightX: dsD.ScreenXCoord;
IF target.point > 60000 THEN LaurelExecImpDefs.ShortenTypeScript[];
[] ← vmD.AppendMessageChar[composedMessage, char];
IF char = Ascii.CR
OR inD.rightMargin - inD.CRWidth >= (rightX ← dsD.GetCharRightX[char, line.rightX])
THEN BEGIN
IF line.state = endOfMessage THEN
BEGIN
line.rightX ← inD.leftMargin;
line.state ← normalText;
IF line.nextLine ~= NIL THEN line.nextLine.state ← endOfMessage;
END;
line.rightX ← IF char = Ascii.TAB
THEN rightX
ELSE dsD.PutCharInBitMap[char, line.rightX, line.y, plainFace];
IF char # Ascii.CR THEN
BEGIN
knowCaretPosition ← TRUE;
caretX ← line.rightX - 3;
caretY ← line.y + 9;
END;
FOR line ← line.nextLine, line.nextLine UNTIL line = NIL DO
line.firstCharIndex ← line.firstCharIndex + 1;
ENDLOOP;
END
ELSE Editor.RefreshFromFirstChange[target.point, 0, 1, cmMnp];
target.point ← vmD.GetMessageSize[composedMessage];
END;
[] ← Editor.MakeCharIndexVisible[target.point, cmMnp]; -- so that caret won’t disappear.
RefreshCaret[knowCaretPosition];
END; -- of AppendCharToMessage --

-- Miscellaneous --

FlashTypescriptRegion: PUBLIC PROCEDURE =
BEGIN
dcb: dsD.DCBptr = intC.CMRegion.dcb;

InvertPause: PROCEDURE = INLINE
BEGIN
startTime: CARDINAL = inD.realTimeClock↑;
UNTIL inD.realTimeClock↑ - startTime >= 8 DO NULL ENDLOOP;
END; -- of InvertPause --

dcb.background ← IF dcb.background = white THEN black ELSE white;
InvertPause[];
dcb.background ← IF dcb.background = white THEN black ELSE white;
END; -- of FlashTypescriptRegion --


GetUserCredentials: PUBLIC PROC [name, password, registry: STRING ← NIL] =
BEGIN
IF name#NIL THEN String.AppendString[name, intC.user.name
! String.StringBoundsFault => CONTINUE ];
IF password#NIL THEN String.AppendString[password, intC.user.password
! String.StringBoundsFault => CONTINUE ];
IF registry#NIL THEN String.AppendString[registry, intC.user.registry
! String.StringBoundsFault => CONTINUE ];
END; --GetUserCredentials--

END. -- of ExecIO --