GetFileImpl.Mesa;
Written by Paxton. January 1981
Cobbled for Tioga2 by Lamming on February 11, 1983 4:49 pm
Last edited by Lamming - June 2, 1983 10:30 am
DIRECTORY
Atom     USING [MakeAtom],
CIFS     USING [Close, OpenFile],
File     USING [Capability],
FileOps    USING [comment, endNode, endOfFile, IntBytes, LengthByte, look1, look2, look3, looks, looksFirst, LooksIndex, looksLast, Op, prop, PropIndex, propShort, rope, runs, startNode, startNodeFirst, startNodeLast, terminalTextNode, terminalTextNodeFirst, terminalTextNodeLast, ThirdByte, TypeIndex],
FileReader   USING [Reply, FromRope, FromStream, Open, OpenC],
IO      USING [Handle],
NameSymbolTable  USING [MakeName, Name],
NodeProps   USING [DoSpecs, PutProp],
PGSupport   USING [CreatePGF, EnterLooks, EnterProp, EnterTypeName, FreePGF, PGF, RetrieveLooks, RetrieveProp, RetrieveTypeName],
PutGet    USING [SpanInfo, SpanInfoRec, MaxLen],
Rope     USING [Find, FromRefText, Lower, Size, Substr, Translate],
RopeReader   USING [Backwards, BumpIndex, Get, GetString, Position, ReadOffEnd, Ref, SetIndex],
RopeEdit    USING [ROPE, Substr],
SafeStorage   USING [SetCollectionInterval],
System    USING [GreenwichMeanTime],
TiogaLooks   USING [BaseRuns, Looks, Runs],
TiogaLooksOps  USING [Concat, LooksBytes],
TiogaLooksSupport  USING [NewBase, Short],
TiogaNode   USING [Offset, Node, Ref, RefBranchNode, RefTextNode],
TiogaNodeOps  USING [LookupItemID, NarrowToBranchNode, NewBranchNode, NewTextNode];
GetFileImpl: CEDAR MONITOR
IMPORTS Atom, CIFS, FileReader, NameSymbolTable, NodeProps, PGSupport, Rope, RopeEdit, RopeReader, SafeStorage, TiogaLooksOps, TiogaLooksSupport, TiogaNodeOps
EXPORTS PutGet = BEGIN
Byte: TYPE = [0..255];
FromFileError: PUBLIC ERROR = CODE;
FromFile: PUBLIC PROC [fileName: RopeEdit.ROPE, start: TiogaNode.Offset ← 0,
len: TiogaNode.Offset ← PutGet.MaxLen, okToMapFile: BOOLFALSE]
RETURNS
[root: TiogaNode.RefBranchNode] = BEGIN
Reads in a file, creating Tioga2 format
ForceLower: PROC [r: RopeEdit.ROPE] RETURNS [RopeEdit.ROPE] = {
ForceCharLower: SAFE PROC [old: CHAR] RETURNS [new: CHAR] = TRUSTED {
RETURN [Rope.Lower[old]] };
RETURN [Rope.Translate[base: r, translator: ForceCharLower]] };
reply:FileReader.Reply;
fh: CIFS.OpenFile;
createDate: System.GreenwichMeanTime;
dot:INTEGER;
ext:RopeEdit.ROPE;
GCBigInterval[];    -- set large GC interval
{ ENABLE UNWIND => {
 CIFS.Close[fh];
GCRestoreInterval[] -- restore original GC interval
};
[reply, fh, createDate]    -- read the file into a buffer
← FileReader.Open[fileName, start, len, okToMapFile];
root ← BuildTiogaStructure[reply] -- crack it!
};
CIFS.Close[fh];
Now put file wide attributes on root node
NodeProps.PutProp[root, $FileExtension,
IF (dot ← Rope.Find[fileName, "."]) > 0 AND
Rope.Size[ext ← Rope.Substr[fileName, dot+1]] > 0 THEN
Atom.MakeAtom[ForceLower[ext]]
ELSE
$null];
AddCreateDate[root, createDate]; -- to be fixed
GCRestoreInterval[]   -- restore original GC interval
END;
FromFileC: PUBLIC PROC [file: File.Capability, start: TiogaNode.Offset ← 0, len: TiogaNode.Offset ← PutGet.MaxLen, okToMapFile: BOOLFALSE]
RETURNS [root: TiogaNode.RefBranchNode] = {
reply:FileReader.Reply;
createDate: System.GreenwichMeanTime;
GCBigInterval[];
{ ENABLE UNWIND => GCRestoreInterval[];
[reply,createDate] ← FileReader.OpenC[file,start,len,okToMapFile];
root ← BuildTiogaStructure[reply]
};
AddCreateDate[root, createDate];
GCRestoreInterval[]
};
AddCreateDate: PROC [root: TiogaNode.RefBranchNode, createDate: System.GreenwichMeanTime] = {
NodeProps.PutProp[root, $FileCreateDate,
NEW[System.GreenwichMeanTime ← createDate]] };
FromRope: PUBLIC PROC [rope: RopeEdit.ROPE, start: TiogaNode.Offset ← 0, len: TiogaNode.Offset ← PutGet.MaxLen] RETURNS [root: TiogaNode.RefBranchNode] = {
GCBigInterval[];
{ ENABLE UNWIND => GCRestoreInterval[];
root ← BuildTiogaStructure[FileReader.FromRope[rope,start,len]]
};
GCRestoreInterval[]
};
FromStream: PUBLIC PROC [stream: IO.Handle, len: TiogaNode.Offset ← PutGet.MaxLen] RETURNS [root: TiogaNode.RefBranchNode] = {
GCBigInterval[];
{  ENABLE UNWIND => GCRestoreInterval[];
root ← BuildTiogaStructure[FileReader.FromStream[stream,len]]
};
GCRestoreInterval[]
};
BuildTiogaStructure: PROCEDURE [fileInfo:FileReader.Reply] RETURNS [root: TiogaNode.RefBranchNode] = {
Applies the appropriate parser to the ropes obtained from the file
SELECT fileInfo.fileType FROM
Tioga2 => { -- just create a stub and return
info:PutGet.SpanInfo ← NEW[PutGet.SpanInfoRec];
root ← TiogaNodeOps.NewBranchNode[];
root.internalRepCreated ← FALSE;
root.externalRepValid ← TRUE;
info.externalRepRope ← fileInfo.fileRope;
info.charsStart ← fileInfo.textStart;
info.charsLen ← fileInfo.textLen;
info.ctrlStart ← fileInfo.controlStart;
info.ctrlLen ← fileInfo.controlLen;
NodeProps.PutProp[root, $BranchInfo, info];
};
ENDCASE => root ← BuildT2FromT1[fileInfo.control, fileInfo.comment, fileInfo.text, fileInfo.fileType=Tioga1];
};
BuildT2FromT1: PROC [control, cmmnt, stext: RopeReader.Ref, tiogaFile: BOOL] RETURNS [rootBranch: TiogaNode.RefBranchNode] = {
op: FileOps.Op;
parentBranch, prevBranch, newBranch:TiogaNode.RefBranchNode;
newText: TiogaNode.RefTextNode;
terminalNode: BOOLEAN;
textLength, runsLength: TiogaNode.Offset ← 0;
typename: NameSymbolTable.Name;
propname: ATOM;
pgf: PGSupport.PGF ← PGSupport.CreatePGF[];
text: REF TEXTNEW[TEXT[32]];
GetAtom: PROC RETURNS [ATOM] = {
GetText[]; -- get the print name
RETURN [Atom.MakeAtom[Rope.FromRefText[text]]]
};
GetControlRope: PROC RETURNS [RopeEdit.ROPE] = {
Read a rope from the control stream
RETURN [GetRope[ReadLength[], control]]
};
GetName: PROC RETURNS [NameSymbolTable.Name] = {
GetText[];
RETURN [NameSymbolTable.MakeName[text]]
};
GetRope: PROC [len: TiogaNode.Offset, rdr: RopeReader.Ref] RETURNS [RopeEdit.ROPE] = {
rope: RopeEdit.ROPE;
pos: TiogaNode.Offset;
[rope,pos] ← RopeReader.Position[rdr];
RopeReader.SetIndex[rdr,pos+len];
RETURN [RopeEdit.Substr[rope,pos,len]]
};
GetText: PROC = {
len: NAT;
IF (len ← ReadByte[]) > text.maxLength THEN text ← NEW[TEXT[len]];
text.length ← 0;
text.length ← RopeReader.GetString[control, text, len]
};
InsertNode: PROC [nodeB: TiogaNode.RefBranchNode] = {
If there is an older sibling, then node is chained on. If there is no older sibling then the node is hung off the parent. If no parent then this is the root
IF prevBranch#NIL THEN {
prevBranch.next ← nodeB;   -- point sib at me
prevBranch.last ← FALSE;
nodeB.next ← parentBranch;   -- point to parent
prevBranch ← nodeB
}
ELSE
IF parentBranch#NIL THEN {
parentBranch.child ← nodeB;
nodeB.next ← parentBranch;   -- point to parent
prevBranch ← nodeB
}
ELSE {
parentBranch ← nodeB;
parentBranch.next ← NIL; -- root node has no next
prevBranch ← NIL;
};
};
NextOp: PROC RETURNS [op: FileOps.Op] = {
op ← RopeReader.Get[control
! RopeReader.ReadOffEnd => {
op ← FileOps.endOfFile;
CONTINUE
}
];
};
ReadByte: PROC RETURNS [Byte] = INLINE {
RETURN [LOOPHOLE[ReadChar[]]]
};
ReadChar: PROC RETURNS [CHARACTER] = {
RETURN [RopeReader.Get[control]]
};
ReadLength: PROC RETURNS [TiogaNode.Offset] = {
first, second, fourth: FileOps.LengthByte;
third: FileOps.ThirdByte;
card: FileOps.IntBytes;
first ← LOOPHOLE[ReadByte[]];
card.first ← first.data;
IF ~first.others THEN
RETURN [LOOPHOLE[card]];
second ← LOOPHOLE[ReadByte[]];
card.second ← second.data;
IF ~second.others THEN
RETURN [LOOPHOLE[card]];
third ← LOOPHOLE[ReadByte[]];
card.thirdBottom ← third.dataBottom;
card.thirdTop ← third.dataTop;
IF ~third.others THEN
RETURN [LOOPHOLE[card]];
fourth ← LOOPHOLE[ReadByte[]];
card.fourth ← fourth.data;
RETURN [LOOPHOLE[card]]
};
ReadProp: PROC = {
specs: RopeEdit.ROPE ← GetControlRope[];
value: REF ← NodeProps.DoSpecs[propname, specs, newBranch];
IF value # NIL THEN
NodeProps.PutProp[newBranch, propname, value]
};
GraftOnTextNode: PROCEDURE [] RETURNS [] = {
Attaches a tex node to the current branch contents field
newBranch.contents ← newText ← TiogaNodeOps.NewTextNode[]; -- hang stmt off brnch
newText.next ← newBranch; -- point to parent
newText.class ← TiogaNodeOps.LookupItemID[$Text];
};
-- BODY OF BuildTiogaStructure
terminalNode ← FALSE;
parentBranch ← NIL; -- means need to establish a root node
prevBranch ← NIL;   -- means no oldest child yet
op ← NextOp[];
DO
SELECT op FROM
IN [FileOps.terminalTextNodeFirst..FileOps.terminalTextNodeLast] => {
LEAF NODE - USING EARLIER FORMAT
typename ← PGSupport.RetrieveTypeName[LOOPHOLE[op-FileOps.terminalTextNodeFirst, FileOps.TypeIndex], pgf];
terminalNode ← TRUE
};
IN [FileOps.startNodeFirst..FileOps.startNodeLast] => {
BRANCH NODE - USING EARLIER FORMAT
typename ← PGSupport.RetrieveTypeName[LOOPHOLE[op-FileOps.startNodeFirst, FileOps.TypeIndex], pgf];
};
FileOps.endNode => {
END NODE - POP UP A LEVEL
IF prevBranch#NIL THEN {
prevBranch.last ← TRUE;
prevBranch.next ← parentBranch
};
prevBranch ← parentBranch;
IF (parentBranch ← TiogaNodeOps.NarrowToBranchNode[parentBranch.next])=NIL THEN EXIT;
op ← NextOp[];
LOOP
};
FileOps.startNode => {
BRANCH NODE - NEW TYPE OF FORMAT
typename ← GetName[];
[] ← PGSupport.EnterTypeName[typename,pgf]
};
FileOps.terminalTextNode => {
LEAF NODE - NEW TYPE OF FORMAT
typename ← GetName[];
[] ← PGSupport.EnterTypeName[typename,pgf];
terminalNode ← TRUE
};
FileOps.rope, FileOps.comment => {
TEXT OR COMMENTS
reader: RopeReader.Ref;
IF newText=NIL THEN GraftOnTextNode[];
IF textNode=NIL OR textNode#node THEN ERROR FromFileError;
IF op=FileOps.rope THEN reader ← stext ELSE { reader ← cmmnt; newText.comment ← TRUE };
IF (textLength←ReadLength[]) > 0 THEN -- get the rope
newText.rope ← GetRope[textLength,reader];
SELECT runsLength FROM
0     => NULL; -- no runs for this rope
textLength  => runsLength ← 0; -- correct length
ENDCASE  => ERROR FromFileError; -- mismatch
RopeReader.BumpIndex[reader,1]; -- skip CR at end of rope
op ← NextOp[];
LOOP
};
FileOps.runs => { -- runs, if any, come before corresponding rope
RUNS OF LOOKS
lookRuns: TiogaLooks.Runs;
numRuns: TiogaNode.Offset;
pos: TiogaNode.Offset ← 0;
IF textNode=NIL OR textNode#node THEN ERROR FromFileError;
IF newText=NIL THEN GraftOnTextNode[];
numRuns ← ReadLength[]; -- read number of runs
WHILE numRuns > 0 DO
num: NAT ← TiogaLooksSupport.Short[MIN[numRuns,LAST[NAT]]];
baseRuns: TiogaLooks.BaseRuns ← TiogaLooksSupport.NewBase[num];
len: TiogaNode.Offset ← pos;
numRuns ← numRuns-num;
FOR i:NAT IN [0..num) DO -- read runs for this baseRuns
looks: TiogaLooks.Looks;
ReadLookChars: PROC [num: NAT] = {
FOR i:NAT IN [0..num) DO looks[ReadChar[]] ← TRUE; ENDLOOP;
[] ← PGSupport.EnterLooks[looks,pgf] };
SELECT op ← NextOp[] FROM
IN [FileOps.looksFirst .. FileOps.looksLast] =>
looks ← PGSupport.RetrieveLooks[
LOOPHOLE[op-FileOps.looksFirst, FileOps.LooksIndex],pgf];
FileOps.look1 => ReadLookChars[1];
FileOps.look2 => ReadLookChars[2];
FileOps.look3 => ReadLookChars[3];
FileOps.looks => {
-- read 4 bytes of looks from control stream
lb: TiogaLooksOps.LooksBytes;
lb.byte0 ← ReadByte[]; lb.byte1 ← ReadByte[];
lb.byte2 ← ReadByte[]; lb.byte3 ← ReadByte[];
[] ← PGSupport.EnterLooks[looks ← LOOPHOLE[lb], pgf] };
ENDCASE => ERROR FromFileError;
baseRuns[i] ← [pos←pos+ReadLength[],looks];
ENDLOOP;
lookRuns ← IF lookRuns=NIL THEN baseRuns ELSE
TiogaLooksOps.Concat[lookRuns,baseRuns,len,pos-len];
ENDLOOP;
runsLength ← pos; -- for use in checking rope length
newText.runs ← lookRuns;
op ← NextOp[];
LOOP
};
FileOps.prop => {
NODE PROPERTIES - NEW SORT
[] ← PGSupport.EnterProp[propname ← GetAtom[], pgf];
ReadProp;
op ← NextOp[];
LOOP
};
FileOps.propShort => {
NODE PROPERTIES - OLD SORT
propname ← PGSupport.RetrieveProp[LOOPHOLE[ReadByte[], FileOps.PropIndex], pgf];
ReadProp;
op ← NextOp[];
LOOP
};
FileOps.endOfFile => {
END OF FILE
IF parentBranch=NIL THEN EXIT; -- have reached the root
[] ← RopeReader.Backwards[control]; -- backup so read endOfFile again
op ← FileOps.endNode;
LOOP
};
ENDCASE => ERROR FromFileError;
If reach here, then want to start a new branch node with a text node hung off it.
InsertNode[newBranch ← TiogaNodeOps.NewBranchNode[]]; -- hang off parent or elder sib.
newText ← NIL;
newBranch.format ← typename;
IF terminalNode THEN
terminalNode ← FALSE -- reset to default case
ELSE {
parentBranch ← newBranch;
prevBranch ← NIL
};
op ← NextOp[];
ENDLOOP;
IF (rootBranch ← prevBranch)=NIL THEN -- don't have a normal tree
ERROR;
IF newBranch=NIL THEN rootBranch ← TiogaNodeOps.qZone.NEW[TextBody] -- null file
ELSE root ← node; -- single node in file
rootBranch.last ← TRUE;
NodeProps.PutProp[rootBranch, $FromTiogaFile, IF tiogaFile THEN $Yes ELSE $No];
PGSupport.FreePGF[pgf]
};
Set GC interval
collectionInterval: LONG CARDINAL;
bigCollectionInterval: LONG CARDINAL = 1000000;
startCount: INTEGER ← 0;
GCBigInterval: PUBLIC ENTRY PROC = {
ENABLE UNWIND => NULL;
IF startCount = 0 THEN {
SafeStorage.ReclaimCollectibleObjects[];
collectionInterval ← SafeStorage.SetCollectionInterval[bigCollectionInterval] };
startCount ← startCount+1
};
GCRestoreInterval: PUBLIC ENTRY PROC = { -- restore initial collectionInterval when all Get's done
ENABLE UNWIND => NULL;
IF (startCount ← startCount-1) = 0 THEN
[] ← SafeStorage.SetCollectionInterval[collectionInterval] };
END.
Edited on March 14, 1983 10:26 am, by Lamming
Forced T1 branches to have changed flag set to force writer to ignore T1 structure
changes to: BuildT2FromT1
Edited on March 21, 1983 3:07 pm, by Lamming
changes to: DIRECTORY, InsertNode
Edited on March 30, 1983 10:11 am, by Lamming
changes to: DIRECTORY
Edited on March 31, 1983 2:35 pm, by Lamming
changes to: DIRECTORY, ForceLower (local of FromFile), FromFile, FromFileC, FromRope, FromStream, BuildTiogaStructure, BuildT2FromT2
Edited on May 3, 1983 8:13 am, by Sosinski
changes to: BuildTiogaStructure, DIRECTORY, GetFileImpl
Edited on May 5, 1983 5:29 pm, by Lamming
changes to: DIRECTORY, GetAtom, GetControlRope, GetName, GetRope, GetText, InsertNode, ReadChar, ReadLength, GraftOnTextNode, BuildTiogaStructure
Edited on May 24, 1983 5:24 pm, by Lamming
changes to: DIRECTORY, BuildTiogaStructure, GraftOnTextNode
Edited on May 31, 1983 1:03 pm, by Lamming
changes to: BuildTiogaStructure
Edited on June 2, 1983 10:30 am, by Lamming
changes to: DIRECTORY, BuildTiogaStructure, GetFileImpl