(* (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands. See the copyright notice in the ACK home directory, in the file "Copyright". *) (*$R-*) IMPLEMENTATION MODULE InOut ; (* Module: Wirth's Input/Output module Author: Ceriel J.H. Jacobs Version: $Id$ *) IMPORT Streams; FROM Conversions IMPORT ConvertCardinal, ConvertInteger, ConvertOctal, ConvertHex; FROM Traps IMPORT Message; CONST TAB = 11C; TYPE numbuf = ARRAY[0..255] OF CHAR; VAR unread: BOOLEAN; unreadch: CHAR; CurrIn, CurrOut: Streams.Stream; result: Streams.StreamResult; PROCEDURE Read(VAR c : CHAR); BEGIN IF unread THEN unread := FALSE; c := unreadch; Done := TRUE; ELSE Streams.Read(CurrIn, c, result); Done := result = Streams.succeeded; END; END Read; PROCEDURE UnRead(ch: CHAR); BEGIN unread := TRUE; unreadch := ch; END UnRead; PROCEDURE Write(c: CHAR); BEGIN Streams.Write(CurrOut, c, result); END Write; PROCEDURE OpenInput(defext: ARRAY OF CHAR); VAR namebuf : ARRAY [1..128] OF CHAR; BEGIN IF CurrIn # Streams.InputStream THEN Streams.CloseStream(CurrIn, result); END; MakeFileName("Name of input file: ", defext, namebuf); IF NOT Done THEN RETURN; END; openinput(namebuf); END OpenInput; PROCEDURE OpenInputFile(filename: ARRAY OF CHAR); BEGIN IF CurrIn # Streams.InputStream THEN Streams.CloseStream(CurrIn, result); END; openinput(filename); END OpenInputFile; PROCEDURE openinput(namebuf: ARRAY OF CHAR); BEGIN IF (namebuf[0] = '-') AND (namebuf[1] = 0C) THEN CurrIn := Streams.InputStream; Done := TRUE; ELSE Streams.OpenStream(CurrIn, namebuf, Streams.text, Streams.reading, result); Done := result = Streams.succeeded; END; END openinput; PROCEDURE CloseInput; BEGIN IF CurrIn # Streams.InputStream THEN Streams.CloseStream(CurrIn, result); END; CurrIn := Streams.InputStream; END CloseInput; PROCEDURE OpenOutput(defext: ARRAY OF CHAR); VAR namebuf : ARRAY [1..128] OF CHAR; BEGIN IF CurrOut # Streams.OutputStream THEN Streams.CloseStream(CurrOut, result); END; MakeFileName("Name of output file: ", defext, namebuf); IF NOT Done THEN RETURN; END; openoutput(namebuf); END OpenOutput; PROCEDURE OpenOutputFile(filename: ARRAY OF CHAR); BEGIN IF CurrOut # Streams.OutputStream THEN Streams.CloseStream(CurrOut, result); END; openoutput(filename); END OpenOutputFile; PROCEDURE openoutput(namebuf: ARRAY OF CHAR); BEGIN IF (namebuf[1] = '-') AND (namebuf[2] = 0C) THEN CurrOut := Streams.OutputStream; Done := TRUE; ELSE Streams.OpenStream(CurrOut, namebuf, Streams.text, Streams.writing, result); Done := result = Streams.succeeded; END; END openoutput; PROCEDURE CloseOutput; BEGIN IF CurrOut # Streams.OutputStream THEN Streams.CloseStream(CurrOut, result); END; CurrOut := Streams.OutputStream; END CloseOutput; PROCEDURE MakeFileName(prompt, defext : ARRAY OF CHAR; VAR buf : ARRAY OF CHAR); VAR i : INTEGER; j : CARDINAL; BEGIN Done := TRUE; IF Streams.isatty(Streams.InputStream, result) THEN XWriteString(prompt); END; XReadString(buf); i := 0; WHILE buf[i] # 0C DO i := i + 1 END; IF i # 0 THEN i := i - 1; IF buf[i] = '.' THEN FOR j := 0 TO HIGH(defext) DO i := i + 1; buf[i] := defext[j]; END; buf[i+1] := 0C; END; RETURN; END; Done := FALSE; END MakeFileName; PROCEDURE ReadInt(VAR integ : INTEGER); CONST SAFELIMITDIV10 = MAX(INTEGER) DIV 10; SAFELIMITREM10 = MAX(INTEGER) MOD 10; TYPE itype = [0..31]; ibuf = ARRAY itype OF CHAR; VAR int : INTEGER; neg : BOOLEAN; safedigit: [0 .. 9]; chvalue: CARDINAL; buf : ibuf; index : itype; BEGIN ReadString(buf); IF NOT Done THEN RETURN END; index := 0; IF buf[index] = '-' THEN neg := TRUE; INC(index); ELSIF buf[index] = '+' THEN neg := FALSE; INC(index); ELSE neg := FALSE END; safedigit := SAFELIMITREM10; IF neg THEN safedigit := safedigit + 1 END; int := 0; WHILE (buf[index] >= '0') & (buf[index] <= '9') DO chvalue := ORD(buf[index]) - ORD('0'); IF (int > SAFELIMITDIV10) OR ( (int = SAFELIMITDIV10) AND (chvalue > safedigit)) THEN Message("integer too large"); HALT; ELSE int := 10*int + VAL(INTEGER, chvalue); INC(index) END; END; IF neg THEN integ := -int ELSE integ := int END; IF buf[index] > " " THEN Message("illegal integer"); HALT; END; Done := TRUE; END ReadInt; PROCEDURE ReadCard(VAR card : CARDINAL); CONST SAFELIMITDIV10 = MAX(CARDINAL) DIV 10; SAFELIMITREM10 = MAX(CARDINAL) MOD 10; TYPE itype = [0..31]; ibuf = ARRAY itype OF CHAR; VAR int : CARDINAL; index : itype; buf : ibuf; safedigit: [0 .. 9]; chvalue: CARDINAL; BEGIN ReadString(buf); IF NOT Done THEN RETURN; END; index := 0; safedigit := SAFELIMITREM10; int := 0; WHILE (buf[index] >= '0') & (buf[index] <= '9') DO chvalue := ORD(buf[index]) - ORD('0'); IF (int > SAFELIMITDIV10) OR ( (int = SAFELIMITDIV10) AND (chvalue > safedigit)) THEN Message("cardinal too large"); HALT; ELSE int := 10*int + chvalue; INC(index); END; END; IF buf[index] > " " THEN Message("illegal cardinal"); HALT; END; card := int; Done := TRUE; END ReadCard; PROCEDURE ReadString(VAR s : ARRAY OF CHAR); TYPE charset = SET OF CHAR; VAR i : CARDINAL; ch : CHAR; BEGIN i := 0; REPEAT Read(ch); UNTIL NOT (ch IN charset{' ', TAB, 12C, 15C}); IF NOT Done THEN RETURN; END; UnRead(ch); REPEAT Read(ch); termCH := ch; IF i <= HIGH(s) THEN s[i] := ch; IF (NOT Done) OR (ch <= " ") THEN s[i] := 0C; END; END; INC(i); UNTIL (NOT Done) OR (ch <= " "); IF Done THEN UnRead(ch); END; END ReadString; PROCEDURE XReadString(VAR s : ARRAY OF CHAR); VAR j : CARDINAL; ch : CHAR; BEGIN j := 0; LOOP Streams.Read(Streams.InputStream, ch, result); IF result # Streams.succeeded THEN EXIT; END; IF ch <= " " THEN s[j] := 0C; EXIT; END; IF j < HIGH(s) THEN s[j] := ch; INC(j); END; END; END XReadString; PROCEDURE XWriteString(s: ARRAY OF CHAR); VAR i: CARDINAL; BEGIN i := 0; LOOP IF (i <= HIGH(s)) AND (s[i] # 0C) THEN Streams.Write(Streams.OutputStream, s[i], result); INC(i); ELSE EXIT; END; END; END XWriteString; PROCEDURE WriteCard(card, width : CARDINAL); VAR buf : numbuf; BEGIN ConvertCardinal(card, width, buf); WriteString(buf); END WriteCard; PROCEDURE WriteInt(int : INTEGER; width : CARDINAL); VAR buf : numbuf; BEGIN ConvertInteger(int, width, buf); WriteString(buf); END WriteInt; PROCEDURE WriteHex(card, width : CARDINAL); VAR buf : numbuf; BEGIN ConvertHex(card, width, buf); WriteString(buf); END WriteHex; PROCEDURE WriteLn; BEGIN Write(EOL) END WriteLn; PROCEDURE WriteOct(card, width : CARDINAL); VAR buf : numbuf; BEGIN ConvertOctal(card, width, buf); WriteString(buf); END WriteOct; PROCEDURE WriteString(str : ARRAY OF CHAR); VAR nbytes : CARDINAL; BEGIN nbytes := 0; WHILE (nbytes <= HIGH(str)) AND (str[nbytes] # 0C) DO Write(str[nbytes]); INC(nbytes) END; END WriteString; BEGIN (* InOut initialization *) CurrIn := Streams.InputStream; CurrOut := Streams.OutputStream; unread := FALSE; END InOut.