-- ExecStreamIO.Mesa
-- Edited by Sandman on July 1, 1980 8:33 AM
-- Edited by Brotz on June 15, 1982 1:34 PM
-- Edited by Levin on January 20, 1981 5:05 PM

DIRECTORY
Editor USING [MakeCharIndexVisible, RefreshFromFirstChange],
inD: FROM "InteractorDefs" USING [CharIndex, StopBlinkingCaret],
intCommon USING [target],
IODefs USING [BS, ControlA, ControlH, ControlQ, ControlR, ControlV, ControlW,
ControlX, CR, DEL, ESC, LF, NumberFormat, SP],
LaurelExecImpDefs USING [cmMnp, ioState, lock, RefreshCaret, ShortenTypeScript,
SpliceExecutiveIntoEditor],
StreamDefs USING [GetDefaultDisplayStream, GetDefaultKey, StreamError, StreamHandle],
String USING [AppendChar, AppendNumber, StringToNumber, SubString,
SubStringDescriptor],
vmD: FROM "VirtualMgrDefs" USING [CharIndex, ComposedMessage,
ComposedMessagePtr, InsertSubstringInMessage, StartMessageInsertion,
StopMessageInsertion, UnAppendMessageChar];

ExecStreamIO: MONITOR LOCKS LaurelExecImpDefs.lock
IMPORTS Editor, inD, intC: intCommon, LaurelExecImpDefs, StreamDefs, String, vmD
EXPORTS IODefs
SHARES IODefs, StreamDefs = PUBLIC

BEGIN OPEN StreamDefs, IODefs, String;

in, out: StreamHandle;
beginLine, echo: PRIVATE BOOLEAN ← TRUE;

GetInputStream: PROCEDURE RETURNS [StreamHandle] = BEGIN RETURN[in] END;

GetOutputStream: PROCEDURE RETURNS [StreamHandle] = BEGIN RETURN[out] END;

SetInputStream: PROCEDURE [s: StreamHandle] = BEGIN in ← s END;

SetOutputStream: PROCEDURE [s: StreamHandle] =
BEGIN out ← s; beginLine ← TRUE; END;

SetEcho: PROCEDURE [new: BOOLEAN] RETURNS [old: BOOLEAN] =
BEGIN old ← echo; echo ← new END;

-- Character operations


ReadChar: PROCEDURE RETURNS [CHARACTER] = BEGIN RETURN[in.get[in]]; END;

WriteChar: PROCEDURE [c: CHARACTER] =
BEGIN out.put[out, c]; beginLine ← c = CR; END;

-- Reading Strings


ReadString: PROCEDURE [s: STRING, t: PROCEDURE [CHARACTER] RETURNS [BOOLEAN]] =
BEGIN WriteChar[ReadEditedString[s, t, TRUE]]; END;

ReadID: PROCEDURE [s: STRING] =
BEGIN [] ← ReadEditedString[s, IsAtom, TRUE]; END;

ReadLine: PROCEDURE [s: STRING] =
BEGIN [] ← ReadEditedString[s, IsCR, TRUE]; WriteChar[CR]; END;

IsCR: PRIVATE PROCEDURE [c: CHARACTER] RETURNS [BOOLEAN] =
BEGIN RETURN[c = CR] END;

IsAtom: PRIVATE PROCEDURE [c: CHARACTER] RETURNS [BOOLEAN] =
BEGIN RETURN[IF c = SP OR c = CR THEN TRUE ELSE FALSE] END;

Rubout: SIGNAL = CODE;
LineOverflow: SIGNAL [s: STRING] RETURNS [ns: STRING] = CODE;

