<> <> <> DIRECTORY Atom USING [MakeAtom], IO USING [atom, bool, card, char, CreateViewerStreams, PutChar, PutF, rope, STREAM], NameSymbolTable USING [MakeName, MakeNameFromRope], NodeProps USING [DoSpecs, GetProp, PutProp], PutGet, Rope USING [ROPE, Substr], RopeEdit USING [Concat, Substr], RopeReader USING [Backwards, BumpIndex, FreeRopeReader, Get, GetIndex, GetRopeReader, GetString, Position, Ref, SetIndex, SetPosition], T2FileOps USING [addLooksFirst, addLooksLast, cmt, comment, default, fmt, format, heavyDuty, IntBytes, itemSpace, lastLooksFirst, lastLooksLast, LengthByte, noClassData, noLooks, Op, prop, runs, startBI, startBranch, startBX, startClassData, startLI, startTI, ThirdByte], TiogaLooks USING [BaseRuns, Look, Looks, noLooks, Runs], TiogaLooksOps USING [Concat], TiogaLooksSupport USING [Short, NewBase], TiogaBasicClass USING [BasicClass], TiogaItemClass USING [ItemClass], TiogaNode USING [Name, Offset, Ref, RefBranchNode, RefItemNode, RefTextNode, RefBoxNode, RefBasicNode, RefListNode], TiogaNodeOps USING [FetchBasicClass, FetchItemClass, LookupBasicID, LookupItemID, NewBasicNode, NewBranchNode, NewBoxNode, NewListNode, NewTextNode]; GetT2FileImpl: CEDAR PROGRAM IMPORTS Atom, IO, NameSymbolTable, NodeProps, PutGet, Rope, RopeEdit, RopeReader, TiogaLooksOps, TiogaLooksSupport, TiogaNodeOps EXPORTS PutGet = BEGIN Debug:BOOLEAN = FALSE; -- says if to generate trace info. report:IO.STREAM; -- trace info. stream Tioga2FileFormatError: PUBLIC SIGNAL = CODE; -- raised for all format faults ClassNotAvailable: PUBLIC SIGNAL = CODE; -- raised when item class not registered NoBranchParseInfo: PUBLIC SIGNAL = CODE; -- raised when client does not supply BranchInfo CreateInternalRep: PUBLIC PROC [br:TiogaNode.RefBranchNode, wholeTree:BOOLEAN_FALSE] = { <> brInfo:PutGet.SpanInfo _ NARROW[NodeProps.GetProp[br, $BranchInfo]]; copy:PutGet.SpanInfo; control:RopeReader.Ref _ RopeReader.GetRopeReader[]; PutGet.GCBigInterval[]; IF wholeTree THEN { <> copy _ NEW[PutGet.SpanInfoRec]; copy^ _ brInfo^; }; CIR[ br:br, brInfo:IF wholeTree THEN copy ELSE brInfo, wholeTree:wholeTree, indent:0, textBuffer: NEW[TEXT[32]], control:control]; RopeReader.FreeRopeReader[control]; PutGet.GCRestoreInterval[] }; CIR: PROCEDURE [br:TiogaNode.RefBranchNode, brInfo:PutGet.SpanInfo, wholeTree:BOOLEAN, indent:CARDINAL, textBuffer:REF TEXT, control:RopeReader.Ref] = { <> -- branch ::= optCmt {prop} optFormat {item} lastItem {child} {childHK} startHK nchild ; <<>> Indent: PROCEDURE [] = { <> FOR i:CARDINAL IN [1..indent] DO IO.PutChar[report, ' ]; ENDLOOP }; NextOp: PROC RETURNS [T2FileOps.Op] = INLINE { <> RETURN[RopeReader.Get[control]]; }; ReadB32: PROCEDURE [] RETURNS [n:INT] = { <> first, second, fourth: T2FileOps.LengthByte; third: T2FileOps.ThirdByte; card: T2FileOps.IntBytes; first _ LOOPHOLE[RopeReader.Backwards[control]]; card.first _ first.data; IF ~first.others THEN -- value within 7 bits so terminate RETURN [LOOPHOLE[card]]; second _ LOOPHOLE[RopeReader.Backwards[control]]; card.second _ second.data; IF ~second.others THEN -- value within 14 bits so terminate RETURN [LOOPHOLE[card]]; third _ LOOPHOLE[RopeReader.Backwards[control]]; card.thirdBottom _ third.dataBottom; card.thirdTop _ third.dataTop; IF ~third.others THEN -- value within 21 bits so terminate RETURN [LOOPHOLE[card]]; fourth _ LOOPHOLE[RopeReader.Backwards[control]]; card.fourth _ fourth.data; RETURN [LOOPHOLE[card]] -- full 28 bit value }; ReadF32: PROCEDURE [] RETURNS [n:INT] = { <> first, second, fourth: T2FileOps.LengthByte; third: T2FileOps.ThirdByte; card: T2FileOps.IntBytes; first _ LOOPHOLE[RopeReader.Get[control]]; card.first _ first.data; IF ~first.others THEN -- value within 7 bits so terminate RETURN [LOOPHOLE[card]]; second _ LOOPHOLE[RopeReader.Get[control]]; card.second _ second.data; IF ~second.others THEN -- value within 14 bits so terminate RETURN [LOOPHOLE[card]]; third _ LOOPHOLE[RopeReader.Get[control]]; card.thirdBottom _ third.dataBottom; card.thirdTop _ third.dataTop; IF ~third.others THEN -- value within 21 bits so terminate RETURN [LOOPHOLE[card]]; fourth _ LOOPHOLE[RopeReader.Get[control]]; card.fourth _ fourth.data; RETURN [LOOPHOLE[card]] -- full 28 bit value }; ReadAtom: PROCEDURE [] RETURNS [ATOM] = INLINE { <> RETURN[Atom.MakeAtom[ReadRope[ReadF32[], control]]]; }; ReadContents: PROCEDURE [parent:TiogaNode.Ref] RETURNS [head:TiogaNode.Ref] = { <> -- contents ::= [ labelledBranch | item | basic ] ; <> previous, item:TiogaNode.Ref; DO SELECT op FROM IN [T2FileOps.startTI..T2FileOps.startLI) => item _ ReadTextItem[]; IN [T2FileOps.startLI..T2FileOps.startLI+T2FileOps.itemSpace) => -- list items item _ ReadNonTextItem[offset:op-T2FileOps.startLI, new:TiogaNodeOps.NewListNode[]]; IN [T2FileOps.startBI..T2FileOps.startBI+T2FileOps.itemSpace) => -- basic items item _ ReadNonTextItem[offset:op-T2FileOps.startBI, new:TiogaNodeOps.NewBasicNode[]]; IN [T2FileOps.startBX..T2FileOps.startBX+T2FileOps.itemSpace) => -- box items item _ ReadNonTextItem[offset:op-T2FileOps.startBX, new:TiogaNodeOps.NewBoxNode[]]; T2FileOps.startBranch => { -- orphan branch <> controlRope, textRope: Rope.ROPE; controlStart, textStart, controlLen, textLen: TiogaNode.Offset; br: TiogaNode.RefBranchNode _ TiogaNodeOps.NewBranchNode[]; orphanBrInfo: PutGet.SpanInfo _ NEW[PutGet.SpanInfoRec]; textLen _ ReadF32[]; -- labelled branch text length controlLen _ ReadF32[]; -- control length [controlRope, controlStart] _ RopeReader.Position[control]; [textRope, textStart] _ RopeReader.Position[text]; orphanBrInfo.externalRepRope _ RopeEdit.Concat[RopeEdit.Substr[textRope, textStart, textLen], RopeEdit.Substr[controlRope, controlStart, controlLen], textLen, controlLen]; br.internalRepCreated _ FALSE; orphanBrInfo.charsStart _ 0; orphanBrInfo.ctrlStart _ orphanBrInfo.charsLen _ textLen; orphanBrInfo.ctrlLen _ controlLen; br.externalRepValid _ ~wholeTree; -- C.F. current.externalRepValid _ ~wholeTree IF wholeTree THEN CIR[ br:br, brInfo:orphanBrInfo, wholeTree:TRUE, indent:indent+5, textBuffer:textBuffer, control:control] -- don't attache, props ELSE NodeProps.PutProp[br, $BranchInfo, orphanBrInfo]; -- attache to branch stub item _ br; RopeReader.SetPosition[control, controlRope, controlStart+controlLen]; -- skip branch RopeReader.SetPosition[text, textRope, textStart+textLen]; -- skip branch }; ENDCASE => { -- anything but an item causes termination of chain IF head=NIL THEN head _ previous _ item; IF item#NIL THEN { -- if no items at all then return NIL previous.next _ parent; previous.last _ TRUE; }; RETURN ; }; IF previous=NIL THEN head _ previous _ item ELSE { previous.next _ item; previous _ item; }; previous.last _ FALSE; -- there might be some more op _ NextOp[]; ENDLOOP }; ReadFormat: PROCEDURE [] RETURNS [n:TiogaNode.Name] = INLINE { -- format ::= symbol ; len:TiogaNode.Offset _ ReadF32[]; IF len>LAST[NAT] THEN { -- mega-symbols need special treatment format:Rope.ROPE _ ReadRope[len, control]; IF Debug THEN { Indent[]; IO.PutF[report, "Format[%g]\n", IO.rope[format]] }; RETURN [NameSymbolTable.MakeNameFromRope[format]] } ELSE { IF len > textBuffer.maxLength THEN textBuffer _ NEW[TEXT[len]]; textBuffer.length _ 0; textBuffer.length _ RopeReader.GetString[control, textBuffer, len]; n _ NameSymbolTable.MakeName[textBuffer]; }; }; ReadItemList: PROCEDURE [parent:TiogaNode.Ref] RETURNS [head:TiogaNode.Ref] = { <> -- {item} lastItem -- item ::= [defaultTextItem | textItem | defaultTextItemHeavyDuty | textItemHeavyDuty | listItem | boxItem] ; previous, item:TiogaNode.Ref; DO SELECT op FROM IN [T2FileOps.startTI..T2FileOps.startLI) => item _ ReadTextItem[]; -- text items IN [T2FileOps.startLI..T2FileOps.startBI) => -- list items item _ ReadNonTextItem[offset:op-T2FileOps.startLI, new:TiogaNodeOps.NewListNode[]]; IN [T2FileOps.startBX..T2FileOps.startBX+T2FileOps.itemSpace) => -- box items item _ ReadNonTextItem[offset:op-T2FileOps.startBX, new:TiogaNodeOps.NewBoxNode[]]; ENDCASE => { -- anything else causes termination of chain IF head=NIL THEN head _ previous _ item; IF item#NIL THEN { -- if no items at all then return NIL previous.next _ parent; previous.last _ TRUE; }; RETURN ; }; IF previous=NIL THEN head _ previous _ item ELSE { previous.next _ item; previous _ item; }; previous.last _ FALSE; -- there might be some more op _ NextOp[]; ENDLOOP }; ReadNonTextItem: PROCEDURE [offset:CARDINAL, new:TiogaNode.Ref] RETURNS [TiogaNode.Ref] = { <> <> <> <> <<>> <> <<>> OPEN T2FileOps; -- ** ACHTUNG! ACHTUNG! ACHTUNG! doHD, doCmt, doRuns, doFmt, doDefault:BOOLEAN _ FALSE; classData:Rope.ROPE _ NIL; <<>> <<** SCANNER>> IF offset>=heavyDuty THEN { -- it has props and/or contents offset _ offset - heavyDuty; doHD _ TRUE; }; SELECT offset FROM 0 => NULL; cmt => { doCmt _ TRUE}; fmt => { doFmt _ TRUE}; fmt+cmt => { doFmt _ doCmt _ TRUE}; default => { doDefault _ TRUE}; default+cmt => { doDefault _ doCmt _ TRUE}; default+fmt => { doDefault _ doFmt _ TRUE}; default+fmt+cmt => { doDefault _ doFmt _ doCmt _ TRUE}; ENDCASE => ERROR; -- offset out of range!!! <<** READER>> IF Debug THEN { Indent[]; IO.PutF[report, "OTHER "]; indent _ indent + 2; }; new.comment _ doCmt; WITH new SELECT FROM bx:TiogaNode.RefBoxNode => { -- BOX NODES classInfo:TiogaItemClass.ItemClass; IF doHD THEN { IF Debug THEN IO.PutF[report, "Heavy Duty\n"]; FOR op _ NextOp[], NextOp[] WHILE op=prop DO -- read any properties ReadProp[bx]; ENDLOOP; <> IF Debug THEN { Indent[]; IO.PutF[report, "CONTENTS\n"]; }; bx.contents _ ReadContents[bx]; <> } ELSE { IF Debug THEN IO.PutF[report, "Regular\n"]; op _ NextOp[]; }; SELECT op FROM startClassData => classData _ ReadRope[ReadF32[], control]; noClassData => NULL; ENDCASE => SIGNAL Tioga2FileFormatError; bx.class _ TiogaNodeOps.LookupItemID[IF doDefault THEN $Box ELSE ReadAtom[]]; classInfo _ TiogaNodeOps.FetchItemClass[bx.class]; IF classInfo.set=NIL THEN SIGNAL ClassNotAvailable ELSE classInfo.set[bx, $Restore, classData]; -- finalise? IF Debug THEN { Indent[]; IO.PutF[report, "Class:%g Comment:%g\n", IO.atom[classInfo.flavor], IO.bool[doCmt]]; }; IF doFmt THEN bx.format _ ReadFormat[]; }; bs:TiogaNode.RefBasicNode => { -- BASIC NODES classInfo:TiogaBasicClass.BasicClass; IF doHD THEN { IF Debug THEN IO.PutF[report, "Heavy Duty\n"]; FOR op _ NextOp[], NextOp[] WHILE op=prop DO -- read any properties ReadProp[bs]; ENDLOOP; <> } ELSE { IF Debug THEN IO.PutF[report, "Regular\n"]; op _ NextOp[]; }; SELECT op FROM startClassData => classData _ ReadRope[ReadF32[], control]; noClassData => NULL; ENDCASE => SIGNAL Tioga2FileFormatError; bs.class _ TiogaNodeOps.LookupBasicID[IF doDefault THEN $Basic ELSE ReadAtom[]]; classInfo _ TiogaNodeOps.FetchBasicClass[bs.class]; IF classInfo.set=NIL THEN SIGNAL ClassNotAvailable ELSE classInfo.set[bs, $Restore, classData]; -- finalise? IF Debug THEN { Indent[]; IO.PutF[report, "Class:%g Comment:%g\n", IO.atom[classInfo.flavor], IO.bool[doCmt]] }; IF doFmt THEN bs.format _ ReadFormat[]; }; li:TiogaNode.RefListNode => { -- LIST NODES classInfo:TiogaItemClass.ItemClass; IF doHD THEN { IF Debug THEN IO.PutF[report, "Heavy Duty\n"]; FOR op _ NextOp[], NextOp[] WHILE op=prop DO -- read any properties ReadProp[li]; ENDLOOP; <> IF Debug THEN { Indent[]; IO.PutF[report, "CONTENTS\n"]; }; li.contents _ ReadContents[li]; <> } ELSE { IF Debug THEN IO.PutF[report, "Regular\n"]; op _ NextOp[]; }; SELECT op FROM startClassData => classData _ ReadRope[ReadF32[], control]; noClassData => NULL; ENDCASE => SIGNAL Tioga2FileFormatError; li.class _ TiogaNodeOps.LookupItemID[IF doDefault THEN $List ELSE ReadAtom[]]; classInfo _ TiogaNodeOps.FetchItemClass[li.class]; IF classInfo.set=NIL THEN SIGNAL ClassNotAvailable ELSE classInfo.set[li, $Restore, classData]; -- finalise? IF Debug THEN { Indent[]; IO.PutF[report, "Class:%g Comment:%g\n", IO.atom[classInfo.flavor], IO.bool[doCmt]] }; IF doFmt THEN li.format _ ReadFormat[]; }; ENDCASE => ERROR; -- ReadNonTextItem called with inappropriate item type IF Debug THEN indent _ indent - 2; RETURN[new] }; ReadProp: PROCEDURE [br:TiogaNode.Ref] = { <> -- prop ::= prop propName specs -- propName ::= symbol ; -- symbol ::= symbolLength symbolRope ; -- symbolLength ::= FORWARD32 ; -- symbolRope ::= {CHAR}; -- specs ::= specsLength specsRope ; -- specsLength ::= FORWARD32 ; -- specsRope ::= {CHAR}; atom:ATOM _ ReadAtom[]; specs:Rope.ROPE _ ReadRope[ReadF32[], control]; IF Debug THEN { Indent[]; IO.PutF[report, "Property[%g, %g]\n", IO.atom[atom], IO.rope[specs]] }; NodeProps.PutProp[br, atom, NodeProps.DoSpecs[atom, specs, br]] }; ReadRope: PROCEDURE [len:INT, rdr:RopeReader.Ref] RETURNS [Rope.ROPE] = { <> rope: Rope.ROPE; pos: TiogaNode.Offset; [rope, pos] _ RopeReader.Position[rdr]; -- find out where the start is RopeReader.SetIndex[rdr, pos+len]; -- step reader over it RETURN [RopeEdit.Substr[rope, pos, len]] -- return it }; ReadRuns: PROCEDURE [] RETURNS [lookRuns:TiogaLooks.Runs] = { -- runs ::= noOfRuns {run} ; -- noOfRuns ::= FORWARD32 ; -- run ::= [lookSeq| noLooks] runLength ; -- lookSeq ::= {addlooks} lastLooks -- addlooks ::= BYTE [addLooksFirst..addLooksLast] ; -- lastLooks ::= BYTE [lastLooksFirst..lastLooksLast] ; -- runLength ::= FORWARD32 ; <<** noOfRuns>> pos: TiogaNode.Offset _ 0; numRuns: TiogaNode.Offset _ ReadF32[]; IF Debug THEN { Indent[]; IO.PutF[report, "Runs (%g) ", IO.card[numRuns]]; }; WHILE numRuns > 0 DO -- ** {run} 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 -- run ReadLooks: PROC [] = { <> FOR op:CHAR _ NextOp[], NextOp[] DO -- ** [lookSeq | noLooks] SELECT op FROM IN [T2FileOps.addLooksFirst..T2FileOps.addLooksLast] => { <> c:CHARACTER _ 'a+(op - T2FileOps.addLooksFirst); IF Debug THEN IO.PutF[report, "%g ", IO.char[c]]; looks[c] _ TRUE; }; IN [T2FileOps.lastLooksFirst..T2FileOps.lastLooksLast] => { <> c:CHARACTER _ 'a+(op - T2FileOps.lastLooksFirst); IF Debug THEN IO.PutF[report, "%g ", IO.char[c]]; looks[c] _ TRUE; EXIT; }; T2FileOps.noLooks => { IF Debug THEN IO.PutF[report, "NoLooks "]; EXIT; }; ENDCASE => SIGNAL Tioga2FileFormatError; ENDLOOP; }; looks: TiogaLooks.Looks _ TiogaLooks.noLooks; lookLen:TiogaNode.Offset; ReadLooks[]; lookLen _ ReadF32[]; baseRuns[i] _ [pos_pos+lookLen, looks]; IF Debug THEN IO.PutF[report, "(%g) ", IO.card[lookLen]]; ENDLOOP; lookRuns _ IF lookRuns=NIL THEN baseRuns ELSE TiogaLooksOps.Concat[lookRuns,baseRuns,len,pos-len]; ENDLOOP; IF Debug THEN IO.PutF[report, "total %g\n", IO.card[pos]]; }; ReadTextItem: PROCEDURE [] RETURNS [item:TiogaNode.RefTextNode] = { OPEN T2FileOps; -- ** ACHTUNG! ACHTUNG! ACHTUNG! <> ReadCRRope: PROCEDURE [rdr:RopeReader.Ref] RETURNS [rope:Rope.ROPE] = INLINE { <> rope _ ReadRope[ReadF32[], rdr]; RopeReader.BumpIndex[rdr, 1]; -- skip over CR IF Debug THEN { Indent[]; IO.PutF[report,"%l%g ...%l\n",IO.rope["b"], IO.rope[Rope.Substr[rope, 0, 40]], IO.rope[" "]] }; }; doHD, doCmt, doRuns, doFmt, doDefault:BOOLEAN _ FALSE; offset:CARDINAL; classInfo:TiogaItemClass.ItemClass; SELECT op FROM -- decide if heavy duty item and set offset to get within-type info IN [startTI..startTI+heavyDuty) => {offset _ op - startTI}; IN [startTI+heavyDuty..startLI) => {doHD _ TRUE; offset _ op - (startTI+heavyDuty)}; ENDCASE => ERROR; -- ReadTextItem called with non text item SELECT offset FROM 0 => NULL; cmt => { doCmt _ TRUE}; runs => { doRuns _ TRUE}; runs+cmt => { doRuns _ doCmt _ TRUE}; fmt => { doFmt _ TRUE}; fmt+cmt => { doFmt _ doCmt _ TRUE}; fmt+runs => { doFmt _ doRuns _ TRUE}; fmt+runs+cmt => { doFmt _ doRuns _ doCmt _ TRUE}; default => { doDefault _ TRUE}; default+cmt => { doDefault _ doCmt _ TRUE}; default+runs => { doDefault _ doRuns _ TRUE}; default+runs+cmt => { doDefault _ doRuns _ doCmt _ TRUE}; default+fmt => { doDefault _ doFmt _ TRUE}; default+fmt+cmt => { doDefault _ doFmt _ doCmt _ TRUE}; default+fmt+runs => { doDefault _ doFmt _ doRuns _ TRUE}; default+fmt+runs+cmt => { doDefault _ doFmt _ doRuns _ doCmt _ TRUE}; ENDCASE => ERROR; -- offset out of range!!! item _ TiogaNodeOps.NewTextNode[]; IF Debug THEN { Indent[]; IO.PutF[report, "TEXT "]; indent _ indent + 2; }; IF doHD THEN { IF Debug THEN { IO.PutF[report, "Heavy Duty\n"]; }; FOR op _ NextOp[], NextOp[] WHILE op=prop DO -- read any properties ReadProp[item]; ENDLOOP; <> } ELSE IF Debug THEN IO.PutF[report, "Regular\n"]; item.class _ TiogaNodeOps.LookupItemID[IF doDefault THEN $Text ELSE ReadAtom[]]; classInfo _ TiogaNodeOps.FetchItemClass[item.class]; IF classInfo=NIL THEN SIGNAL ClassNotAvailable; IF Debug THEN { Indent[]; IO.PutF[report, "Class:%g Comment:%g\n", IO.atom[classInfo.flavor], IO.bool[doCmt]] }; IF doRuns THEN item.runs _ ReadRuns[]; -- construct the runs descriptor IF doFmt THEN item.format _ ReadFormat[]; item.comment _ doCmt; item.rope _ IF doCmt THEN ReadCRRope[control] ELSE ReadCRRope[text]; IF Debug THEN indent _ indent - 2; }; <<*** CREATEINTERNALREP STARTS HERE ***>> -- optCmt {prop} optFormat {item} lastItem text: RopeReader.Ref; nKids: CARDINAL; prev, current: TiogaNode.RefBranchNode ; kidCtrlStart, kidTextStart: TiogaNode.Offset; op: T2FileOps.Op; IF brInfo=NIL THEN ERROR; -- client did not supply branch info. properties IF Debug THEN { Indent[]; IO.PutF[report, "%gBRANCH Data: %g %g Control: %g %g\n", IF brInfo.ctrlLen=0 THEN IO.rope["CHEAP "] ELSE IO.rope[""], IO.card[brInfo.charsStart], IO.card[brInfo.charsLen], IO.card[brInfo.ctrlStart], IO.card[brInfo.ctrlLen]]; }; text _ RopeReader.GetRopeReader[]; -- get text reader from RR cache IF Debug THEN { Indent[]; IO.PutF[report, " CONTENTS: "]; indent _ indent + 2; }; <<*** PARSE BRANCH CONTENTS DATA ***>> -- cheapBranch | optCmt {prop} optFormat {item} lastItem RopeReader.SetPosition[text, brInfo.externalRepRope, brInfo.charsStart]; RopeReader.SetPosition[control, brInfo.externalRepRope, brInfo.ctrlStart]; IF brInfo.ctrlLen=0 THEN { <> IF brInfo.charsLen=0 THEN { IF Debug THEN IO.PutF[report, "EMPTY\n"]; } ELSE { t:TiogaNode.RefTextNode _ br.contents _ TiogaNodeOps.NewTextNode[]; t.class _ TiogaNodeOps.LookupItemID[$Text]; t.next _ br; t.rope _ RopeEdit.Substr[brInfo.externalRepRope, brInfo.charsStart, brInfo.charsLen-1]; -- skip CR IF Debug THEN IO.PutF[report, "%l%g ...%l\n", IO.rope["b"], IO.rope[RopeEdit.Substr[t.rope, 0, 40]], IO.rope[" "]]; }; br.internalRepCreated _ TRUE; -- mark branch as cracked at last indent _ indent - 2; RopeReader.FreeRopeReader[text]; RETURN; }; IF Debug THEN IO.PutF[report, "\n"]; op _ NextOp[]; DO SELECT op FROM T2FileOps.comment => { br.comment _ TRUE; op _ NextOp[] }; T2FileOps.prop => { ReadProp[br]; op _ NextOp[] }; T2FileOps.format => { br.format _ ReadFormat[]; op _ NextOp[] }; ENDCASE => { br.contents _ NARROW[ReadItemList[parent:br]]; EXIT; }; ENDLOOP; kidCtrlStart _ RopeReader.GetIndex[control]; -- remember where the kids start kidTextStart _ RopeReader.GetIndex[text]; RopeReader.FreeRopeReader[text]; -- only play with the control stream hereafter <> -- {child} {childHK} startHK nchild ; <<>> <> RopeReader.SetPosition[control, brInfo.externalRepRope, brInfo.ctrlStart+brInfo.ctrlLen]; nKids _ ReadB32[]; <> IF Debug THEN { indent _ indent - 1; Indent[]; IO.PutF[report, "%lChildren %g%l\n", IO.rope["i"], IO.card[nKids], IO.rope[" "]] }; IF nKids>0 THEN { <> crntInfo:PutGet.SpanInfo; FOR i:CARDINAL IN [1..nKids] DO current _ TiogaNodeOps.NewBranchNode[]; IF prev=NIL THEN br.child _ current ELSE prev.next _ current; current.last _ (i=nKids); -- default is TRUE damnit current.externalRepValid _ ~wholeTree; <> current.internalRepCreated _ FALSE; -- maybe not going to crack child here <> IF wholeTree THEN crntInfo _ brInfo ELSE crntInfo _ NEW[PutGet.SpanInfoRec]; crntInfo.externalRepRope _ brInfo.externalRepRope; crntInfo.charsLen _ ReadB32[]; crntInfo.ctrlLen _ ReadB32[]; crntInfo.ctrlStart _ kidCtrlStart ; crntInfo.charsStart _ kidTextStart ; <> kidCtrlStart _ kidCtrlStart + crntInfo.ctrlLen; kidTextStart _ kidTextStart + crntInfo.charsLen; IF wholeTree THEN { ropeSave:Rope.ROPE; ropeOffset:TiogaNode.Offset; IF Debug THEN { Indent[]; IO.PutF[report, "CHILD %g:\n", IO.card[i]]; }; [ropeSave, ropeOffset] _ RopeReader.Position[control]; -- save vitals so sub-CIR can use CIR[ br:current, brInfo:crntInfo, wholeTree:TRUE, indent:indent+4, textBuffer:textBuffer, control:control]; RopeReader.SetPosition[control, ropeSave, ropeOffset]; -- restore vitals } ELSE NodeProps.PutProp[current, $BranchInfo, crntInfo]; prev _ current; ENDLOOP; current.next _ br; -- point child at parent }; br.internalRepCreated _ TRUE; -- mark branch as cracked at last indent _ indent - 1; }; NewReport: PROCEDURE [] RETURNS [] = { <> <> [, report] _ IO.CreateViewerStreams["Tioga2 file description"]; }; IF Debug THEN NewReport[]; END.