FileWriter.Mesa
written by Paxton. March 1981
last written by Paxton. August 19, 1983 1:16 pm
DIRECTORY
Rope,
IO,
File,
MonitoredQueue,
RopeReader,
RopeEditingBLT;
FileWriter: CEDAR DEFINITIONS
IMPORTS RopeEditingBLT, RopeReader, MonitoredQueue =
BEGIN
ROPE: TYPE = Rope.ROPE;
Offset: TYPE = LONG INTEGER;
Ref: TYPE = REF FileWriterBody;
FileWriterBody:
PRIVATE
TYPE =
RECORD [
block: REF TEXT, -- current block of characters
blockList: BlockList, -- list of blocks
blockQueue: MonitoredQueue.MQ, -- monitored queue of blocks
blockCount: NAT ← 0, -- number added to queue/list
stream: IO.Handle, -- file being written
toRope: BOOLEAN, -- true if output to rope instead of file
closeStream: BOOLEAN, -- true if should close stream after write
consumer: PROCESS, -- removes blocks from queue
kind: OfWriter ← unused
];
OfWriter: TYPE = {control, comment, data, unused};
BlockList: TYPE = REF BlockListBody;
BlockListBody: TYPE = RECORD[block: REF TEXT, next: BlockList];
blockSize: NAT = 512;
OpenC:
PROC [capability: File.Capability, start: Offset ← 0, makeControl:
BOOLEAN ←
TRUE]
RETURNS [control, data: Ref];
ToRope: PROC [makeControl: BOOLEAN ← TRUE] RETURNS [control, data: Ref];
ToStream:
PROC [stream:
IO.Handle, makeControl:
BOOLEAN ←
TRUE]
RETURNS [control, data: Ref];
Close:
PROC [control, data: Ref, textOnly:
BOOL, flags:
CHAR]
RETURNS [dataLen, count: Offset, output: ROPE];
WriteChar:
PROC [c:
CHARACTER, writer: Ref] =
INLINE {
loc: NAT;
block: REF TEXT ← writer.block;
IF (loc𡤋lock.length) >= blockSize
THEN
-- buffer is full
{ block ← BumpWriter[writer]; loc ← 0 };
block[loc] ← c; block.length ← loc+1 };
WriteRope:
PROC
[r: ROPE, size: Offset, writer: Ref, reader: RopeReader.Ref, start: Offset𡤀] = INLINE {
cnt: NAT;
block: REF TEXT ← writer.block;
RopeReader.SetPosition[reader,r,start];
UNTIL size=0
DO
IF block.length >= blockSize
THEN
-- buffer is full
block ← BumpWriter[writer];
cnt ← RopeReader.GetString[reader:reader, str:block, length:size];
size ← size-cnt;
ENDLOOP };
WriteText:
PROC [txt:
REF
READONLY
TEXT, writer: Ref] =
INLINE {
cnt, loc, txtLoc: NAT;
size: NAT ← txt.length;
block: REF TEXT ← writer.block;
txtLoc ← 0;
UNTIL size=0
DO
IF (loc𡤋lock.length) >= blockSize
THEN
-- buffer is full
{ block ← BumpWriter[writer]; loc ← block.length };
cnt ← MIN[blockSize-loc,size];
RopeEditingBLT.StringToStringBlt[txt,txtLoc,block,loc,cnt];
size ← size-cnt; txtLoc ← txtLoc+cnt; block.length ← loc+cnt;
ENDLOOP };
BumpWriter:
PRIVATE
PROC [writer: Ref]
RETURNS [
REF
TEXT];
-- move chars to end of list and allocate a new one
END.