-- FileIOCommonImpl.mesa
-- Last Edited by
-- MBrown on May 16, 1983 3:32 pm
-- Teitelman on June 9, 1982 9:14 pm
DIRECTORY
Rope USING [Fetch, Length, Match, ROPE],
FileIO USING [AccessOptions, CreateOptions, CloseOptions, OpenFailed, OpenFailure,
RawOption, StreamBufferParms, Trans],
FileIOPrivate USING [AlpineOpen, CIFSOpen, ComSoftOpen, Data],
IO USING [CreateRefStreamProcs, Error, GetChar, GetIndex, GetLength, SetIndex,
STREAM, StreamProcs, UnsafeBlock],
Transaction USING [Handle, nullHandle];
FileIOCommonImpl: CEDAR PROGRAM
IMPORTS
FileIO,
FileIOPrivate,
IO,
Rope,
Transaction
EXPORTS
FileIO,
FileIOPrivate =
BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
DataHandle: TYPE = REF Data;
Data: TYPE = FileIOPrivate.Data;
OpenFailed: PUBLIC SIGNAL [why: FileIO.OpenFailure, fileName: ROPE]
RETURNS [retryFileName: ROPE] = CODE;
Open: PUBLIC PROC [
fileName: ROPE,
accessOptions: FileIO.AccessOptions,
createOptions: FileIO.CreateOptions,
closeOptions: FileIO.CloseOptions,
transaction: FileIO.Trans,
raw: FileIO.RawOption,
createLength: INT,
streamBufferParms: FileIO.StreamBufferParms]
RETURNS [STREAM] = TRUSTED {
-- FileIO.Open
-- This proc just decides which more specific Open proc to call, and handles a few errors.
openFailure: FileIO.OpenFailure;
{ -- block for failure exit
DirSystem: TYPE = { CIFS, ComSoft, Alpine };
SelectDirSystem: SAFE PROC [fileName: ROPE] RETURNS [dir: DirSystem] = CHECKED {
RETURN [
SELECT fileName.Fetch[0] FROM
'/ => CIFS,
'[ => IF Rope.Match[pattern: "[*.alpine]*", object: fileName, case: FALSE] THEN
Alpine ELSE CIFS,
ENDCASE => ComSoft ];
};
dirSystem: DirSystem;
IF fileName.Length[] = 0 THEN {
openFailure ← fileNotFound; GOTO failure };
IF accessOptions = read THEN createOptions ← oldOnly;
dirSystem ← SelectDirSystem[fileName];
SELECT dirSystem FROM
CIFS, ComSoft => {
trans: Transaction.Handle ← Transaction.nullHandle;
WITH t: transaction SELECT FROM
pilot => trans ← t.trans;
juniper => IF t.trans # NIL THEN {
openFailure ← wrongTransactionType; GOTO failure };
ENDCASE => ERROR;
IF dirSystem = CIFS THEN RETURN [FileIOPrivate.CIFSOpen[
fileName, accessOptions, createOptions, closeOptions, trans,
raw, createLength, streamBufferParms]]
ELSE RETURN [FileIOPrivate.ComSoftOpen[
fileName, accessOptions, createOptions, closeOptions, trans,
raw, createLength, streamBufferParms]];
}; -- CIFS, ComSoft
Alpine => RETURN [FileIOPrivate.AlpineOpen[
fileName, accessOptions, createOptions, closeOptions, NIL,
raw, createLength, streamBufferParms]];
ENDCASE => ERROR;
EXITS
failure => {
retryFileName: ROPE =
SIGNAL FileIO.OpenFailed[why: openFailure, fileName: fileName];
RETURN [Open[retryFileName, accessOptions, createOptions, closeOptions,
transaction, raw, createLength, streamBufferParms]]
}
}};--Open
-- Procs exported to FileIOPrivate
IsThisThingATiogaFile: PUBLIC PROC [h: STREAM]
RETURNS [BOOLEAN, INT] = {
-- FileIOPrivate.IsThisThingATiogaFile
pos, len, length: INT;
{ -- block so EXITS code can use pos, len, and length.
controlHeaderId: ARRAY [0..fileIdSize) OF CHAR = [235C,312C];
controlTrailerId: ARRAY [0..fileIdSize) OF CHAR = [205C,227C];
commentHeaderId: ARRAY [0..fileIdSize) OF CHAR = [0C,0C];
fileIdSize: NAT = 2;
numTrailerLengths: NAT = 3; -- <file-props-length> <data-length> <file-length>
endSize: NAT = fileIdSize+numTrailerLengths*4; -- trailer plus three lengths
ReadLen: PROC [h: STREAM] RETURNS [INT] = {
start: PACKED ARRAY [0..3] OF CHARACTER;
start[0] ← h.GetChar[]; start[1] ← h.GetChar[];
start[2] ← h.GetChar[]; start[3] ← h.GetChar[];
RETURN [LOOPHOLE[start]] };
commentStart, commentLen, propsLen, controlLen, controlEnd: INT;
pos ← h.GetIndex[]; -- save position to restore later
length ← h.GetLength[]; -- length including any trailer stuff
controlEnd ← length-endSize; -- where the trailer info starts
IF controlEnd <= 0 THEN GOTO fail; -- too small
h.SetIndex[controlEnd]; -- set up to read the trailer
FOR i:NAT IN [0..fileIdSize) DO -- read the controlTrailerId
IF h.GetChar[] # controlTrailerId[i] THEN GOTO fail;
ENDLOOP;
IF (propsLen ← ReadLen[h]) NOT IN [0..controlEnd) THEN GOTO fail;
IF (commentStart ← ReadLen[h]) NOT IN [0..controlEnd) THEN GOTO fail;
IF ReadLen[h] # length THEN GOTO fail;
IF commentStart > 0 THEN { -- may have padded text with a null
h.SetIndex[commentStart-1];
len ← IF h.GetChar[]=0C THEN commentStart-1 ELSE commentStart }
ELSE h.SetIndex[len ← commentStart];
FOR i:NAT IN [0..fileIdSize) DO -- read the commentHeaderId
IF h.GetChar[] # commentHeaderId[i] THEN GOTO fail;
ENDLOOP;
commentLen ← ReadLen[h]; -- the length of the comment section
IF commentStart+commentLen NOT IN [0..controlEnd) THEN GOTO fail;
h.SetIndex[commentStart+commentLen]; -- go to start of control info
FOR i:NAT IN [0..fileIdSize) DO -- check the controlHeaderId
IF h.GetChar[] # controlHeaderId[i] THEN GOTO fail;
ENDLOOP;
controlLen ← ReadLen[h]; -- the length of the control section
IF commentStart+commentLen+controlLen # length THEN GOTO fail;
GOTO succeed;
EXITS
fail => { h.SetIndex[pos]; RETURN [FALSE, length] };
succeed => { h.SetIndex[pos]; RETURN [TRUE, len] };
}};
GetCharDisallowed: PUBLIC PROC [self: STREAM] RETURNS [CHAR] = {
RaiseStreamError[self]; ERROR };
PutCharDisallowed: PUBLIC PROC [self: STREAM, char: CHAR] = {
RaiseStreamError[self] };
GetBlockDisallowed: PUBLIC PROC [self: STREAM, block: REF TEXT,
startIndex: NAT, stopIndexPlusOne: NAT] RETURNS [nBytesRead: NAT] = {
RaiseStreamError[self]; ERROR };
PutBlockDisallowed: PUBLIC PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT,
stopIndexPlusOne: NAT] = { RaiseStreamError[self] };
UnsafeGetBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock]
RETURNS [nBytesRead: INT] = { RaiseStreamError[self]; ERROR };
UnsafePutBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock] = {
RaiseStreamError[self] };
SetIndexDisallowed: PUBLIC PROC [self: STREAM, index: INT] = {
RaiseStreamError[self] };
RaiseStreamError: PROC [self: STREAM] = {
selfData: DataHandle = NARROW[self.streamData];
ERROR IO.Error[
IF selfData.streamIsClosed THEN StreamClosed ELSE NotImplementedForThisStream, self]
};
Invalidate: PUBLIC PROC [self: STREAM] = {
-- FileIOPrivate.Invalidate
self.streamProcs ← commonFileIOInvalidProcs;
-- Procs on self.propList must fend for themselves
};
-- Procs called via commonFileIOInvalidProcs.
GetIndexDisallowed: PROC [self: STREAM] RETURNS [i: INT] = {
RaiseStreamError[self] };
DisallowedOpReturnsBoolean: PROC [self: STREAM] RETURNS[BOOL] = {
RaiseStreamError[self]; ERROR };
StreamOpIsNoop: PROC [self: STREAM] = { };
CloseIsNoop: PROC [self: STREAM, abort: BOOL] = { };
commonFileIOInvalidProcs: REF IO.StreamProcs = IO.CreateRefStreamProcs[
getChar: GetCharDisallowed,
endOf: DisallowedOpReturnsBoolean,
charsAvail: DisallowedOpReturnsBoolean,
getBlock: GetBlockDisallowed,
unsafeGetBlock: UnsafeGetBlockDisallowed,
putChar: PutCharDisallowed,
putBlock: PutBlockDisallowed,
unsafePutBlock: UnsafePutBlockDisallowed,
flush: StreamOpIsNoop,
reset: StreamOpIsNoop,
close: CloseIsNoop,
getIndex: GetIndexDisallowed,
setIndex: SetIndexDisallowed,
name: "Closed File"
];
END.
CHANGE LOG
Created by MBrown on December 12, 1980 12:56 PM
Changed by MBrown on January 6, 1981 8:22 PM
-- HandleFromFileName moved to FileByteStreamPilotImpl, since it now admits to being
--Pilot-specific. Added Invalidate, and private disallowed procs (GetLength, etc).
Changed by MBrown on 21-Jan-81 23:54:12
-- Added IndexTooLarge.
Changed by MBrown on January 22, 1981 3:59 PM
-- Make various procs raise streamClosed or operationDisallowed depending on value of
--streamIsClosed.
Changed by MBrown on 27-Jan-81 15:25:20
-- Moved Open here (juniper stuff being added).
Changed by MBrown on 29-Jan-81 8:58:37
-- Bug in Open: passed fileName (including server) to JOpen. Juniper gave a "protection violation".
Changed by MBrown on 29-Jan-81 20:38:29
-- Moved POpen and JOpen out.
Changed by MBrown on 1-Mar-81 13:05:50
-- Minor changes due to change in CedarString interface (Rest procedure gone, SubString -> Substr).
Changed by MBrown on 31-Mar-81 17:06:56
-- In Open, IF accessOptions = read THEN createOptions ← oldOnly.
Change by Russ Atkinson, 26-May-81 14:00:13
-- CedarString -> Rope, LONG CARDINAL -> LONG INTEGER
Changed by MBrown on 7-Dec-81 10:33:20
-- Changed name to FileIO, made compatible with IO, use INT, ROPE, etc.
Changed by MBrown on March 25, 1982 9:07 am
-- In Open, check for fileName.Length[] = 0 before doing fileName.Fetch[0]. Change
--Rope.Size -> Rope.Length, Rope.Index -> Rope.Find.
Changed by MBrown on March 26, 1982 5:14 pm
-- Added IsThisThingATiogaFile, raw parm to Open.
Changed by MBrown on September 1, 1982 9:37 pm
-- FileIO.OpenFailed, CIFS access, initial file size in Open, buffer parms.
Changed by MBrown on February 8, 1983 4:45 pm
-- Flushed Juniper support.
Changed by MBrown on May 16, 1983 2:30 pm
-- Changed Open to call FileIO.AlpineOpen when appropriate.