ack/lang/m2/libm2/PascalIO.mod

426 lines
8.7 KiB
Modula-2
Raw Normal View History

1988-02-19 15:54:01 +00:00
(*
(c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
See the copyright notice in the ACK home directory, in the file "Copyright".
*)
1987-08-19 18:07:01 +00:00
(*$R-*)
1987-07-03 16:07:18 +00:00
IMPLEMENTATION MODULE PascalIO;
1988-02-19 13:05:03 +00:00
(*
Module: Pascal-like Input/Output
Author: Ceriel J.H. Jacobs
Version: $Header$
*)
1987-06-26 15:59:52 +00:00
IMPORT Conversions;
IMPORT Traps;
IMPORT RealConversions;
1988-02-19 13:05:03 +00:00
FROM Streams IMPORT Stream, StreamKind, StreamMode, StreamResult,
InputStream, OutputStream, OpenStream, CloseStream,
1988-02-19 16:52:54 +00:00
EndOfStream, Read, Write, StreamBuffering;
1987-06-26 15:59:52 +00:00
FROM Storage IMPORT ALLOCATE;
FROM SYSTEM IMPORT ADR;
TYPE charset = SET OF CHAR;
1988-02-19 16:36:45 +00:00
btype = (Preading, Pwriting, free);
1987-06-26 15:59:52 +00:00
1988-02-19 13:05:03 +00:00
CONST spaces = charset{11C, 12C, 13C, 14C, 15C, ' '};
1987-06-26 15:59:52 +00:00
1988-02-19 13:05:03 +00:00
TYPE IOstream = RECORD
1987-06-26 15:59:52 +00:00
type: btype;
1988-02-19 13:05:03 +00:00
done, eof : BOOLEAN;
ch: CHAR;
1987-06-26 15:59:52 +00:00
next: Text;
1988-02-19 13:05:03 +00:00
stream: Stream;
1987-06-26 15:59:52 +00:00
END;
1988-02-19 13:05:03 +00:00
Text = POINTER TO IOstream;
1987-06-26 15:59:52 +00:00
numbuf = ARRAY[0..255] OF CHAR;
1988-02-19 13:05:03 +00:00
VAR ibuf, obuf: IOstream;
1987-06-26 15:59:52 +00:00
head: Text;
1988-02-19 13:05:03 +00:00
result: StreamResult;
1987-06-26 15:59:52 +00:00
PROCEDURE Reset(VAR InputText: Text; Filename: ARRAY OF CHAR);
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
doclose(InputText);
getstruct(InputText);
WITH InputText^ DO
1988-02-19 13:05:03 +00:00
OpenStream(stream, Filename, text, reading, result);
IF result # succeeded THEN
1987-06-26 15:59:52 +00:00
Traps.Message("could not open input file");
HALT;
END;
1988-02-19 16:36:45 +00:00
type := Preading;
1988-02-19 13:05:03 +00:00
done := FALSE;
eof := FALSE;
1987-06-26 15:59:52 +00:00
END;
END Reset;
PROCEDURE Rewrite(VAR OutputText: Text; Filename: ARRAY OF CHAR);
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
doclose(OutputText);
getstruct(OutputText);
WITH OutputText^ DO
1988-02-19 13:05:03 +00:00
OpenStream(stream, Filename, text, writing, result);
IF result # succeeded THEN
1987-06-26 15:59:52 +00:00
Traps.Message("could not open output file");
HALT;
END;
1988-02-19 16:36:45 +00:00
type := Pwriting;
1987-06-26 15:59:52 +00:00
END;
END Rewrite;
1987-07-03 16:07:18 +00:00
PROCEDURE CloseOutput();
1988-02-19 13:05:03 +00:00
VAR p: Text;
1987-06-26 15:59:52 +00:00
BEGIN
1988-02-19 13:05:03 +00:00
p := head;
WHILE p # NIL DO
doclose(p);
p := p^.next;
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
END CloseOutput;
1987-06-26 15:59:52 +00:00
1988-02-19 13:05:03 +00:00
PROCEDURE doclose(Xtext: Text);
1987-06-26 15:59:52 +00:00
BEGIN
1988-02-19 13:05:03 +00:00
IF Xtext # Notext THEN
WITH Xtext^ DO
1987-06-26 15:59:52 +00:00
IF type # free THEN
1988-02-19 13:05:03 +00:00
CloseStream(stream, result);
1987-06-26 15:59:52 +00:00
type := free;
END;
END;
END;
END doclose;
1988-02-19 13:05:03 +00:00
PROCEDURE getstruct(VAR Xtext: Text);
1987-06-26 15:59:52 +00:00
BEGIN
1988-02-19 13:05:03 +00:00
Xtext := head;
WHILE (Xtext # NIL) AND (Xtext^.type # free) DO
Xtext := Xtext^.next;
1987-06-26 15:59:52 +00:00
END;
1988-02-19 13:05:03 +00:00
IF Xtext = NIL THEN
ALLOCATE(Xtext,SIZE(IOstream));
Xtext^.next := head;
head := Xtext;
1987-06-26 15:59:52 +00:00
END;
END getstruct;
1988-02-19 13:05:03 +00:00
PROCEDURE Error(tp: btype);
1987-06-26 15:59:52 +00:00
BEGIN
1988-02-19 16:36:45 +00:00
IF tp = Preading THEN
1988-02-19 13:05:03 +00:00
Traps.Message("input text expected");
ELSE
Traps.Message("output text expected");
1987-06-26 15:59:52 +00:00
END;
1988-02-19 13:05:03 +00:00
HALT;
END Error;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE ReadChar(InputText: Text; VAR ch : CHAR);
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
ch := NextChar(InputText);
1988-02-19 13:05:03 +00:00
InputText^.done := FALSE;
1987-07-03 16:07:18 +00:00
END ReadChar;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE NextChar(InputText: Text): CHAR;
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
WITH InputText^ DO
1988-02-19 16:36:45 +00:00
IF type # Preading THEN Error(Preading); END;
1988-02-19 13:05:03 +00:00
IF NOT done THEN
Get(InputText);
done := TRUE;
1987-06-26 15:59:52 +00:00
END;
1988-02-19 13:05:03 +00:00
RETURN ch;
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
END NextChar;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE Get(InputText: Text);
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
WITH InputText^ DO
1988-02-19 16:36:45 +00:00
IF type # Preading THEN Error(Preading); END;
1987-06-26 15:59:52 +00:00
IF eof THEN
1987-06-29 12:27:50 +00:00
Traps.Message("unexpected EOF");
HALT;
1987-06-26 15:59:52 +00:00
END;
1988-02-19 13:05:03 +00:00
IF EndOfStream(stream, result) THEN
1987-06-26 15:59:52 +00:00
eof := TRUE;
1988-02-19 13:05:03 +00:00
ch := 0C;
1987-06-26 15:59:52 +00:00
ELSE
1988-02-19 13:05:03 +00:00
Read(stream, ch, result);
1987-06-26 15:59:52 +00:00
END;
END;
1988-02-19 13:05:03 +00:00
END Get;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE Eoln(InputText: Text): BOOLEAN;
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
RETURN NextChar(InputText) = 12C;
1987-06-26 15:59:52 +00:00
END Eoln;
1987-07-03 16:07:18 +00:00
PROCEDURE Eof(InputText: Text): BOOLEAN;
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
RETURN (NextChar(InputText) = 0C) AND InputText^.eof;
1987-06-26 15:59:52 +00:00
END Eof;
1987-07-03 16:07:18 +00:00
PROCEDURE ReadLn(InputText: Text);
1987-06-26 15:59:52 +00:00
VAR ch: CHAR;
BEGIN
REPEAT
1987-07-03 16:07:18 +00:00
ReadChar(InputText, ch)
1987-06-26 15:59:52 +00:00
UNTIL ch = 12C;
END ReadLn;
1988-02-19 13:05:03 +00:00
PROCEDURE WriteChar(OutputText: Text; char: CHAR);
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
WITH OutputText^ DO
1988-02-19 16:36:45 +00:00
IF type # Pwriting THEN Error(Pwriting); END;
1988-02-19 13:05:03 +00:00
Write(stream, char, result);
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
END WriteChar;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE WriteLn(OutputText: Text);
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
WriteChar(OutputText, 12C);
1987-06-26 15:59:52 +00:00
END WriteLn;
1987-07-03 16:07:18 +00:00
PROCEDURE Page(OutputText: Text);
1987-06-26 15:59:52 +00:00
BEGIN
1987-07-03 16:07:18 +00:00
WriteChar(OutputText, 14C);
1987-06-26 15:59:52 +00:00
END Page;
1987-07-03 16:07:18 +00:00
PROCEDURE ReadInteger(InputText: Text; VAR int : INTEGER);
1987-06-26 15:59:52 +00:00
CONST
SAFELIMITDIV10 = MAX(INTEGER) DIV 10;
SAFELIMITREM10 = MAX(INTEGER) MOD 10;
VAR
neg : BOOLEAN;
safedigit: CARDINAL;
ch: CHAR;
chvalue: CARDINAL;
BEGIN
1987-07-03 16:07:18 +00:00
WHILE NextChar(InputText) IN spaces DO
Get(InputText);
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
ch := NextChar(InputText);
1987-06-26 15:59:52 +00:00
IF ch = '-' THEN
1987-07-03 16:07:18 +00:00
Get(InputText);
ch := NextChar(InputText);
1987-06-26 15:59:52 +00:00
neg := TRUE;
ELSIF ch = '+' THEN
1987-07-03 16:07:18 +00:00
Get(InputText);
ch := NextChar(InputText);
1987-06-26 15:59:52 +00:00
neg := FALSE;
ELSE
neg := FALSE
END;
safedigit := SAFELIMITREM10;
IF neg THEN safedigit := safedigit + 1 END;
int := 0;
IF (ch >= '0') AND (ch <= '9') THEN
WHILE (ch >= '0') & (ch <= '9') DO
chvalue := ORD(ch) - ORD('0');
IF (int < -SAFELIMITDIV10) OR
( (int = -SAFELIMITDIV10) AND
(chvalue > safedigit)) THEN
Traps.Message("integer too large");
HALT;
ELSE
int := 10*int - VAL(INTEGER, chvalue);
1987-07-03 16:07:18 +00:00
Get(InputText);
ch := NextChar(InputText);
1987-06-26 15:59:52 +00:00
END;
END;
IF NOT neg THEN
int := -int
END;
ELSE
Traps.Message("integer expected");
HALT;
END;
1987-07-03 16:07:18 +00:00
END ReadInteger;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE ReadCardinal(InputText: Text; VAR card : CARDINAL);
1987-06-26 15:59:52 +00:00
CONST
SAFELIMITDIV10 = MAX(CARDINAL) DIV 10;
SAFELIMITREM10 = MAX(CARDINAL) MOD 10;
VAR
ch : CHAR;
safedigit: CARDINAL;
chvalue: CARDINAL;
BEGIN
1987-07-03 16:07:18 +00:00
WHILE NextChar(InputText) IN spaces DO
Get(InputText);
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
ch := NextChar(InputText);
1987-06-26 15:59:52 +00:00
safedigit := SAFELIMITREM10;
card := 0;
IF (ch >= '0') AND (ch <= '9') THEN
WHILE (ch >= '0') & (ch <= '9') DO
chvalue := ORD(ch) - ORD('0');
IF (card > SAFELIMITDIV10) OR
( (card = SAFELIMITDIV10) AND
(chvalue > safedigit)) THEN
Traps.Message("cardinal too large");
HALT;
ELSE
card := 10*card + chvalue;
1987-07-03 16:07:18 +00:00
Get(InputText);
ch := NextChar(InputText);
1987-06-26 15:59:52 +00:00
END;
END;
ELSE
Traps.Message("cardinal expected");
HALT;
END;
1987-07-03 16:07:18 +00:00
END ReadCardinal;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE ReadReal(InputText: Text; VAR real: REAL);
1987-06-26 15:59:52 +00:00
VAR
buf: numbuf;
ch: CHAR;
ok: BOOLEAN;
index: INTEGER;
1987-06-29 12:27:50 +00:00
PROCEDURE inch(): CHAR;
BEGIN
buf[index] := ch;
INC(index);
1987-07-03 16:07:18 +00:00
Get(InputText);
RETURN NextChar(InputText);
1987-06-29 12:27:50 +00:00
END inch;
1987-06-26 15:59:52 +00:00
BEGIN
index := 0;
ok := TRUE;
1987-07-03 16:07:18 +00:00
WHILE NextChar(InputText) IN spaces DO
Get(InputText);
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
ch := NextChar(InputText);
1987-06-26 15:59:52 +00:00
IF (ch ='+') OR (ch = '-') THEN
1987-06-29 12:27:50 +00:00
ch := inch();
1987-06-26 15:59:52 +00:00
END;
IF (ch >= '0') AND (ch <= '9') THEN
WHILE (ch >= '0') AND (ch <= '9') DO
1987-06-29 12:27:50 +00:00
ch := inch();
1987-06-26 15:59:52 +00:00
END;
IF (ch = '.') THEN
1987-06-29 12:27:50 +00:00
ch := inch();
1987-06-26 15:59:52 +00:00
IF (ch >= '0') AND (ch <= '9') THEN
WHILE (ch >= '0') AND (ch <= '9') DO
1987-06-29 12:27:50 +00:00
ch := inch();
1987-06-26 15:59:52 +00:00
END;
ELSE
ok := FALSE;
END;
END;
IF ok AND (ch = 'E') THEN
1987-06-29 12:27:50 +00:00
ch := inch();
1987-06-26 15:59:52 +00:00
IF (ch ='+') OR (ch = '-') THEN
1987-06-29 12:27:50 +00:00
ch := inch();
1987-06-26 15:59:52 +00:00
END;
IF (ch >= '0') AND (ch <= '9') THEN
WHILE (ch >= '0') AND (ch <= '9') DO
1987-06-29 12:27:50 +00:00
ch := inch();
1987-06-26 15:59:52 +00:00
END;
ELSE
ok := FALSE;
END;
END;
ELSE
ok := FALSE;
END;
IF ok THEN
buf[index] := 0C;
RealConversions.StringToReal(buf, real, ok);
END;
IF NOT ok THEN
Traps.Message("Illegal real");
HALT;
END;
1987-07-03 16:07:18 +00:00
END ReadReal;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE WriteCardinal(OutputText: Text; card: CARDINAL; width: CARDINAL);
1987-06-26 15:59:52 +00:00
VAR
buf : numbuf;
BEGIN
Conversions.ConvertCardinal(card, 1, buf);
1987-07-03 16:07:18 +00:00
WriteString(OutputText, buf, width);
END WriteCardinal;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE WriteInteger(OutputText: Text; int: INTEGER; width: CARDINAL);
1987-06-26 15:59:52 +00:00
VAR
buf : numbuf;
BEGIN
Conversions.ConvertInteger(int, 1, buf);
1987-07-03 16:07:18 +00:00
WriteString(OutputText, buf, width);
END WriteInteger;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE WriteBoolean(OutputText: Text; bool: BOOLEAN; width: CARDINAL);
1987-06-26 15:59:52 +00:00
BEGIN
IF bool THEN
1987-07-03 16:07:18 +00:00
WriteString(OutputText, " TRUE", width);
1987-06-26 15:59:52 +00:00
ELSE
1987-07-03 16:07:18 +00:00
WriteString(OutputText, "FALSE", width);
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
END WriteBoolean;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE WriteReal(OutputText: Text; real: REAL; width, nfrac: CARDINAL);
1987-06-26 15:59:52 +00:00
VAR
buf: numbuf;
ok: BOOLEAN;
digits: INTEGER;
BEGIN
IF width > SIZE(buf) THEN
width := SIZE(buf);
END;
IF nfrac > 0 THEN
1987-06-29 12:27:50 +00:00
RealConversions.RealToString(real, width, nfrac, buf, ok);
1987-06-26 15:59:52 +00:00
ELSE
IF width < 9 THEN width := 9; END;
IF real < 0.0 THEN
digits := 7 - INTEGER(width);
ELSE
digits := 6 - INTEGER(width);
END;
1987-06-29 12:27:50 +00:00
RealConversions.RealToString(real, width, digits, buf, ok);
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
WriteString(OutputText, buf, 0);
END WriteReal;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
PROCEDURE WriteString(OutputText: Text; str: ARRAY OF CHAR; width: CARDINAL);
1987-06-26 15:59:52 +00:00
VAR index: CARDINAL;
BEGIN
index := 0;
1987-07-03 16:07:18 +00:00
WHILE (index <= HIGH(str)) AND (str[index] # Eos) DO
1987-06-26 15:59:52 +00:00
INC(index);
END;
WHILE index < width DO
1987-07-03 16:07:18 +00:00
WriteChar(OutputText, " ");
1987-06-26 15:59:52 +00:00
INC(index);
END;
index := 0;
1987-07-03 16:07:18 +00:00
WHILE (index <= HIGH(str)) AND (str[index] # Eos) DO
WriteChar(OutputText, str[index]);
1987-06-26 15:59:52 +00:00
INC(index);
END;
1987-07-03 16:07:18 +00:00
END WriteString;
1987-06-26 15:59:52 +00:00
1987-07-03 16:07:18 +00:00
BEGIN (* PascalIO initialization *)
1987-06-26 15:59:52 +00:00
WITH ibuf DO
1988-02-19 13:05:03 +00:00
stream := InputStream;
1987-06-26 15:59:52 +00:00
eof := FALSE;
1988-02-19 16:36:45 +00:00
type := Preading;
1988-02-19 13:05:03 +00:00
done := FALSE;
1987-06-26 15:59:52 +00:00
END;
WITH obuf DO
1988-02-19 13:05:03 +00:00
stream := OutputStream;
1987-06-26 15:59:52 +00:00
eof := FALSE;
1988-02-19 16:36:45 +00:00
type := Pwriting;
1987-06-26 15:59:52 +00:00
END;
1987-07-03 16:07:18 +00:00
Notext := NIL;
Input := ADR(ibuf);
Output := ADR(obuf);
Input^.next := Output;
Output^.next := NIL;
head := Input;
END PascalIO.