-- FileIOPrivate.mesa
-- Last edited by
--   MBrown on February 8, 1983 4:46 pm
--   Teitelman on May 26, 1982 4:52 pm

	DIRECTORY
		CIFS USING [OpenFile],
		Environment USING [Byte],
		File USING [Capability],
		IO USING [STREAM, UnsafeBlock],
		FileIO USING [AccessOptions, CreateOptions, CloseOptions, FileSystem,
		  RawOption, StreamBufferParms],
		FileStream USING [Subtype],
		Rope USING [ROPE],
		Space USING [Handle],
		System USING [GreenwichMeanTime],
		Transaction USING [Handle];
		
FileIOPrivate:  CEDAR DEFINITIONS =
	BEGIN
	ROPE: TYPE = Rope.ROPE;
	STREAM: TYPE = IO.STREAM;
	
	-- We model the behavior of a File IOStream with variables "file", "fileLen", and
	--"streamIndex", where
	--   file is an ARRAY [0..fileLen) OF CHAR
	--   streamIndex is an INT [0..fileLen]
	
	-- The real stream contains a lot of redundant state to make the frequently-used
	--operations GetChar and PutChar fast.  We shall list some invariant properties of
	--this state below.  These invariants hold on entry to and exit from each stream
	--operation. (Redundant properties, included for their intuitive value, are given in
	--parentheses.)
	
	-- We also define a piece of fictional state: trueDataBytesInBuffer. 
	-- trueDataBytesInBuffer ::= MIN[bufferBytes, fileLen - firstByteInBuffer].
	-- trueDataBytesInBuffer is too expensive for PutByte to maintain at all times, but it
	--is useful for other operations.
	
	DataHandle: TYPE = REF Data;
	PilotDataHandle: TYPE = REF Data[pilot];
	JuniperDataHandle: TYPE = REF Data[juniper];
	
	Data: TYPE = RECORD [
		-- common part, followed by variant depending on FileSystem.
		-- order these components to optimize the code generated for GetChar and PutChar.
		index: CARDINAL ← 0,
			-- index is IN [0..bufferBytes].
			-- didPut AND index >= dataBytesInBuffer => trueDataBytesInBuffer = index.
		dataBytesInBuffer: CARDINAL ← 0,
			-- dataBytesInBuffer is IN [0..trueDataBytesInBuffer] => IN [0..bufferBytes].
			-- NOT didPut OR (didPut AND index <= dataBytesInBuffer) =>
			--   trueDataBytesInBuffer = dataBytesInBuffer.
		bufferBytes: CARDINAL ← 0,
			-- (see buffer below).
		eofInBuffer: BOOL ← FALSE,
			-- eofInBuffer <=> fileLen <= firstFileByteInBuffer + bufferBytes.
			-- (this means fileLen = 0, or file[fileLen-1] is contained in the buffer.  This
			--is a useful piece of redundant state; fortunately, none of the cheap operations
			--need to update it).
		didPut: BOOL ← FALSE,
			-- (somebody has done a Put and not updated dataBytesInBuffer, FileLength, and
			--bufferDirty).
		bufferDirty: BOOL ← FALSE,
			-- didPut OR bufferDirty => there exists some i IN [0..trueDataBytesInBuffer) such
			--that buffer[i] # file[i] as last read from file system.  (Not maintained for
			--Pilot because of its mapped files.)
		tiogaReader: BOOL ← FALSE,
			-- TRUE iff file is being read as a Tioga file (reading the plain text only).
			--This implies that the file length shown in the stream is not the true file length,
			--but instead is the Tioga plain text length.
		streamIsClosed: BOOL ← FALSE,
			-- stream.Close[] was called.
			-- (all operations should now raise StreamError[streamClosed]).
		firstFileByteInBuffer: INT ← 0,
			-- streamIndex = firstFileByteInBuffer + index.
			-- firstFileByteInBuffer < fileLen OR firstFileByteInBuffer = fileLen = 0.
			-- firstFileByteInBuffer MOD bytesPerPage = 0.
			-- (buffer[0] is indentified with file[firstFileByteInBuffer].  There is always
			--one file byte in the buffer unless file is empty.)
		fileLength: INT ← 0,
			-- NOT didPut => fileLen = fileLength.
			-- didPut AND index > dataBytesInBuffer => fileLen = firstFileByteInBuffer +
			--index.
		buffer: LONG POINTER TO PACKED ARRAY [0..0) OF Environment.Byte ← NIL,
			-- (the current stream buffer.)
			-- buffer is PACKED ARRAY [0..bufferBytes) OF CHARACTER.
			-- file[firstFileByteInBuffer..firstFileByteInBuffer+trueDataBytesInBuffer) = 
			--   buffer[0..trueDataBytesInBuffer)
			-- (in case of Pilot, buffer[0..bufferBytes) are always backed by pages of file.)
		bufferLength: CARDINAL ← TRASH,
			-- The length of the buffer space, in bytes.  It is possible that not all of the
			-- buffer space is mapped; bufferBytes gives the length of the mapped prefix.
			-- Ignored by Juniper streams.
		bufferSwapUnitLength: CARDINAL ← TRASH,
			-- The length of the buffer swap units, in bytes.  Always <= 2*bufferLength.
			--Ignored by Juniper streams.
		bufferSpace: Space.Handle ← TRASH,
			-- (a space of length maxBufferPages pages for the stream buffer above. If buffer
			--= NIL, the space has not yet been created.)
		accessOptions: FileIO.AccessOptions,
		closeOptions: FileIO.CloseOptions,
		fileName: ROPE,
		body: SELECT type: FileIO.FileSystem FROM
			pilot => [
				fileBytes: INT ← 0,
					-- fileBytes MOD bytesPerPage = 0.
					-- length of pilot file, in bytes on all allocated pages.  This is the
					--"logical" length, i.e. it excludes the leader page if any).
				dataOffset: [0..1] ← 0,
					-- pages to skip at start of file in finding data pages: 1 if file has a
					--leader page, 0 if it doesn't.
				leader: LONG POINTER TO LeaderPage ← NIL,
					-- the leader page (may be absent).  Its length field will generally be out of
					--date.
				leaderSpace: Space.Handle ← TRASH,
					-- if leader = NIL, no leaderSpace has been created.
				openFile: CIFS.OpenFile ← NIL,
					-- if openFile = NIL then file was not opened through CIFS.
				file: File.Capability,
				trans: Transaction.Handle],
			juniper => [
				],
			ENDCASE];
			
			
	GetCharDisallowed: PROC [self: STREAM] RETURNS [CHAR];
	PutCharDisallowed: PROC [self: STREAM, char: CHAR];
	GetBlockDisallowed: PROC [self: STREAM, block: REF TEXT,
		startIndex: NAT ← 0, stopIndexPlusOne: NAT] RETURNS [nBytesRead: NAT];
	PutBlockDisallowed: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT,
		stopIndexPlusOne: NAT];
	UnsafeGetBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock]
		RETURNS [nBytesRead: INT];
	UnsafePutBlockDisallowed: PUBLIC PROC [self: STREAM, block: IO.UnsafeBlock];
	SetIndexDisallowed: PROC [self: STREAM, index: INT];
		-- These all raise IO.Error[IF streamIsClosed THEN StreamClosed ELSE
		--NotImplementedForThisStream].
		
	Invalidate: PROC [self: STREAM];
		-- Substitutes a new ProcHandle into self such that all operations raise
		--IO.Error[IF streamIsClosed THEN StreamClosed ELSE NotImplementedForThisStream].
		
	CIFSOpen: PROC [
		fileName: ROPE, 
		accessOptions: FileIO.AccessOptions,
		createOptions: FileIO.CreateOptions,
		closeOptions: FileIO.CloseOptions,
		transaction: Transaction.Handle,
		raw: FileIO.RawOption,
		createLength: INT,
		streamBufferParms: FileIO.StreamBufferParms]
		RETURNS [STREAM];
			-- CIFS version of FileIO.Open.
			
	ComSoftOpen: PROC [
		fileName: ROPE, 
		accessOptions: FileIO.AccessOptions,
		createOptions: FileIO.CreateOptions,
		closeOptions: FileIO.CloseOptions,
		transaction: Transaction.Handle,
		raw: FileIO.RawOption,
		createLength: INT,
		streamBufferParms: FileIO.StreamBufferParms]
		RETURNS [STREAM];
			-- Common Software Directory Package version of FileIO.Open.
			
	IsThisThingATiogaFile: PROC [h: STREAM] RETURNS [yes: BOOLEAN, len: INT];
		-- h must be a file stream.  Checks to see if the file behind h is in tioga format,
		--and if so returns the number of bytes of plain text in it.

	-- Pilot leader page format (must agree with format used by directory implementation).
	
	LeaderPage: TYPE = MACHINE DEPENDENT RECORD [
		versionID: CARDINAL,
			-- key to identify this leader page format
		dataType: FileStream.Subtype,
			-- ??
		create, write, read: System.GreenwichMeanTime,
		length: INT,
			-- number of bytes in file
		nameLength: CARDINAL,
			-- number of bytes in name string
		name: PACKED ARRAY [0..maxLeaderNameCharacters) OF CHARACTER];
		
	leaderVersionID: CARDINAL = 01240;
	maxLeaderNameCharacters: CARDINAL = 40;
	
	
