<> <> <> <> <> <> <> DIRECTORY Ascii USING [CR, SP, TAB], GetTree, TextNode, Rope, RopeEdit, RopeIO, RopeReader; GetTreeImpl: CEDAR PROGRAM IMPORTS TextNode, RopeEdit, RopeIO, RopeReader EXPORTS GetTree = BEGIN OPEN GetTree; ROPE: TYPE = Rope.ROPE; Offset: TYPE = TextNode.Offset; ReadIndent: PUBLIC PROC [fileName: ROPE, tabIndent: NAT _ 4] RETURNS [root: RefTextNode] = { input: ROPE _ RopeIO.FromFile[fileName]; rdr: RopeReader.Ref _ RopeReader.GetRopeReader[]; maxOpen: NAT = 40; openNodes: ARRAY [0..maxOpen] OF RefTextNode; openIndents: ARRAY [0..maxOpen] OF INTEGER; level, lvl: NAT; indent: INTEGER; node: RefTextNode; noMoreInput: BOOL _ FALSE; ReadLine: PROC RETURNS [ROPE] = { -- read line and set indent tab: CHAR=Ascii.TAB; space: CHAR=Ascii.SP; cr: CHAR=Ascii.CR; start, end: Offset _ 0; indent _ 0; DO SELECT RopeReader.Get[rdr ! RopeReader.ReadOffEnd => { noMoreInput _ TRUE; EXIT }] FROM cr => EXIT; -- blank line tab => indent _ indent+tabIndent; space => indent _ indent+1; 0C => { noMoreInput _ TRUE; EXIT }; -- stop at first NULL char ENDCASE => { -- just saw the first nonblank char on the line start _ RopeReader.GetIndex[rdr]-1; DO SELECT RopeReader.Get[rdr ! RopeReader.ReadOffEnd => { end _ RopeReader.GetIndex[rdr]; noMoreInput _ TRUE; EXIT }] FROM cr => { end _ RopeReader.GetIndex[rdr]-1; EXIT }; 0C => { end _ RopeReader.GetIndex[rdr]-1; noMoreInput _ TRUE; EXIT }; ENDCASE; ENDLOOP; EXIT }; ENDLOOP; RETURN [RopeEdit.Substr[input,start,end-start]] }; PlaceNode: PROC = { dest: RefTextNode; SELECT lvl FROM < level => { -- insert as sibling of node at lvl+1 dest _ openNodes[level _ lvl+1]; dest.last _ FALSE; node.next _ dest.next; dest.next _ node }; = maxOpen => { -- insert as sibling of node at max level dest _ openNodes[level]; dest.last _ FALSE; node.next _ dest.next; dest.next _ node }; ENDCASE => { -- increase level dest _ openNodes[level]; node.next _ dest; dest.child _ node; level _ level+1 }; node.last _ TRUE; openIndents[level] _ indent; openNodes[level] _ node }; RopeReader.SetPosition[rdr,input,0]; openNodes[0] _ root _ TextNode.NewTextNode[]; root.last _ TRUE; openIndents[0] _ -1; level _ 0; UNTIL noMoreInput DO node _ TextNode.NewTextNode[]; IF (node.rope _ ReadLine[])=NIL THEN indent _ MAX[0,openIndents[level]]; FOR lvl _ level, lvl-1 DO IF openIndents[lvl] < indent THEN { PlaceNode[]; EXIT }; ENDLOOP; ENDLOOP; RopeReader.FreeRopeReader[rdr]; }; END.