PSFileImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Doug Wyatt, May 14, 1987 11:38:33 am PDT
PostScript implementation: file operations.
DIRECTORY
Basics USING [LongNumber],
FS USING [AccessOptions, Error, ErrorDesc, StreamOpen],
IO USING [Close, EndOfStream, Error, GetByte, GetChar, PutByte, PutChar, STREAM],
PS USING [Error, File, NewFile, PopFile, PopInt, PopString, PushBool, PushFile, PushInt, PushString, Register, RegisterPrimitives, Root, RopeFromString, String, StringGet, StringGetInterval, StringIndex, StringPut],
Rope USING [Equal, ROPE];
PSFileImpl: CEDAR PROGRAM
IMPORTS FS, IO, PS, Rope
~ BEGIN OPEN PS;
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
File operations
FileCreate: PROC [string1, string2: String] RETURNS [File] ~ {
fileName: ROPE ~ RopeFromString[string1];
fileAccess: ROPE ~ RopeFromString[string2];
accessOptions: FS.AccessOptions ← read;
stream: STREAMNIL;
fsError: FS.ErrorDesc;
SELECT TRUE FROM
Rope.Equal[fileName, "%stdin"] => xxx;
Rope.Equal[fileName, "%stdout"] => xxx;
Rope.Equal[fileName, "%stderr"] => xxx;
ENDCASE;
SELECT TRUE FROM
Rope.Equal[fileAccess, "r"] => accessOptions ← read;
Rope.Equal[fileAccess, "w"] => accessOptions ← create;
ENDCASE => ERROR Error[invalidfileaccess];
stream ← FS.StreamOpen[fileName: fileName, accessOptions: accessOptions !
FS.Error => { fsError ← error; CONTINUE };
];
IF stream=NIL THEN SELECT fsError.group FROM
user => ERROR Error[undefinedfilename];
ENDCASE => ERROR Error[ioerror];
RETURN [NewFile[executable: FALSE, access: unlimited, stream: stream]];
};
WriteString: PROC [file: File, string: String] ~ {
IF file.access<unlimited THEN ERROR Error[invalidaccess];
FOR si: StringIndex IN[0..string.length) DO
char: CHAR ~ StringGet[string, si];
IO.PutChar[file.stream, char !
IO.Error => GOTO IOError;
];
ENDLOOP;
EXITS
IOError => ERROR Error[ioerror];
};
Primitives
Pfile: PROC [self: Root] ~ {
string2: String ~ PopString[self];
string1: String ~ PopString[self];
PushFile[self, FileCreate[string1, string2]];
};
Pclosefile: PROC [self: Root] ~ {
file: File ~ PopFile[self];
IO.Close[file.stream];
};
Pread: PROC [self: Root] ~ {
file: File ~ PopFile[self];
int: INT;
IF file.access<readOnly THEN ERROR Error[invalidaccess];
int ← IO.GetByte[file.stream !
IO.EndOfStream => GOTO EndOfFile;
IO.Error => IF ec=StreamClosed THEN GOTO EndOfFile ELSE GOTO IOError;
];
PushInt[self, int];
PushBool[self, TRUE];
EXITS
EndOfFile => PushBool[self, FALSE];
IOError => ERROR Error[ioerror];
};
Pwrite: PROC [self: Root] ~ {
int: INT ~ PopInt[self];
file: File ~ PopFile[self];
IF file.access<unlimited THEN ERROR Error[invalidaccess];
IO.PutByte[file.stream, LOOPHOLE[int, Basics.LongNumber].ll !
IO.EndOfStream => GOTO IOError;
IO.Error => GOTO IOError;
];
EXITS
IOError => ERROR Error[ioerror];
};
Preadhexstring: PROC [self: Root] ~ {
string: String ~ PopString[self];
file: File ~ PopFile[self];
hi: [0..2] ← 0;
h: ARRAY [0..2) OF [0..16) ← ALL[0];
si: StringIndex ← 0;
IF file.access<readOnly THEN ERROR Error[invalidaccess];
WHILE si<string.length DO
char: CHAR ~ IO.GetChar[file.stream !
IO.EndOfStream => EXIT;
IO.Error => GOTO IOError;
];
SELECT char FROM
IN ['0..'9] => { h[hi] ← (char-'0); hi ← hi+1 };
IN ['A..'F] => { h[hi] ← 10+(char-'A); hi ← hi+1 };
IN ['a..'f] => { h[hi] ← 10+(char-'a); hi ← hi+1 };
ENDCASE;
IF hi=2 THEN { StringPut[string, si, VAL[h[0]*16+h[1]]]; si ← si+1; hi ← 0 };
ENDLOOP;
IF si=string.length THEN { PushString[self, string]; PushBool[self, TRUE] }
ELSE { PushString[self, StringGetInterval[string, 0, si]]; PushBool[self, FALSE] };
EXITS
IOError => ERROR Error[ioerror];
};
Pwritehexstring: PROC [self: Root] ~ {
string: String ~ PopString[self];
file: File ~ PopFile[self];
IF file.access<unlimited THEN ERROR Error[invalidaccess];
FOR si: StringIndex IN[0..string.length) DO
byte: BYTE ~ ORD[StringGet[string, si]];
Hex: PROC [h: [0..16)] RETURNS [CHAR] ~ {
RETURN [IF h<10 THEN '0+h ELSE 'a+(h-10)];
};
IO.PutChar[file.stream, Hex[byte/16] !
IO.Error => GOTO IOError;
];
IO.PutChar[file.stream, Hex[byte MOD 16] !
IO.Error => GOTO IOError;
];
ENDLOOP;
EXITS
IOError => ERROR Error[ioerror];
};
Preadstring: PROC [self: Root] ~ {
string: String ~ PopString[self];
file: File ~ PopFile[self];
si: StringIndex ← 0;
IF file.access<readOnly THEN ERROR Error[invalidaccess];
WHILE si<string.length DO
char: CHAR ~ IO.GetChar[file.stream !
IO.EndOfStream => EXIT;
IO.Error => GOTO IOError;
];
StringPut[string, si, char];
si ← si+1;
ENDLOOP;
IF si=string.length THEN { PushString[self, string]; PushBool[self, TRUE] }
ELSE { PushString[self, StringGetInterval[string, 0, si]]; PushBool[self, FALSE] };
EXITS
IOError => ERROR Error[ioerror];
};
Pwritestring: PROC [self: Root] ~ {
string: String ~ PopString[self];
file: File ~ PopFile[self];
WriteString[file, string];
};
Preadline: PROC [self: Root] ~ {
};
Pbytesavailable: PROC [self: Root] ~ {
};
Pflush: PROC [self: Root] ~ {
};
Pflushfile: PROC [self: Root] ~ {
};
Presetfile: PROC [self: Root] ~ {
};
Pstatus: PROC [self: Root] ~ {
};
Prun: PROC [self: Root] ~ {
};
Pcurrentfile: PROC [self: Root] ~ {
};
Pprint: PROC [self: Root] ~ {
string: String ~ PopString[self];
WriteString[self.stdout, string];
};
Pecho: PROC [self: Root] ~ {
};
FilePrimitives: PROC [self: Root] ~ {
Register[self, "file", Pfile];
Register[self, "closefile", Pclosefile];
Register[self, "read", Pread];
Register[self, "write", Pwrite];
Register[self, "readhexstring", Preadhexstring];
Register[self, "writehexstring", Pwritehexstring];
Register[self, "readstring", Preadstring];
Register[self, "writestring", Pwritestring];
Register[self, "readline", Preadline];
Register[self, "bytesavailable", Pbytesavailable];
Register[self, "flush", Pflush];
Register[self, "flushfile", Pflushfile];
Register[self, "resetfile", Presetfile];
Register[self, "status", Pstatus];
Register[self, "run", Prun];
Register[self, "currentfile", Pcurrentfile];
Register[self, "print", Pprint];
Register[self, "echo", Pecho];
};
RegisterPrimitives[FilePrimitives];
END.