END.


CHANGE LOG

Created by MBrown on December 12, 1980  12:04 PM

Changed by MBrown on January 6, 1981  8:53 PM
-- Added Invalidate, added trans field to pilot data.

Changed by MBrown on January 16, 1981  10:00 AM
-- DataObject is now defined without using a Stream.Handle (copied structure from
--FileStreamImpl).

Changed by MBrown on January 18, 1981  1:00 AM
-- LeaderPage now defined here (but it uses something called FileStream.Subtype for its
--"dataType" field).

Changed by MBrown on 18-Jan-81 16:49:31
-- Added bufferDirty (for juniper stream use). and streamIsClosed (for diagnosis from
--the debugger).  Improved the description of invariants. 

Changed by MBrown on January 21, 1981  3:45 PM
-- Complete re-think of Pilot FileStream state, to make Put faster and generally reduce
--the number of expensive conversions betweeen pages and bytes.  Not yet implemented.

Changed by MBrown on January 22, 1981  3:12 PM
-- Improved comments on invariants.

Changed by MBrown on January 25, 1981  8:19 PM
-- Added Juniper variant of Data.

Changed by MBrown on 27-Jan-81 15:10:07
-- FileByteStreamJuniper -> Juniper.

Changed by MBrown on 29-Jan-81 20:43:05
-- Added JOpen, POpen.

Changed by Russ Atkinson on 26-May-81 14:07:10
-- CedarString -> Rope, LONG CARDINAL -> LONG INTEGER

Changed by MBrown on  7-Dec-81 10:30:56
-- Conversion to IO, INT, ROPE, etc.

Changed by MBrown on March 26, 1982 4:40 pm
-- Added tiogaReader field (this is redundant, but may be useful for debugging), and the
--IsThisThingATiogaFile proc.

Changed by Teitelman on May 26, 1982 4:52 pm
-- changed to safe language, name change IOStream -> IO.

Changed by MBrown on August 23, 1982 2:18 pm
-- Eliminated TEXTDataOffset, added bufferParms, renamed JOpen -> JuniperOpen,
--POpen -> ComSoftOpen, added CIFSOpen, added CIFS open file to pilot variant of Data.

Changed by MBrown on February 8, 1983 4:46 pm
-- Flushed Juniper support.