GetFileImpl.Mesa
written by Paxton. January 1981
Paxton. December 1, 1982 9:44 am
Russ Atkinson, September 13, 1983 5:02 pm
Paul Rovner, August 10, 1983 4:28 pm
Doug Wyatt, December 5, 1983 2:37 pm
DIRECTORY
Ascii,
Atom,
BasicTime,
FS USING [nullOpenFile, OpenFile],
FileOps,
FileReader,
GetFile,
InterFile,
IO,
NameSymbolTable,
NodeProps,
OtherNode,
PGSupport,
PutGet,
Rope,
RopeEdit,
RopeReader,
SafeStorage,
TextEdit,
TextLooks,
TextLooksSupport,
TextNode;
GetFileImpl: CEDAR MONITOR
IMPORTS
Ascii, Atom, FileReader, InterFile, NameSymbolTable, npI:NodeProps, OtherNode, PGSupport, Rope, RopeEdit, RopeReader, SafeStorage, TextLooks, TextLooksSupport, TextNode
EXPORTS PutGet, GetFile
SHARES TextLooks
= BEGIN OPEN PutGet, GetFile, TextNode;
Byte: TYPE = [0..255];
FromFileError: PUBLIC ERROR = CODE;
FromFile: PUBLIC PROC
[fileName: ROPE, start: Offset ← 0, len: Offset ← MaxLen] RETURNS [root: Ref] = {
control, comment, stext: RopeReader.Ref;
interdoc, ext: ROPE;
tiogaFile: BOOL;
dot: INT;
ForceLower: PROC [r: ROPE] RETURNS [ROPE] = {
ForceCharLower: SAFE PROC [old: CHAR] RETURNS [new: CHAR] = TRUSTED {
RETURN [Ascii.Lower[old]] };
RETURN [Rope.Translate[base: r, translator: ForceCharLower]] };
fh: FS.OpenFile;
createDate: BasicTime.GMT;
StartRead[];
{ ENABLE UNWIND => { IF fh # FS.nullOpenFile THEN EndRead[] };
[control,comment,stext,tiogaFile,fh,createDate] ←
FileReader.Open[fileName,start,len !
FileReader.InterDoc => { interdoc ← doc; RESUME }];
root ← IF interdoc#NIL THEN InterFile.FromRope[interdoc]
ELSE Finish[control,comment,stext,tiogaFile] };
npI.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];
EndRead[];
};
FromFileC: PUBLIC PROC [file: FS.OpenFile, start: Offset ← 0, len: Offset ← MaxLen]
RETURNS [root: Ref] = {
control, comment, stext: RopeReader.Ref;
interdoc: ROPE;
tiogaFile: BOOL;
createDate: BasicTime.GMT;
StartRead[];
{ ENABLE UNWIND => EndRead[];
[control,comment,stext,tiogaFile,createDate] ← FileReader.OpenC[file,start,len !
FileReader.InterDoc => { interdoc ← doc; RESUME }];
root ← IF interdoc#NIL THEN InterFile.FromRope[interdoc]
ELSE Finish[control,comment,stext,tiogaFile] };
AddCreateDate[root, createDate];
EndRead[];
};
AddCreateDate: PROC [root: Ref, createDate: BasicTime.GMT] = {
npI.PutProp[root, $FileCreateDate,
TextNode.pZone.NEW[BasicTime.GMT ← createDate]];
};
FromRope: PUBLIC PROC
[rope: ROPE, start: Offset ← 0, len: Offset ← MaxLen] RETURNS [root: Ref] = {
control, comment, stext: RopeReader.Ref;
interdoc: ROPE;
tiogaFile: BOOL;
StartRead[];
{ ENABLE UNWIND => EndRead[];
[control,comment,stext,tiogaFile] ← FileReader.FromRope[rope,start,len !
FileReader.InterDoc => { interdoc ← doc; RESUME }];
root ← IF interdoc#NIL THEN InterFile.FromRope[interdoc]
ELSE Finish[control,comment,stext,tiogaFile] };
EndRead[];
};
FromStream: PUBLIC PROC
[stream: IO.STREAM, len: Offset ← MaxLen] RETURNS [root: Ref] = {
control, comment, stext: RopeReader.Ref;
interdoc: ROPE;
tiogaFile: BOOL;
StartRead[];
{ ENABLE UNWIND => EndRead[];
[control,comment,stext,tiogaFile] ← FileReader.FromStream[stream,len !
FileReader.InterDoc => { interdoc ← doc; RESUME }];
root ← IF interdoc#NIL THEN InterFile.FromRope[interdoc]
ELSE Finish[control,comment,stext,tiogaFile] };
EndRead[];
};
collectionInterval: LONG CARDINAL;
bigCollectionInterval: LONG CARDINAL = 1000000;
startCount: INTEGER ← 0;
StartRead: ENTRY PROC = {
ENABLE UNWIND => NULL;
IF startCount = 0 THEN {
collectionInterval ← SafeStorage.SetCollectionInterval[bigCollectionInterval];
};
startCount ← startCount+1
};
EndRead: ENTRY PROC = { -- restore initial collectionInterval when all Get's done
ENABLE UNWIND => NULL;
IF (startCount ← startCount-1) = 0 THEN
[] ← SafeStorage.SetCollectionInterval[collectionInterval];
};
Finish: PROC [control, cmmnt, stext: RopeReader.Ref, tiogaFile: BOOL] RETURNS [root: Ref] = {
OPEN FileOps;
op: Op;
parent, node, prev: Ref;
textNode: RefTextNode;
othrNode: RefOtherNode;
terminalNode: BOOLEAN;
textLength, runsLength: Offset ← 0;
typename: TypeName;
propname: ATOM;
InsertNode: PROC [node: Ref] = {
IF prev#NIL THEN prev.next ← node
ELSE IF parent#NIL THEN parent.child ← node;
prev ← node };
ReadByte: PROC RETURNS [Byte] = INLINE {
RETURN [LOOPHOLE[ReadChar[]]] };
ReadChar: PROC RETURNS [CHARACTER] = {
RETURN [RopeReader.Get[control]] };
MakeOtherNode: PROC = {
InsertNode[node ← othrNode ← qZone.NEW[OtherBody]];
node.typename ← typename;
node.next ← parent; parent ← node; prev ← NIL };
OtherNodeSpecs: PROC = {
IF othrNode=NIL OR othrNode#node THEN ERROR FromFileError;
othrNode.variety ← propname;
OtherNode.DoSpecs[othrNode,GetControlRope[]] };
ReadProp: PROC = {
specs: ROPE ← GetControlRope[];
value: REF ← npI.DoSpecs[propname,specs];
IF value # NIL THEN npI.PutProp[node,propname,value] };
GetRope: PROC [len: Offset, rdr: RopeReader.Ref] RETURNS [ROPE] = {
rope: ROPE;
pos: Offset;
[rope,pos] ← RopeReader.Position[rdr];
RopeReader.SetIndex[rdr,pos+len];
RETURN [RopeEdit.Substr[rope,pos,len]] };
GetControlRope: PROC RETURNS [ROPE] = {
RETURN [GetRope[ReadLength[],control]] };
GetText: PROC = {
len: NAT;
IF (len ← ReadByte[]) > text.maxLength THEN text ← pZone.NEW[TEXT[len]];
text.length ← 0;
text.length ← RopeReader.GetString[control, text, len] };
GetAtom: PROC RETURNS [ATOM] = {
GetText[]; -- get the print name
RETURN [Atom.MakeAtom[Rope.FromRefText[text]]] };
GetName: PROC RETURNS [NameSymbolTable.Name] = {
GetText[]; RETURN [NameSymbolTable.MakeName[text]] };
ReadLength: PROC RETURNS [Offset] = {
first, second, fourth: LengthByte;
third: ThirdByte;
card: 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]] };
NextOp: PROC RETURNS [op: Op] = {
OPEN RopeReader;
op ← Get[control ! ReadOffEnd => { op ← endOfFile; CONTINUE }] };
-- MAIN PROGRAM
pgf: PGSupport.PGF ← PGSupport.CreatePGF[];
text: REF TEXT ← pZone.NEW[TEXT[32]];
terminalNode ← FALSE;
op ← NextOp[];
DO
SELECT op FROM
IN [terminalTextNodeFirst..terminalTextNodeLast] => {
typename ← PGSupport.RetrieveTypeName[
LOOPHOLE[op-terminalTextNodeFirst, TypeIndex], pgf];
terminalNode ← TRUE };
IN [startNodeFirst..startNodeLast] =>
typename ← PGSupport.RetrieveTypeName[
LOOPHOLE[op-startNodeFirst, TypeIndex], pgf];
endNode => {
IF prev#NIL THEN { prev.last ← TRUE; prev.next ← parent };
prev ← parent;
IF (parent ← parent.next)=NIL THEN EXIT;
op ← NextOp[]; LOOP };
startNode => {
typename ← GetName[];
[] ← PGSupport.EnterTypeName[typename,pgf] };
terminalTextNode => {
typename ← GetName[];
[] ← PGSupport.EnterTypeName[typename,pgf];
terminalNode ← TRUE };
rope, comment => {
reader: RopeReader.Ref;
IF op=rope THEN reader ← stext ELSE { reader ← cmmnt; textNode.comment ← TRUE };
IF textNode=NIL OR textNode#node THEN ERROR FromFileError;
IF (textLength←ReadLength[]) > 0 THEN -- get the rope
textNode.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 };
runs => { -- runs, if any, come before corresponding rope
lookRuns: TextLooks.Runs;
numRuns: Offset;
pos: Offset ← 0;
IF textNode=NIL OR textNode#node THEN ERROR FromFileError;
numRuns ← ReadLength[]; -- read number of runs
WHILE numRuns > 0 DO
num: NAT ← TextLooksSupport.Short[MIN[numRuns,LAST[NAT]]];
baseRuns: TextLooks.BaseRuns ← TextLooksSupport.NewBase[num];
len: Offset ← pos;
numRuns ← numRuns-num;
FOR i:NAT IN [0..num) DO -- read runs for this baseRuns
looks: TextLooks.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 [looksFirst .. looksLast] =>
looks ← PGSupport.RetrieveLooks[
LOOPHOLE[op-looksFirst,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: TextLooks.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
TextLooks.Concat[lookRuns,baseRuns,len,pos-len];
ENDLOOP;
runsLength ← pos; -- for use in checking rope length
textNode.runs ← lookRuns;
op ← NextOp[]; LOOP };
prop => {
[] ← PGSupport.EnterProp[propname ← GetAtom[], pgf];
ReadProp;
op ← NextOp[]; LOOP };
propShort => {
propname ← PGSupport.RetrieveProp[LOOPHOLE[ReadByte[],PropIndex], pgf];
ReadProp;
op ← NextOp[]; LOOP };
otherNode => {
typename ← GetName[];
[] ← PGSupport.EnterTypeName[typename, pgf];
MakeOtherNode;
op ← NextOp[]; LOOP };
otherNodeShort => {
typename ← PGSupport.RetrieveTypeName[
LOOPHOLE[ReadByte[],TypeIndex], pgf];
MakeOtherNode;
op ← NextOp[]; LOOP };
otherNodeSpecs => {
[] ← PGSupport.EnterProp[propname ← GetAtom[], pgf];
OtherNodeSpecs;
op ← NextOp[]; LOOP };
otherNodeSpecsShort => {
propname ← PGSupport.RetrieveProp
[LOOPHOLE[ReadByte[],PropIndex], pgf];
OtherNodeSpecs;
op ← NextOp[]; LOOP };
endOfFile => {
IF parent=NIL THEN EXIT; -- have reached the root
[] ← RopeReader.Backwards[control]; -- backup so read endOfFile again
op ← endNode; LOOP };
ENDCASE => ERROR FromFileError;
-- if reach here, then want to start a new text node
InsertNode[node ← textNode ← qZone.NEW[TextBody]];
node.typename ← typename;
IF terminalNode THEN terminalNode ← FALSE
ELSE { node.next ← parent; parent ← node; prev ← NIL };
op ← NextOp[];
ENDLOOP;
IF (root ← prev)=NIL THEN -- don't have a normal tree
IF node=NIL THEN root ← qZone.NEW[TextBody] -- null file
ELSE root ← node; -- single node in file
root.last ← TRUE;
npI.PutProp[root, $FromTiogaFile, IF tiogaFile THEN $Yes ELSE $No];
PGSupport.FreePGF[pgf];
};
StartGetFile: PUBLIC PROC = {
};
END.