DIRECTORY
Basics USING [LowByte],
Convert USING [RealFromRope, RopeFromReal],
IO,
PascalBasic,
PascalWizardFiles,
PrincOpsUtils USING [LongCopy],
Real USING [DefaultSinglePrecision],
RefText USING [TrustTextAsRope],
Rope USING [Cat, Fetch, FromChar, Length];
PascalWizardFilesImpl:
CEDAR
PROGRAM
IMPORTS Basics, Convert, IO, PascalBasic, PrincOpsUtils, RefText, Rope
EXPORTS PascalWizardFiles =
BEGIN OPEN PascalBasic, PascalWizardFiles;
V A R I A B L E S (all private)
openFiles: MesaFilePtr ← NIL;
P R O C E D U R E S
PascalTextBREAK:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
file.baseFile.str.Flush[];
END;
PascalTextGET:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
file.element ← file.baseFile.str.GetChar[ !
IO.EndOfStream => GOTO EOF];
SELECT file.element
FROM
'\N
--CarriageReturn-- => {
file.eoln ← TRUE; file.element ← ' };
ENDCASE => file.eoln ← FALSE;
EXITS
EOF => {
file.baseFile.eof ← file.eoln ← TRUE;
file.element ← ' };
END;
PascalTextElement:
PUBLIC
PROCEDURE [file: PascalTextFilePtr]
RETURNS [PascalChar] =
TRUSTED BEGIN
RETURN[file.element];
END;
PascalTextPUT:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
file.baseFile.str.PutChar[file.element];
END;
PascalTextRESET:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
file.baseFile.str.SetIndex[0 !
IO.Error => {IF ec = NotImplementedForThisStream THEN CONTINUE}];
file.baseFile.eof ← FALSE;
PascalTextGET[file];
END;
PascalTextREWRITE:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
file.baseFile.str.SetIndex[0 !
IO.Error => {IF ec = NotImplementedForThisStream THEN CONTINUE}];
file.baseFile.str.SetLength[0 !
IO.Error => {IF ec = NotImplementedForThisStream THEN CONTINUE}];
file.baseFile.eof ← TRUE;
END;
PascalTextPAGE:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
BEGIN
PascalWriteLn[file: file];
PascalWriteChar[file: file, item: '\F --form feed--];
PascalWriteLn[file: file]
END;
PascalTextEOF:
PUBLIC
PROCEDURE [file: PascalTextFilePtr]
RETURNS [BOOLEAN] =
TRUSTED BEGIN
RETURN[file.baseFile.eof];
END;
PascalTextEOLN:
PUBLIC
PROCEDURE [file: PascalTextFilePtr]
RETURNS [BOOLEAN] =
TRUSTED BEGIN
RETURN[file.eoln];
END;
PascalBREAK:
PUBLIC
PROCEDURE [
file: PascalFilePtr, length: CARDINAL,
element: LONG POINTER] = TRUSTED {file.str.Flush[]};
PascalGET:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalFilePtr, length: CARDINAL,
element: LONG POINTER -- TO ARRAY[0..length) OF UNSPECIFIED --] =
UNCHECKED BEGIN
IF length = 1
THEN
element^ ← file.str.GetChar[ ! IO.EndOfStream => {file.eof ← TRUE; CONTINUE}]
ELSE
IF length # file.str.UnsafeGetBlock[[base: element, startIndex: 0,
count: length]] THEN file.eof ← TRUE;
END;
PascalPUT:
PUBLIC
PROCEDURE [
file: PascalFilePtr, length: CARDINAL,
element: LONG POINTER -- TO ARRAY[0..length) OF UNSPECIFIED --] =
TRUSTED BEGIN
IF length = 1
THEN
file.str.PutChar[LOOPHOLE[Basics.LowByte[LOOPHOLE[element^]]]]
ELSE file.str.UnsafePutBlock[[base: element, startIndex: 0,
count: length]];
END;
PascalRESET:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalFilePtr, length: CARDINAL,
element: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED --] =
UNCHECKED BEGIN
file.str.SetIndex[0];
file.eof ← FALSE;
PascalGET[file, length, element];
END;
PascalREWRITE:
PUBLIC
PROCEDURE [
file: PascalFilePtr, length: CARDINAL ← 0,
element: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED -- ← NIL] =
TRUSTED BEGIN
file.str.SetIndex[0];
file.str.SetLength[0];
file.eof ← TRUE;
END;
PascalRead,
PascalReadLong:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalFilePtr, length: CARDINAL,
element: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED --,
item: LONG POINTER -- TO ARRAY[0..length/2) OF UNSPECIFIED --] =
UNCHECKED BEGIN
IF length = 1
THEN item^ ← element^
ELSE PrincOpsUtils.LongCopy[from: element, nwords: length/2, to: item];
PascalGET[file: file, length: length, element: element];
END;
PascalWrite,
PascalWriteLong:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalFilePtr, length: CARDINAL,
element: LONG POINTER TO -- ARRAY[0..length/2) OF -- UNSPECIFIED,
item: LONG POINTER TO -- ARRAY[0..length/2) OF -- UNSPECIFIED] =
UNCHECKED BEGIN
IF length = 1
THEN element^ ← item^
ELSE PrincOpsUtils.LongCopy[from: item, nwords: length/2, to: element];
PascalPUT[file: file, length: length, element: element];
END;
PascalEOF:
PUBLIC
PROCEDURE [file: PascalFilePtr]
RETURNS [
BOOLEAN] =
TRUSTED {
RETURN[file.eof]};
PascalReadLn:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
WHILE NOT PascalTextEOLN[file] DO PascalTextGET[file] ENDLOOP;
PascalTextGET[file];
END;
PascalWriteLn:
PUBLIC
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
file.baseFile.str.PutChar['\N -- CarriageReturn -- ];
END;
PascalReadInteger:
PUBLIC
PROCEDURE [file: PascalTextFilePtr]
RETURNS [PascalInteger] =
TRUSTED BEGIN
SkipBlanks[file];
SELECT file.element
FROM
'- => {PascalTextGET[file]; RETURN[-ReadDecimal[file].n]};
'+ => {PascalTextGET[file]; RETURN[ReadDecimal[file].n]};
ENDCASE => RETURN[ReadDecimal[file].n];
END;
SkipBlanks:
PROCEDURE [file: PascalTextFilePtr] =
TRUSTED BEGIN
WHILE
NOT PascalTextEOF[file]
AND
(
SELECT file.element
FROM
'-, '+, IN ['0..'9], '., IN ['a..'z], IN ['A..'Z] => FALSE,
ENDCASE => TRUE) DO PascalTextGET[file] ENDLOOP;
END;
ReadDecimal:
PROCEDURE [file: PascalTextFilePtr]
RETURNS [n, digitCount: PascalInteger] =
TRUSTED BEGIN
n ← 0;
digitCount ← 0;
IF
NOT PascalTextEOF[file]
AND file.element
NOT
IN ['0..'9]
THEN
SIGNAL NumericInputError;
WHILE file.element
IN ['0..'9]
DO
n ← 10*n + (file.element - '0);
digitCount ← digitCount + 1;
PascalTextGET[file];
ENDLOOP;
END;
PascalWriteInteger:
PUBLIC
PROCEDURE [
file: PascalTextFilePtr, item: PascalInteger,
fieldMinLength: PascalInteger ← -1] =
TRUSTED BEGIN
sayMinus: BOOLEAN ← FALSE;
digits: ARRAY [0..15] OF [0..9];
nDigits: [0..15] ← 0;
i: PascalInteger;
stream: IO.STREAM;
stream ← file.baseFile.str;
IF NOT fieldMinLength IN [0..1] THEN stream.PutChar[' ];
IF sayMinus ← item < 0
THEN {
item ← -item; fieldMinLength ← fieldMinLength - 1};
IF item = 0 THEN {digits[0] ← 0; nDigits ← 1}
ELSE
WHILE item # 0
DO
digits[nDigits] ← item MOD 10;
nDigits ← nDigits + 1;
item ← item/10;
ENDLOOP;
FOR i IN [1..fieldMinLength - nDigits] DO stream.PutChar[' ] ENDLOOP;
IF sayMinus THEN stream.PutChar['-];
FOR i
DECREASING
IN [0..nDigits)
DO
stream.PutChar['0 + digits[i]] ENDLOOP;
END;
PascalReadReal:
PUBLIC
PROCEDURE [file: PascalTextFilePtr]
RETURNS [PascalReal] =
TRUSTED BEGIN
s: REF TEXT ← NEW[TEXT[50]];
s.length ← 0;
SkipBlanks[file];
WHILE
(
SELECT file.element
FROM
IN ['a..'z], IN ['A..'Z], '+, '-, '., IN ['0..'9] => TRUE,
ENDCASE => FALSE) DO
s[s.length] ← file.element;
s.length ← s.length + 1;
PascalTextGET[file];
ENDLOOP;
RETURN[Convert.RealFromRope[RefText.TrustTextAsRope[s]]];
END;
PascalWriteReal:
PUBLIC
PROCEDURE [
file: PascalTextFilePtr, item: PascalReal,
fieldMinLength, fracLength: PascalInteger ← -1] =
TRUSTED BEGIN
shortFracLength: INTEGER ← fracLength;
IF
NOT fieldMinLength
IN [0..1]
THEN
file.baseFile.str.PutChar[' ];
PascalWriteString[file, Convert.RopeFromReal[
from: item,
precision:
IF fracLength < 0 THEN Real.DefaultSinglePrecision ELSE shortFracLength], fieldMinLength];
END;
PascalReadChar:
PUBLIC
PROCEDURE [file: PascalTextFilePtr]
RETURNS [PascalChar] =
TRUSTED BEGIN
c: PascalChar;
c ← PascalTextElement[file];
PascalTextGET[file];
RETURN[c];
END;
PascalWriteChar:
PUBLIC
PROCEDURE [
file: PascalTextFilePtr, item: PascalChar,
fieldMinLength: PascalInteger ← -1] =
TRUSTED BEGIN
i: PascalInteger;
FOR i
IN [1..fieldMinLength)
DO
file.baseFile.str.PutChar[' ] ENDLOOP;
IF fieldMinLength#0
THEN
BEGIN
file.baseFile.str.PutChar[item];
file.element ← item;
END;
END;
PascalReadBoolean:
PUBLIC
PROCEDURE [file: PascalTextFilePtr]
RETURNS [PascalBoolean] =
TRUSTED BEGIN
b: PascalBoolean;
SkipBlanks[file];
SELECT file.element
FROM
'T, 't => b ← TRUE;
'F, 'f => b ← FALSE;
ENDCASE => {SIGNAL NumericInputError; b ← FALSE};
WHILE
(
SELECT file.element
FROM
IN ['a..'z], IN ['A..'Z] => TRUE,
ENDCASE => FALSE) DO PascalTextGET[file] ENDLOOP;
RETURN[b];
END;
PascalWriteBoolean:
PUBLIC
PROCEDURE [
file: PascalTextFilePtr, item: PascalBoolean,
fieldMinLength: PascalInteger ← -1] =
TRUSTED BEGIN
IF
NOT fieldMinLength
IN [0..1]
THEN
PascalWriteChar[file, ' ];
PascalWriteString[file, IF item THEN "TRUE" ELSE "FALSE", fieldMinLength];
END;
PascalReadArrayOfChar, PascalReadLongArrayOfChar:
PUBLIC UNSAFE PROCEDURE [
file: PascalTextFilePtr,
item: CharArrayPtr, arrayBound: PascalInteger] =
UNCHECKED BEGIN
v: CharArrayConcretePtr ← item;
i: PascalInteger;
FOR i
IN [1..arrayBound]
DO
v[i] ← PascalTextElement[file]; PascalTextGET[file]; ENDLOOP;
END;
PascalWriteArrayOfChar, PascalWriteLongArrayOfChar:
PUBLIC PROCEDURE [
file: PascalTextFilePtr,
item: CharArrayPtr,
arrayBound: PascalInteger, fieldMinLength: PascalInteger ← -1] =
TRUSTED BEGIN
v: CharArrayConcretePtr ← LOOPHOLE[item];
i, arrayLim: PascalInteger;
FOR i
IN [arrayBound..fieldMinLength)
DO
file.baseFile.str.PutChar[' ] ENDLOOP;
arrayLim ←
IF fieldMinLength < 0 THEN arrayBound ELSE MIN[fieldMinLength, arrayBound];
FOR i
IN [1..arrayLim]
DO
file.baseFile.str.PutChar[v[i]] ENDLOOP;
IF ((fieldMinLength < 0
AND arrayLim > 0)
OR fieldMinLength>0)
THEN
file.element ← IF arrayLim > 0 THEN v[arrayLim] ELSE ' ;
END;
ReadString:
PRIVATE
PROCEDURE [file: PascalTextFilePtr]
RETURNS [r:
ROPE]=
TRUSTED BEGIN
r ← "";
WHILE
NOT PascalTextEOLN[file]
AND
NOT file.baseFile.eof
DO
r ← Rope.Cat[r, Rope.FromChar[file.element]];
PascalTextGET[file];
ENDLOOP;
END;
PascalWriteString,
PascalWriteLongString:
PUBLIC
PROCEDURE [
file: PascalTextFilePtr, item: ROPE, fieldMinLength: PascalInteger ← -1] =
TRUSTED BEGIN
i, len, stringLim: PascalInteger;
len ← item.Length[];
FOR i
IN [len..fieldMinLength)
DO
file.baseFile.str.PutChar[' ] ENDLOOP;
stringLim ← IF fieldMinLength < 0 THEN len ELSE MIN[fieldMinLength, len];
FOR i
IN [0..stringLim)
DO
file.baseFile.str.PutChar[Rope.Fetch[item, i]] ENDLOOP;
IF ((fieldMinLength < 0
AND stringLim > 0)
OR fieldMinLength>0)
THEN
file.element ← IF stringLim > 0 THEN Rope.Fetch[item, stringLim-1] ELSE ' ;
END;
P R O C E D U R E S NOT Called by PasMesa
(and hence, intended to be called as external procedures by the Pascal
program, or else from Mesa code that implements such external procedures).
PascalOpenTextFileWithStream:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalTextFilePtr,
stream: IO.STREAM] =
Allocates a new MesaFile and installs the specified stream
UNCHECKED BEGIN
openFiles ← z.NEW[MesaFile ← [str: stream, openFileLink: openFiles]];
file.baseFile ← LOOPHOLE[openFiles];
END;
PascalOpenTextFileTTYInput:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalTextFilePtr] =
Allocates a new MesaFile and sets up file to read from the terminal (no pre-read)
UNCHECKED BEGIN
openFiles ← z.NEW[MesaFile ← [str: ttyInputStream, eof: FALSE, openFileLink: openFiles]];
file.baseFile ← LOOPHOLE[openFiles];
file.element ← ' ;
file.eoln ← TRUE;
END;
PascalOpenTextFileTTYOutput:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalTextFilePtr] =
Allocates a new MesaFile and sets up file to output to the terminal
UNCHECKED BEGIN
openFiles ← z.NEW[MesaFile ← [str: ttyOutputStream, eof: TRUE, openFileLink: openFiles]];
file.baseFile ← LOOPHOLE[openFiles];
END;
PascalCloseTextFile:
PUBLIC
UNSAFE
PROCEDURE [file: PascalTextFilePtr] =
Closes the file, and sets the PascalFile to NIL; the MesaFile must
continue to exist however, to avoid collecting non-garbage.
UNCHECKED BEGIN
IF file.baseFile # NIL THEN file.baseFile.str.Close[];
file.baseFile ← NIL;
END;
PascalOpenFileWithStream:
PUBLIC
UNSAFE
PROCEDURE [
file: PascalFilePtr,
stream: IO.STREAM] =
Allocates a new MesaFile and installs the specified stream
UNCHECKED BEGIN
openFiles ← z.NEW[MesaFile ← [str: stream, openFileLink: openFiles]];
file^ ← LOOPHOLE[openFiles];
END;
PascalCloseFile:
PUBLIC
UNSAFE
PROCEDURE [file: PascalFilePtr] =
Closes the file, and sets the PascalFile to NIL; the MesaFile must
continue to exist however, to avoid collecting non-garbage.
UNCHECKED BEGIN
IF file^ # NIL THEN file.str.Close[];
file^ ← NIL;
END;
END. -- PascalWizardFilesImpl