UnixRemoteFileImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Demers, November 10, 1987 7:24:51 pm PST
DIRECTORY
IO USING [CreateStream, CreateStreamProcs, EndOfStream, Error, GetBlock, GetInfo, PutBlock, STREAM, StreamProcs],
RefText USING [New, ObtainScratch, ReleaseScratch],
RemoteFile USING [Error, GetProcs, GetServer, ServerHandle],
Rope USING [ROPE],
UnixRemoteFile USING [Close, Create, Mode, Open, Read, UnixServerHandle, UnixServerObject, Write]
;
UnixRemoteFileImpl: CEDAR PROGRAM
IMPORTS IO, RefText, RemoteFile, UnixRemoteFile
EXPORTS UnixRemoteFile
~ {
OPEN UnixRemoteFile;
Types
FileDescriptor: TYPE ~ REF;
Handle: TYPE ~ UnixServerHandle;
Object: TYPE ~ UnixServerObject;
ROPE: TYPE ~ Rope.ROPE;
ServerHandle: TYPE ~ RemoteFile.ServerHandle;
STREAM: TYPE ~ IO.STREAM;
Parameters
bufferBytes: CARDINAL ~ 2048;
viewUnix: PUBLIC ATOM ← $Unix;
Handle Create / Destroy
CreateHandle: PUBLIC PROC [serverName: ROPE] RETURNS [h: Handle] ~ {
sH: ServerHandle;
tProcs: REF;
sH ← RemoteFile.GetServer[serverName
! RemoteFile.Error => ReportError[$unknownServer, "can't find server"] ];
tProcs ← RemoteFile.GetProcs[sH, viewUnix
! RemoteFile.Error => IF code = $notImplemented
THEN CONTINUE
ELSE ReportError[$unreachable, "can't contact server"]
];
IF tProcs = NIL THEN ReportError[$viewNotImplemented, "Unix(tm) view not implemented by server"];
h ← NEW[Object ← [sH, NARROW[tProcs]]];
};
DestroyHandle: PUBLIC PROC [h: Handle] ~ { h^ ← [NIL, NIL] };
Creature Comforts
RetrieveFile: PUBLIC PROC [h: Handle, path: ROPE, into: STREAM] ~ {
offset: CARD ← 0;
buffer: REF TEXT ← RefText.ObtainScratch[bufferBytes];
fD: FileDescriptor ← NIL;
{
ENABLE UNWIND => {
RefText.ReleaseScratch[buffer];
IF fD # NIL THEN Close[h, fD ! Error => CONTINUE];
};
fD ← Open[h, path];
DO
[] ← Read[h, fD, offset, bufferBytes, 0, buffer];
IO.PutBlock[into, buffer];
offset ← offset + buffer.length;
IF buffer.length < bufferBytes THEN EXIT;
ENDLOOP;
};
Close[h, fD];
RefText.ReleaseScratch[buffer];
};
StoreFile: PUBLIC PROC [h: Handle, path: ROPE, mode: Mode, from: STREAM] ~ {
offset: CARD ← 0;
buffer: REF TEXT ← RefText.ObtainScratch[bufferBytes];
fD: FileDescriptor ← NIL;
{
ENABLE UNWIND => {
RefText.ReleaseScratch[buffer];
IF fD # NIL THEN Close[h, fD ! Error => CONTINUE];
};
fD ← Create[h, path, mode];
DO
bytesRead, bytesWritten: CARD;
bytesRead ← IO.GetBlock[from, buffer, 0, bufferBytes];
IF bytesRead = 0 THEN EXIT;
bytesWritten ← Write[h, fD, offset, bytesRead, 0, buffer];
offset ← offset + bytesWritten;
IF bytesWritten # bytesRead THEN ReportError[$io, "short write error"];
ENDLOOP;
};
Close[h, fD];
RefText.ReleaseScratch[buffer];
};
Stream Implementation
StreamData: TYPE ~ REF StreamDataObject;
StreamDataObject: TYPE ~ RECORD [
h: Handle,
fD: FileDescriptor,
fileOffset: CARD,
buffer: REF TEXT,
index: CARDINAL,
closed: BOOL
];
inputStreamProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[
variety~input,
class~$UnixRemoteFile,
getChar~MyGetChar,
endOf~MyEndOf,
close~MyClose
];
outputStreamProcs: REF IO.StreamProcs ~ IO.CreateStreamProcs[
variety~output,
class~$UnixRemoteFile,
putChar~MyPutChar,
flush~MyFlush,
close~MyClose
];
OpenReadStream: PUBLIC PROC [h: Handle, path: ROPE] RETURNS [str: STREAM] ~ {
fD: FileDescriptor ← Open[h, path];
streamData: StreamData ← NEW[StreamDataObject ← [h, fD, 0, RefText.New[bufferBytes], 0, FALSE]];
str ← IO.CreateStream[inputStreamProcs, streamData, NIL];
};
OpenWriteStream: PUBLIC PROC [h: Handle, path: ROPE, mode: Mode] RETURNS [str: STREAM] ~ {
fD: FileDescriptor ← Create[h, path, mode];
streamData: StreamData ← NEW[StreamDataObject ← [h, fD, 0, RefText.New[bufferBytes], 0, FALSE]];
str ← IO.CreateStream[outputStreamProcs, streamData, NIL];
};
CheckStreamClosed: PROC [d: StreamData, self: STREAM] ~ INLINE {
IF d.closed THEN ERROR IO.Error[StreamClosed, self] };
MyEndOf: PROC [self: STREAM] RETURNS [BOOL] ~ {
streamData: StreamData ← NARROW[self.streamData];
b: REF TEXT ← streamData.buffer;
CheckStreamClosed[streamData, self];
IF streamData.index >= b.length THEN {
bytesRead: CARD ← Read[streamData.h, streamData.fD, streamData.fileOffset, b.maxLength, 0, b];
IF bytesRead = 0 THEN RETURN[TRUE];
streamData.index ← 0;
streamData.fileOffset ← streamData.fileOffset + bytesRead;
};
RETURN[FALSE];
};
MyGetChar: PROC [self: STREAM] RETURNS [c: CHAR] ~ {
streamData: StreamData ← NARROW[self.streamData];
b: REF TEXT ← streamData.buffer;
i: CARDINAL ← streamData.index;
CheckStreamClosed[streamData, self];
IF i >= b.length THEN {
bytesRead: CARD ← Read[streamData.h, streamData.fD, streamData.fileOffset, b.maxLength, 0, b];
IF bytesRead = 0 THEN ERROR IO.EndOfStream[self];
streamData.fileOffset ← streamData.fileOffset + bytesRead;
i ← 0;
};
c ← b[i];
i ← i + 1;
streamData.index ← i;
};
MyPutChar: PROC [self: STREAM, char: CHAR] ~ {
streamData: StreamData ← NARROW[self.streamData];
b: REF TEXT ← streamData.buffer;
i: CARDINAL ← streamData.index;
CheckStreamClosed[streamData, self];
IF i >= b.maxLength THEN {
bytesWritten: CARD;
b.length ← i;
bytesWritten ← Write[streamData.h, streamData.fD, streamData.fileOffset, i, 0, b];
IF bytesWritten # i THEN ERROR; -- BUG: should have raised Error[...]
streamData.fileOffset ← streamData.fileOffset + bytesWritten;
i ← 0;
};
b[i] ← char;
i ← i + 1;
streamData.index ← i;
};
MyFlush: PROC [self: STREAM] ~ {
streamData: StreamData ← NARROW[self.streamData];
b: REF TEXT ← streamData.buffer;
i: CARDINAL ← streamData.index;
CheckStreamClosed[streamData, self];
IF i > 0 THEN {
bytesWritten: CARD;
b.length ← i;
bytesWritten ← Write[streamData.h, streamData.fD, streamData.fileOffset, i, 0, b];
IF bytesWritten # i THEN ERROR; -- BUG: should have raised Error[...]
streamData.fileOffset ← streamData.fileOffset + bytesWritten;
i ← 0;
};
streamData.index ← i;
};
MyClose: PROC [self: STREAM, abort: BOOL] ~ {
streamData: StreamData ← NARROW[self.streamData];
IF streamData.closed THEN RETURN;
IF (IO.GetInfo[self].variety = output) AND (NOT abort) THEN MyFlush[self];
Close[streamData.h, streamData.fD];
streamData.fD ← NIL;
streamData.buffer ← NIL;
streamData.closed ← TRUE;
};
Errors
Error: PUBLIC ERROR [code: ATOM, msg: ROPE] ~ CODE;
ReportError: PROC [code: ATOM, msg: ROPENIL] ~ {
ERROR Error[code, msg];
};
}...