DIRECTORY Ascii USING [Lower], Atom USING [MakeAtom, MakeAtomFromRefText], BasicTime USING [GMT], FileOps USING [comment, endNode, endOfFile, IntBytes, LengthByte, look1, look2, look3, looks, looksFirst, LooksIndex, looksLast, Op, otherNode, otherNodeShort, otherNodeSpecs, otherNodeSpecsShort, prop, PropIndex, propShort, rope, runs, startNode, startNodeFirst, startNodeLast, terminalTextNode, terminalTextNodeFirst, terminalTextNodeLast, ThirdByte, FormatIndex], FileReader USING [FromRope, FromStream, InterDoc, Open, OpenC], FS USING [ComponentPositions, ExpandName, GetName, OpenFile, Position], InterFile USING [FromRope], IO USING [STREAM], NodeProps USING [DoSpecs, PutProp], PGSupport USING [BadIndex, CreatePGF, EnterLooks, EnterProp, EnterFormatName, FreePGF, PGF, RetrieveLooks, RetrieveProp, RetrieveFormatName], PutGet USING [], Rope USING [MaxLen, ROPE, Substr, Translate], RopeEdit USING [MaxLen, Substr], RopeReader USING [Backwards, BumpIndex, Get, GetRope, Position, ReadOffEnd, Ref, SetIndex], RuntimeError USING [UNCAUGHT], SafeStorage USING [SetCollectionInterval], TextEdit USING [], TextLooks USING [BaseRuns, Concat, Looks, LooksBytes, Runs], TextLooksSupport USING [NewBase, Short], TextNode USING [Body, MaxLen, Ref, RefTextNode]; GetFileImpl: CEDAR MONITOR IMPORTS Ascii, Atom, FileReader, FS, InterFile, NodeProps, PGSupport, Rope, RopeEdit, RopeReader, RuntimeError, SafeStorage, TextLooks, TextLooksSupport EXPORTS PutGet SHARES TextLooks = BEGIN OPEN FileOps; ROPE: TYPE = Rope.ROPE; Byte: TYPE = [0..255]; FromFileError: PUBLIC ERROR = CODE; FromFile: PUBLIC PROC [fileName: ROPE, start: INT _ 0, len: INT _ TextNode.MaxLen] RETURNS [root: TextNode.Ref] = { control, comment, stext: RopeReader.Ref; interdoc: ROPE; tiogaFile: BOOL; fh: FS.OpenFile; createDate: BasicTime.GMT; StartRead[]; { ENABLE UNWIND => 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]; }; AddFileExtension[root, fh]; AddCreateDate[root, createDate]; EndRead[]; }; FromFileC: PUBLIC PROC [file: FS.OpenFile, start: INT _ 0, len: INT _ TextNode.MaxLen] RETURNS [root: TextNode.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]; }; AddFileExtension[root, file]; AddCreateDate[root, createDate]; EndRead[]; }; AddFileExtension: PROC [root: TextNode.Ref, file: FS.OpenFile] = { ForceLower: PROC [r: ROPE] RETURNS [ROPE] = { ForceCharLower: PROC [old: CHAR] RETURNS [new: CHAR] = { RETURN [Ascii.Lower[old]]; }; RETURN [Rope.Translate[base: r, translator: ForceCharLower]]; }; name: ROPE; cp: FS.ComponentPositions; [fullFName: name, cp: cp] _ FS.ExpandName[name: FS.GetName[file].fullFName]; NodeProps.PutProp[root, $FileExtension, IF cp.ext.length=0 THEN $null ELSE Atom.MakeAtom[ForceLower[name.Substr[cp.ext.start, cp.ext.length]]]]; }; AddCreateDate: PROC [root: TextNode.Ref, createDate: BasicTime.GMT] = { NodeProps.PutProp[root, $FileCreateDate, NEW[BasicTime.GMT _ createDate]]; }; FromRope: PUBLIC PROC [rope: ROPE, start: INT _ 0, len: INT _ TextNode.MaxLen] RETURNS [root: TextNode.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: INT _ TextNode.MaxLen] RETURNS [root: TextNode.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: TextNode.Ref] = { op: Op; parent, node, prev: TextNode.Ref; textNode: TextNode.RefTextNode; terminalNode: BOOL; textLength, runsLength: INT _ 0; formatName: ATOM; propname: ATOM; charProps: REF _ NIL; charSets: REF _ NIL; InsertNode: PROC [node: TextNode.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 [CHAR] = { RETURN [RopeReader.Get[control]]; }; ReadProp: PROC = { specs: ROPE _ GetControlRope[]; disaster: BOOL _ FALSE; value: REF; value _ NodeProps.DoSpecs[propname, specs ! RuntimeError.UNCAUGHT => {disaster_TRUE} ]; IF disaster THEN ERROR FromFileError; IF value # NIL THEN { IF propname = $CharProps THEN charProps _ value ELSE IF propname = $CharSets THEN charSets _ value ELSE NodeProps.PutProp[node, propname, value]; }; }; GetRope: PROC [len: INT, rdr: RopeReader.Ref] RETURNS [ROPE] = { rope: ROPE; pos: INT; [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 _ NEW[TEXT[len]]; FOR i: NAT IN [0..len) DO text[i] _ RopeReader.Get[control]; ENDLOOP; text.length _ len; }; GetAtom: PROC RETURNS [ATOM] = { GetText[]; -- get the print name RETURN [IF text.length = 0 THEN NIL ELSE Atom.MakeAtomFromRefText[text]]; }; ReadLength: PROC RETURNS [INT] = { 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] = { op _ RopeReader.Get[control ! RopeReader.ReadOffEnd => { op _ endOfFile; CONTINUE }]; }; pgf: PGSupport.PGF _ PGSupport.CreatePGF[]; text: REF TEXT _ NEW[TEXT[32]]; terminalNode _ FALSE; op _ NextOp[]; DO SELECT op FROM IN [terminalTextNodeFirst..terminalTextNodeLast] => { formatName _ PGSupport.RetrieveFormatName[ LOOPHOLE[op-terminalTextNodeFirst, FormatIndex], pgf ! PGSupport.BadIndex => ERROR FromFileError ]; terminalNode _ TRUE; }; IN [startNodeFirst..startNodeLast] => formatName _ PGSupport.RetrieveFormatName[ LOOPHOLE[op-startNodeFirst, FormatIndex], pgf ! PGSupport.BadIndex => ERROR FromFileError ]; endNode => { IF prev#NIL THEN { prev.last _ TRUE; prev.next _ parent;}; prev _ parent; IF (parent _ parent.next)=NIL THEN EXIT; op _ NextOp[]; LOOP; }; startNode => { formatName _ GetAtom[]; [] _ PGSupport.EnterFormatName[formatName, pgf]; }; terminalTextNode => { formatName _ GetAtom[]; [] _ PGSupport.EnterFormatName[formatName, 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]; IF charProps#NIL THEN {NodeProps.PutProp[node,$CharProps,charProps]; charProps_NIL}; IF charSets#NIL THEN {NodeProps.PutProp[node, $CharSets, charSets]; charSets _ NIL}; 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: INT; pos: INT _ 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: INT _ 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 ! PGSupport.BadIndex => ERROR FromFileError ] }; look1 => ReadLookChars[1]; look2 => ReadLookChars[2]; look3 => ReadLookChars[3]; FileOps.looks => { 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 ! PGSupport.BadIndex => ERROR FromFileError ]; ReadProp; op _ NextOp[]; LOOP; }; otherNode, otherNodeShort, otherNodeSpecs, otherNodeSpecsShort => { ERROR FromFileError; }; 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 charProps # NIL OR charSets # NIL THEN ERROR FromFileError; InsertNode[node _ textNode _ NEW[TextNode.Body]]; node.formatName _ formatName; 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 _ NEW[TextNode.Body] -- null file ELSE root _ node; -- single node in file root.last _ TRUE; NodeProps.PutProp[root, $FromTiogaFile, IF tiogaFile THEN $Yes ELSE $No]; PGSupport.FreePGF[pgf]; }; END. rGetFileImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. written by Paxton. January 1981 Paxton. December 1, 1982 9:44 am Russ Atkinson, June 18, 1984 8:29:12 pm PDT Paul Rovner, August 10, 1983 4:28 pm Doug Wyatt, March 3, 1985 5:09:00 pm PST Michael Plass, March 29, 1985 2:10:32 pm PST Rick Beach, March 28, 1985 9:46:42 am PST The character properties and character sets are not stored in the node until after the rope is stored, so that NodePropsImpl can do its consistency check. MAIN PROGRAM read 4 bytes of looks from control stream if reach here, then want to start a new text node Κ Ϊ˜codešœ™Kšœ Οmœ7™BKšœ ™ Kšœ ™ Kšœ+™+Kšœ$™$Kšœ(™(Kšœ,™,K™)—K˜šΟk ˜ Kšœžœ ˜Kšœžœ"˜,Kšœ žœžœ˜Kšœžœβ˜οKšœ žœ0˜@Kšžœžœ@˜HKšœ žœ ˜Kšžœžœžœ˜Kšœ žœ˜$Kšœ žœHžœ4˜ŽKšœžœ˜Kšœžœ žœ˜.Kšœ žœ˜!Kšœ žœL˜\Kšœ žœžœ˜Kšœ žœ˜+Kšœ žœ˜Kšœ žœ.˜=Kšœžœ˜)Kšœ žœ"˜0—K˜KšΠbl œžœž˜Kšžœžœu˜˜Kšžœ˜Kšžœ ˜šœžœžœ ˜K˜Kšžœžœžœ˜Kšœžœ ˜Kšœžœžœžœ˜#šΟnœžœžœ žœ žœ žœžœ˜sK˜(Kšœ žœ˜Kšœ žœ˜Kšœžœ ˜Kšœžœ˜K˜ šœžœžœ˜˜6˜&Kšœ)žœ˜3——šœžœ žœžœ˜8Kšžœ,˜0—K˜—K˜K˜ K˜ K˜—K˜š   œžœžœžœžœ žœ˜VKšžœ˜ K˜(Kšœ žœ˜Kšœ žœ˜Kšœžœ˜K˜ šœžœžœ˜˜VKšœ)žœ˜3—šœžœ žœžœ˜8Kšžœ,˜0—K˜—K˜K˜ K˜ K˜K˜—š œžœžœ˜Bš   œžœžœžœžœ˜-š  œžœžœžœžœ˜8Kšžœ˜K˜—Kšžœ7˜=K˜—Kšœžœžœ˜&Kšœžœžœ˜Lšœ(žœžœ˜EKšžœF˜J—K˜—K˜š  œžœ,žœ˜Gšœ)˜)Kšžœ žœ˜!—K˜—K˜Kš œžœž˜š œžœ žœ žœžœ˜YK˜(Kšœ žœ˜Kšœ žœ˜K˜ šœžœžœ˜˜MKšœ)žœ˜3—šœžœ žœžœ˜8Kšžœ,˜0—K˜—K˜ K˜—K˜Kš  œžœž˜š œ žœžœžœžœ˜PK˜(Kšœ žœ˜Kšœ žœ˜K˜ šœžœžœ˜˜JKšœ)žœ˜3—šœžœ žœžœ˜8Kšžœ,˜0—K˜—K˜ K˜—K˜Kšœžœžœ˜"Kšœžœžœ ˜/Kšœ žœ˜š  œžœžœ˜Kšžœžœžœ˜šžœžœ˜K˜NK˜—K˜K˜—K˜š œžœžœΟc9˜QKšžœžœžœ˜Kšžœ!ž˜'K˜;K˜—K˜š œžœ4žœžœ˜fK˜K˜K˜!K˜Kšœžœ˜Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜Kšœ žœžœ˜Kšœ žœžœ˜K˜š  œžœ˜)šžœžœžœ˜!Kšžœžœžœžœ˜,—K˜ K˜—K˜š œžœžœ žœ˜(Kšžœžœ˜K˜—K˜š œžœžœžœ˜!Kšžœ˜!K˜—K˜š œžœ˜Kšœžœ˜Kšœ žœžœ˜Kšœžœ˜ šœ+˜+Kšœ žœžœ˜(Kšœ˜—Kšžœ žœžœ˜&šžœ žœžœ˜J™šJšžœžœ˜/Jšžœžœžœ˜2Jšžœ*˜.Jšœ˜—K˜—K˜š  œžœžœžœžœ˜@Kšœžœ˜ Kšœžœ˜ K˜'K˜"Kšžœ#˜)K˜—K˜š œžœžœžœ˜'Kšžœ"˜(K˜—K˜š œžœ˜Kšœžœ˜ Kšžœ%žœžœžœ˜Bšžœžœžœ ž˜Kšœ"˜"Kšžœ˜—Kšœ˜K˜—K˜š œžœžœžœ˜ Kšœ ‘˜ Kš žœžœžœžœžœ!˜IK˜—K˜š  œžœžœžœ˜"K˜"K˜K˜Kšœžœ ˜K˜Kšžœžœžœžœ˜.Kšœ žœ ˜K˜Kšžœžœžœžœ˜/Kšœžœ ˜K˜$K˜Kšžœžœžœžœ˜.Kšœ žœ ˜K˜Kšžœžœ˜K˜—K˜š œžœžœ˜"K˜KšœIžœ˜UK˜—K˜Kšœ ™ Kšœžœ˜+Kš œžœžœžœžœ˜K˜Kšœžœ˜K˜šž˜šžœž˜šžœ3˜5šœ*˜*Kšžœ,˜4Kšœžœ˜+Kšœ˜—Kšœžœ˜K˜—Kšžœ#˜%šœ*˜*Kšžœ%˜-Kšœžœ˜+Kšœ˜—˜ Kšžœžœžœžœ˜:K˜Kšžœžœžœžœ˜(Kšœžœ˜K˜—˜K˜K˜0K˜—˜K˜K˜0Kšœžœ˜K˜—˜K˜Kšžœ žœžœ&žœ˜PKš žœ žœžœžœžœ˜:šžœžœ‘˜6K˜,—Kšžœ žœžœ:žœ˜TKšžœ žœžœ;žœ˜Tšžœ ž˜Kšœžœ‘˜#Kšœ‘˜/Kšžœžœ‘ ˜+—Kšœ!‘˜:Kšœžœ˜K˜—šœ ‘/˜9K˜Kšœ žœ˜ Kšœžœ˜ Kš žœ žœžœžœžœ˜:Kšœ‘˜.šžœ ž˜Kš œžœžœ žœžœ˜;K˜=Kšœžœ˜K˜š žœžœžœ žœ‘˜7K˜š  œžœžœ˜"Kš žœžœžœ žœžœžœ˜;K˜&K˜—šžœž˜šžœ˜!šœ ˜ Kšžœ ˜(Kšœžœ˜+Kšœ˜—Kšœ˜—K˜K˜K˜˜Kšœ)™)K˜K˜-K˜-Kšœ"žœ ˜5K˜—Kšžœžœ˜—K˜,Kšžœ˜—Kšœ žœ žœžœ ž˜-K˜3Kšžœ˜—Kšœ‘"˜4K˜Kšœžœ˜K˜—˜ K˜4K˜ Kšœžœ˜K˜—˜šœ"˜"Kšžœ˜$Kšœžœ˜+Kšœ˜—K˜ Kšœžœ˜K˜—šœC˜CKšžœ˜K˜—˜Kš žœžœžœžœ‘˜1Kšœ$‘!˜EKšœžœ˜K˜—Kšžœžœ˜—Kšœ1™1Kš žœ žœžœ žœžœžœ˜>Kšœžœ˜1K˜Kšžœžœž˜)Kšžœ-žœ˜7K˜Kšžœ˜—Kšžœžœžœ‘˜5š žœžœžœžœ‘ ˜7Kšžœ‘˜(—Kšœ žœ˜Kšœ(žœ žœžœ˜IK˜K˜—K˜—Kšžœ˜—…—+τ<@