ReadEditedString: PROCEDURE [
s: STRING, t: PROCEDURE [CHARACTER] RETURNS [BOOLEAN], newstring: BOOLEAN]
RETURNS [CHARACTER] =
BEGIN
c: CHARACTER;
i: CARDINAL;
state: {ti, v, li};
c ← in.get[in];
IF newstring THEN
IF c = ESC THEN BEGIN WriteString[s]; c ← in.get[in]; END ELSE s.length ← 0;
UNTIL t[c] DO
SELECT c FROM
DEL => SIGNAL Rubout;
ControlA, ControlH =>
BEGIN
IF s.length > 0 THEN
BEGIN
IF echo THEN
WITH out SELECT FROM
Display => clearChar[out, s[s.length - 1]];
ENDCASE => out.put[out, c];
s.length ← s.length - 1;
END;
END;
ControlW, ControlQ =>
BEGIN -- text to be backed up is of the form
-- ...<li><v><ti>; the <v> and <ti> are to be removed.
state ← ti;
FOR i DECREASING IN [0..s.length) DO
SELECT s[
i] FROM
IN [’A..’Z], IN [’a..’z], IN [’0..’9] =>
IF state = ti THEN state ← v;
ENDCASE => IF state = v THEN state ← li;
IF state = li THEN GO TO Done;
IF echo THEN
WITH out SELECT FROM
Display => clearChar[out, s[i]];
ENDCASE => out.put[out, ControlA];
REPEAT Done => s.length ← i + 1; FINISHED => s.length ← 0;
ENDLOOP;
END;
ControlR => IF echo THEN BEGIN WriteChar[CR]; WriteString[s]; END;
ControlX =>
BEGIN
IF echo THEN
WITH out SELECT FROM
Display => clearCurrentLine[out];
ENDCASE => out.put[out, c];
s.length ← 0;
END;
ControlV =>
BEGIN
WHILE s.length >= s.maxlength DO s ← SIGNAL LineOverflow[s]; ENDLOOP;
s[s.length] ← c ← in.get[in];
s.length ← s.length + 1;
IF echo THEN WriteChar[c];
END;
ENDCASE =>
BEGIN
WHILE s.length >= s.maxlength DO s ← SIGNAL LineOverflow[s]; ENDLOOP;
s[s.length] ← c;
s.length ← s.length + 1;
IF echo THEN WriteChar[c];
END;
c ← in.get[in];
ENDLOOP;
RETURN[c];
END;

-- Writing Strings


WriteString: PROCEDURE [s: STRING] =
BEGIN
ssd: String.SubStringDescriptor ← [base: s, offset: 0, length: s.length];
WriteSubString[@ssd];
END; -- of WriteString --

WriteSubString: ENTRY PROCEDURE [s: String.SubString] =
BEGIN
OPEN LaurelExecImpDefs;
start: vmD.CharIndex;
resumeScan: CARDINAL ← s.offset;
ssEnd: CARDINAL = s.offset + s.length;
runLength: CARDINAL;
cm: vmD.ComposedMessagePtr;

WITH s: out SELECT FROM
Display => NULL;
ENDCASE => ERROR StreamDefs.StreamError[out, StreamType ! UNWIND => NULL];
IF ioState = originalScreen THEN {ioState ← typescriptActive; SpliceExecutiveIntoEditor[]};
start ← intC.target.point;
cm ← vmD.ComposedMessage[cmMnp.message];
inD.StopBlinkingCaret[];
[] ← Editor.MakeCharIndexVisible[start, cmMnp];
IF start > 60000 THEN {LaurelExecImpDefs.ShortenTypeScript[]; start ← intC.target.point};
UNTIL resumeScan >= ssEnd DO
startInSS: CARDINAL ← resumeScan;
FOR i: CARDINAL IN [startInSS .. ssEnd) DO
SELECT s.base[i] FROM
LF => {runLength ← i - startInSS; resumeScan ← i + 1; EXIT};
CR => {runLength ← i - startInSS + 1; resumeScan ← i + 1; EXIT};
BS => BEGIN
runLength ← i - startInSS;
IF runLength > 0 THEN resumeScan ← i
ELSE BEGIN
resumeScan ← i + 1;
start ← start - 1;
vmD.UnAppendMessageChar[cm];
Editor.RefreshFromFirstChange[start, 1, 0, cmMnp];
[] ← Editor.MakeCharIndexVisible[start, cmMnp];
END;
EXIT;
END;
ENDCASE;
REPEAT
FINISHED => {runLength ← ssEnd - startInSS; resumeScan ← ssEnd};
ENDLOOP;
IF runLength = 0 THEN LOOP;
vmD.StartMessageInsertion[cm, start];
[] ← vmD.InsertSubstringInMessage[cm, s.base, startInSS, runLength];
vmD.StopMessageInsertion[cm];
Editor.RefreshFromFirstChange[start, 0, runLength, cmMnp];
start ← start + runLength;
[] ← Editor.MakeCharIndexVisible[start, cmMnp];
ENDLOOP;
intC.target.point ← start;
LaurelExecImpDefs.RefreshCaret[FALSE];
IF s.length ~= 0 THEN beginLine ← s.base[s.offset + s.length - 1] = CR;
END; -- of WriteSubString --

