DIRECTORY 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: BOOLEAN _ FALSE; ReadLine: PROC RETURNS [ROPE] = { -- read line and set indent tab: CHAR='I-100B; space: CHAR=' ; cr: CHAR='M-100B; 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] }; Start: PUBLIC PROC = { }; END. äGetTreeImpl.Mesa written by Paxton. May 1981 Paxton. August 24, 1982 10:39 am Russ Atkinson, July 26, 1983 5:43 pm Each line of input file becomes a node (parent for line is the closest previous line with smaller indent). Ê*˜šÏc™Jš™Jš ™ J™$—J˜Jšj™jJ˜šÏk ˜ J˜J˜ J˜J˜ J˜J˜ —J˜šœ ž ˜Jšžœ'˜.Jšžœ˜Jšœžœžœ ˜—J˜Jšžœžœžœ˜Jšœžœ˜J˜š Ïn œžœžœ žœ žœžœ˜\Jšœžœ˜(J˜1Jšœ žœ˜Jšœ žœžœ ˜-Jšœ žœžœžœ˜+Jšœ žœ˜Jšœžœ˜J˜Jšœ žœžœ˜J˜š Ÿœžœžœžœ˜=Jšœžœ ˜Jšœžœ˜Jšœžœ ˜J˜J˜ šžœžœ0˜9Jšœžœžœž˜ —Jšœžœ ˜J˜!J˜Jšœžœžœ˜>šžœ/˜