-- StreamIO.Mesa Edited by Sandman on August 1, 1980 10:20 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY IODefs USING [ ControlA, ControlH, ControlQ, ControlR, ControlV, ControlW, ControlX, CR, DEL, ESC, NumberFormat, SP], StreamDefs USING [GetDefaultDisplayStream, GetDefaultKey, StreamHandle], StringDefs USING [AppendChar, AppendNumber, StringToNumber, SubString]; StreamIO: PROGRAM IMPORTS StreamDefs, StringDefs EXPORTS IODefs SHARES IODefs, StreamDefs =PUBLIC BEGIN OPEN StreamDefs, IODefs, StringDefs; 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]; IF echo THEN 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 i: CARDINAL; FOR i IN [0..s.length) DO out.put[out, s[i]]; ENDLOOP; IF s.length # 0 THEN beginLine ← s[s.length - 1] = CR; END; WriteSubString: PROCEDURE [s: StringDefs.SubString] = BEGIN i: CARDINAL; FOR i IN [s.offset..s.offset + s.length) DO out.put[out, s.base[i]]; ENDLOOP; IF s.length # 0 THEN beginLine ← s.base[s.offset + s.length - 1] = CR; END; 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.