WriteLine: PROCEDURE [s: STRING] = BEGIN WriteString[s]; WriteChar[CR]; END;

NewLine: PROCEDURE RETURNS [BOOLEAN] = BEGIN RETURN[beginLine] END;

-- Numerical i/o


ReadNumber: PROCEDURE [default: UNSPECIFIED, radix: CARDINAL]
RETURNS [UNSPECIFIED] =
BEGIN
s: STRING ← [10];
IF radix = 10 AND LOOPHOLE[default, INTEGER] < 0 THEN
BEGIN default ← -default; s[0] ← ’-; s.length ← 1 END;
AppendNumber[s, default, radix];
IF radix = 8 THEN AppendChar[s, ’B];
[] ← ReadEditedString[s, IsAtom, TRUE];
RETURN[StringToNumber[s, radix]];
END;

ReadDecimal: PROCEDURE RETURNS [INTEGER] =
BEGIN
s: STRING ← [10];
[] ← ReadEditedString[s, IsAtom, TRUE];
RETURN[StringToNumber[s, 10]]
END;

ReadOctal: PROCEDURE RETURNS [UNSPECIFIED] =
BEGIN
s: STRING ← [10];
[] ← ReadEditedString[s, IsAtom, TRUE];
RETURN[StringToNumber[s, 8]]
END;

OutNumber: PROCEDURE [
stream: StreamHandle, val: INTEGER, format: NumberFormat] =
BEGIN
i: CARDINAL;
neg: BOOLEAN ← FALSE;
fill: CHARACTER ← (IF format.zerofill THEN ’0 ELSE ’ );
s: STRING ← [17];
IF val < 0 AND ~format.unsigned THEN BEGIN val ← -val; neg ← TRUE END;
AppendNumber[s, val, format.base];
i ← s.length;
IF neg THEN
BEGIN
i ← i + 1;
IF format.zerofill THEN BEGIN stream.put[stream, ’-]; neg ← FALSE END;
END;
THROUGH (i..format.columns] DO stream.put[stream, fill] ENDLOOP;
IF neg THEN stream.put[stream, ’-];
FOR i IN [0..s.length) DO stream.put[stream, s[i]] ENDLOOP;
RETURN
END;

WriteNumber: PROCEDURE [v: UNSPECIFIED, f: NumberFormat] =
BEGIN OutNumber[out, v, f]; beginLine ← FALSE; RETURN END;

WriteDecimal: PROCEDURE [n: INTEGER] =
BEGIN WriteNumber[n, NumberFormat[10, FALSE, FALSE, 0]]; RETURN END;

WriteOctal: PROCEDURE [n: UNSPECIFIED] =
BEGIN
WriteNumber[n, NumberFormat[8, FALSE, TRUE, 0]];
IF n ~ IN [0..7] THEN WriteChar[’B];
RETURN
END;

in ← StreamDefs.GetDefaultKey[ ! ANY => CONTINUE];
out ← StreamDefs.GetDefaultDisplayStream[ ! ANY => CONTINUE];

END.