-- 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.