DIRECTORY IO, IOUtils, Rope, TextNode, TiogaFileOps, TiogaOps, TiogaStreams; TiogaStreamsImpl: CEDAR PROGRAM IMPORTS IO, IOUtils, Rope, TN: TextNode, TFO: TiogaFileOps, TiogaOps EXPORTS TiogaStreams = BEGIN ROPE: TYPE = Rope.ROPE; CommentHandling: TYPE = TiogaStreams.CommentHandling; DepthOp: TYPE = TiogaStreams.DepthOp; IsATS: PUBLIC PROC [s: IO.STREAM] RETURNS [is: BOOLEAN] = {is _ s # NIL AND s.streamData # NIL AND ( ISTYPE[s.streamData, TiogaInStreamData] OR ISTYPE[s.streamData, TiogaOutStreamData]); }; CreateInput: PUBLIC PROC [from: TN.Ref, commentHandling: CommentHandling _ discard, levelPrefix: ROPE _ NIL] RETURNS [in: IO.STREAM] = BEGIN sd: TiogaInStreamData _ NEW [TiogaInStreamDataRep _ [ commentHandling: commentHandling, levelPrefix: levelPrefix, node: NIL, root: from ]]; GoToBeginning[sd]; in _ IO.CreateStream[streamProcs: tiogaInStreamProcs, streamData: sd]; END; GoToBeginning: PROC [sd: TiogaInStreamData] = { dd: INT; IF sd.root = NIL THEN {sd.end _ TRUE; RETURN}; [sd.node, dd] _ TN.Forward[sd.root]; IF sd.node = NIL THEN {sd.end _ TRUE; RETURN}; SELECT dd FROM <1 => {sd.end _ TRUE; RETURN}; =1 => { sd.end _ FALSE; sd.depth _ 1; sd.indexAtNodeStart _ 0; NodeHello[sd]; }; ENDCASE => ERROR; }; tiogaInStreamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[variety: input, class: $TiogaInStream, getChar: GetChar, endOf: EndOf, backup: BackupIn, getIndex: GetInIndex, setIndex: SetInIndex]; GetChar: PROC [self: IO.STREAM] RETURNS [char: CHAR] = BEGIN sd: TiogaInStreamData _ NARROW[self.streamData]; TryForNextChar[sd]; IF sd.end THEN ERROR IO.EndOfStream[self]; char _ sd.nodeRope.Fetch[sd.next]; sd.next _ sd.next + 1; sd.index _ sd.index + 1; END; EndOf: PROC [self: IO.STREAM] RETURNS [end: BOOLEAN] = BEGIN sd: TiogaInStreamData _ NARROW[self.streamData]; TryForNextChar[sd]; end _ sd.end; END; BackupIn: PROC [self: IO.STREAM, char: CHAR] = { past: INT _ self.GetIndex[]; oldChar: CHAR; IF past = 0 THEN ERROR IO.Error[IllegalBackup, self]; self.SetIndex[past-1]; oldChar _ self.GetChar[]; IF oldChar # char THEN ERROR IO.Error[IllegalBackup, self]; self.SetIndex[past-1]; }; GetInIndex: PROC [self: IO.STREAM] RETURNS [index: INT] = { sd: TiogaInStreamData _ NARROW[self.streamData]; index _ sd.index; }; SetInIndex: PROC [self: IO.STREAM, index: INT] = { sd: TiogaInStreamData _ NARROW[self.streamData]; local: INT; TryForNextChar[sd]; local _ index - sd.indexAtNodeStart; IF local IN [0 .. sd.nodeLen] THEN { sd.next _ local; sd.index _ index; sd.end _ FALSE; --well, what this really means is that we don't yet know that it's at the end } ELSE { GoToBeginning[sd]; sd.next _ sd.index _ index; }; }; CurInNode: PUBLIC PROC [s: IO.STREAM] RETURNS [n: TN.Ref] = { sd: TiogaInStreamData _ NARROW[s.streamData]; TryForNextChar[sd]; n _ sd.node; }; SkipChildren: PUBLIC PROC [s: IO.STREAM] = { sd: TiogaInStreamData = NARROW[s.streamData]; Work: PROC [of: TN.Ref] RETURNS [next: TN.Ref, dd, di: INT] = { rawSize: INT = TN.NodeRope[of].Length[]; di _ IF NOT of.comment THEN rawSize+1 ELSE SELECT sd.commentHandling FROM discard => 0, useDirectly => rawSize+1, prefixWithDashDash => rawSize+3, ENDCASE => ERROR; [next, dd] _ TN.Forward[of]; IF dd > 1 THEN ERROR; IF dd < 1 THEN RETURN; dd _ dd - 1; WHILE dd = 0 DO ddi: INT; [next, dd, ddi] _ Work[next]; di _ di + ddi; ENDLOOP; dd _ dd + 1; }; new: TN.Ref; dd, di, newStart: INT; TryForNextChar[sd]; [new, dd, di] _ Work[sd.node]; newStart _ sd.indexAtNodeStart + di; IF newStart < sd.index THEN ERROR; sd.index _ newStart; IF sd.depth+dd <= 0 OR new = NIL THEN {sd.end _ TRUE; RETURN}; sd.node _ new; sd.indexAtNodeStart _ newStart; sd.depth _ sd.depth + dd; sd.next _ 0; NodeHello[sd]; }; TiogaInStreamData: TYPE = REF TiogaInStreamDataRep; TiogaInStreamDataRep: TYPE = RECORD [ commentHandling: CommentHandling, end: BOOLEAN _ FALSE, next, nodeLen, depth: INT _ 0, indexAtNodeStart, index: INT _ 0, nodeRope: ROPE _ NIL, levelPrefix: ROPE, node, root: TN.Ref]; TryForNextChar: PROC [sd: TiogaInStreamData] = BEGIN IF sd.end THEN RETURN; WHILE sd.next >= sd.nodeLen DO dd: INT; next: TN.Ref; [next, dd] _ TN.Forward[sd.node]; IF sd.depth+dd <= 0 OR next = NIL THEN {sd.end _ TRUE; RETURN}; sd.next _ sd.next - sd.nodeLen; sd.depth _ sd.depth + dd; sd.indexAtNodeStart _ sd.indexAtNodeStart + sd.nodeLen; sd.node _ next; NodeHello[sd]; ENDLOOP; END; NodeHello: PROC [sd: TiogaInStreamData] = BEGIN tn: TN.RefTextNode _ sd.node; Use: PROC [prefix: ROPE] = { sd.nodeRope _ TN.NodeRope[tn].Concat["\n"]; IF prefix # NIL THEN sd.nodeRope _ prefix.Concat[sd.nodeRope]; IF sd.levelPrefix.Length[] # 0 THEN THROUGH [1 .. sd.depth) DO sd.nodeRope _ sd.levelPrefix.Concat[sd.nodeRope]; ENDLOOP; sd.nodeLen _ sd.nodeRope.Length[]; }; IF tn.comment THEN SELECT sd.commentHandling FROM discard => { sd.nodeRope _ NIL; sd.nodeLen _ 0; }; useDirectly => Use[NIL]; prefixWithDashDash => Use["--"]; ENDCASE => ERROR ELSE Use[NIL]; END; CreateOutput: PUBLIC PROC [to: TFO.Ref, breakAtNewline: BOOL _ FALSE, levelPrefix, defaultFormat: ROPE _ NIL] RETURNS [out: IO.STREAM] = BEGIN sd: TiogaOutStreamData _ NEW [TiogaOutStreamDataRep _ [ breakAtNewline: breakAtNewline, parsePrefix: levelPrefix # NIL, levelPrefix: levelPrefix, root: to, nodes: LIST[to], lpLength: levelPrefix.Length[], nextDepth: 1, defaultFormat: defaultFormat ]]; pfp: IOUtils.PFProcs; out _ IO.CreateStream[streamProcs: tiogaOutStreamProcs, streamData: sd]; pfp _ IOUtils.CopyPFProcs[out]; [] _ IOUtils.SetPFCodeProc[pfProcs: pfp, char: 'l, codeProc: FormatL]; [] _ IOUtils.SetPFProcs[stream: out, pfProcs: pfp]; PrepareForChar[out, sd]; END; tiogaOutStreamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[variety: output, class: $TiogaOutStream, putChar: PutChar, putBlock: PutBlock, close: CloseOut]; PutChar: PROC [self: IO.STREAM, char: CHAR] = BEGIN sd: TiogaOutStreamData _ NARROW[self.streamData]; SELECT TRUE FROM sd.breakAtNewline AND char = '\n => EndNode[self, reset, FALSE]; sd.parsePrefix AND (NOT sd.ready) AND char = sd.levelPrefix.Fetch[sd.lpCharsSeen] => { sd.lpCharsSeen _ sd.lpCharsSeen + 1; IF sd.lpCharsSeen = sd.lpLength THEN { sd.lpCharsSeen _ 0; sd.nextDepth _ sd.nextDepth + 1; }; }; ENDCASE => { PrepareForChar[self, sd]; sd.contents _ sd.contents.Concat[Rope.FromChar[char]]; }; END; PutBlock: PROC [self: IO.STREAM, block: REF READONLY TEXT, startIndex, count: NAT] = BEGIN sd: TiogaOutStreamData _ NARROW[self.streamData]; next: NAT _ startIndex; afterLast: NAT _ startIndex + count; WHILE next < afterLast DO nextCR, subsize: NAT; WHILE (NOT sd.ready) OR block[next] = '\n DO PutChar[self, block[next]]; next _ next + 1; IF next >= afterLast THEN RETURN; ENDLOOP; FOR nextCR _ next, nextCR + 1 WHILE nextCR < afterLast AND block[nextCR] # '\n DO NULL ENDLOOP; IF (subsize _ nextCR - next) # 0 THEN { sd.contents _ sd.contents.Concat[RopeFromSubText[block, next, subsize]]; next _ nextCR; }; ENDLOOP; END; CloseOut: PROC [self: IO.STREAM, abort: BOOL _ FALSE] = BEGIN EndNode[self]; IOUtils.AmbushStream[self: self, streamProcs: IOUtils.closedStreamProcs, streamData: NIL]; END; CurOutNode: PUBLIC PROC [s: IO.STREAM] RETURNS [n: TFO.Ref] = BEGIN sd: TiogaOutStreamData _ NARROW[s.streamData]; n _ sd.nodes.first; END; SetFormat: PUBLIC PROC [of: IO.STREAM, format: ROPE] = BEGIN n: TFO.Ref _ CurOutNode[of]; TFO.SetFormat[n, format]; END; FormatL: PROC [stream: IO.STREAM, val: IO.Value, format: IOUtils.Format, char: CHAR] = { sd: TiogaOutStreamData _ NARROW[stream.streamData]; PrepareForChar[stream, sd]; WITH val SELECT FROM rv: IO.Value[rope] => LooksWork[stream, sd, rv.value]; ENDCASE => ERROR IO.Error[PFUnprintableValue, stream]; }; LooksWork: PROC [stream: IO.STREAM, sd: TiogaOutStreamData, chars: ROPE] = { index: INT _ sd.contents.Length[]; FOR i: INT IN [0 .. chars.Length[]) DO c: CHAR _ chars.Fetch[i]; SELECT c FROM ' => LooksWork[stream, sd, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]; IN ['a .. 'z] => { IF sd.looks[c] = NIL OR sd.looks[c].first.afterLast # notClosed THEN sd.looks[c] _ CONS[[first: index, afterLast: notClosed], sd.looks[c]] }; IN ['A .. 'Z] => {l: Look _ c + ('a - 'A); IF sd.looks[l] # NIL AND sd.looks[l].first.afterLast = notClosed THEN sd.looks[l].first.afterLast _ index; }; ENDCASE => ERROR IO.Error[PFUnprintableValue, stream]; ENDLOOP; }; EndNode: PUBLIC PROC [s: IO.STREAM, depthOp: DepthOp _ reset, idempotently: BOOLEAN _ FALSE] = BEGIN sd: TiogaOutStreamData _ NARROW[s.streamData]; IF NOT sd.ready THEN BEGIN IF idempotently THEN RETURN; PrepareForChar[s, sd]; END; TFO.SetContents[sd.nodes.first, sd.contents]; SetLooks[sd]; sd.ready _ FALSE; sd.lpCharsSeen _ 0; sd.contents _ NIL; sd.nextDepth _ SELECT depthOp FROM same => sd.userDepth, reset => 1, ENDCASE => ERROR; END; SetLooks: PROC [sd: TiogaOutStreamData] = { len: INT _ sd.contents.Length[]; FOR l: Look IN Look DO FOR lr: LooksRuns _ sd.looks[l], lr.rest WHILE lr # NIL DO afterLast: INT _ IF lr.first.afterLast = notClosed THEN len ELSE lr.first.afterLast; TFO.AddLooks[x: sd.nodes.first, start: lr.first.first, len: afterLast - lr.first.first, look: l, root: sd.root]; ENDLOOP; ENDLOOP; sd.looks _ ALL[NIL]; }; ChangeDepth: PUBLIC PROC [s: IO.STREAM, deltaDepth: INTEGER _ 0, autoEndNode: BOOLEAN _ TRUE, idempotently: BOOLEAN _ FALSE] = BEGIN sd: TiogaOutStreamData _ NARROW[s.streamData]; IF autoEndNode THEN EndNode[s, same, idempotently]; IF sd.ready THEN ERROR NotNow[s]; sd.nextDepth _ sd.nextDepth + deltaDepth; END; NotNow: PUBLIC ERROR [s: IO.STREAM] = CODE; BadDepth: PUBLIC ERROR [s: IO.STREAM, depth: INT] = CODE; TiogaOutStreamData: TYPE = REF TiogaOutStreamDataRep; TiogaOutStreamDataRep: TYPE = RECORD [ breakAtNewline, parsePrefix: BOOL, levelPrefix: ROPE, root: TFO.Ref _ NIL, nodes: LIST OF TFO.Ref _ NIL, ready: BOOLEAN _ FALSE, lpCharsSeen, lpLength: INT _ 0, nodeDepth, userDepth, --deltaDepth--nextDepth: INT _ 0, contents: ROPE _ NIL, defaultFormat: ROPE _ NIL, looks: ARRAY Look OF LooksRuns _ ALL[NIL]]; LooksRuns: TYPE = LIST OF LooksRun; LooksRun: TYPE = RECORD [first, afterLast: INT]; Look: TYPE = CHAR['a .. 'z]; notClosed: INT = -1; PrepareForChar: PROC [s: IO.STREAM, sd: TiogaOutStreamData] = BEGIN IF sd.ready THEN RETURN; IF sd.nextDepth < 0 THEN ERROR BadDepth[s, sd.nextDepth]; WHILE sd.nextDepth < sd.nodeDepth DO sd.nodes _ sd.nodes.rest; sd.nodeDepth _ sd.nodeDepth - 1; ENDLOOP; IF sd.nextDepth > sd.nodeDepth THEN { sd.nodes _ CONS[TFO.InsertAsLastChild[x: sd.nodes.first], sd.nodes]; sd.nodeDepth _ sd.nodeDepth + 1} ELSE { sd.nodes.first _ TFO.InsertNode[x: sd.nodes.first, child: FALSE]; }; IF sd.defaultFormat # NIL THEN TFO.SetFormat[sd.nodes.first, sd.defaultFormat]; sd.contents _ NIL; sd.ready _ TRUE; sd.userDepth _ sd.nodeDepth; WHILE sd.userDepth < sd.nextDepth DO sd.contents _ sd.contents.Concat[sd.levelPrefix]; sd.userDepth _ sd.userDepth + 1; ENDLOOP; IF sd.lpCharsSeen > 0 THEN { sd.contents _ sd.contents.Concat[sd.levelPrefix.Substr[len: sd.lpCharsSeen]]; }; END; true: REF ANY _ NEW [BOOL _ TRUE]; CopyChildren: PUBLIC PROC [from: TN.Ref, to: TFO.Ref] = BEGIN Work: PROC [from: TN.Ref, to: TFO.Ref] RETURNS [next: TN.Ref, dd: INT] = TRUSTED { last: TFO.Ref _ to; lastIsParent: BOOLEAN _ TRUE; [next, dd] _ TN.Forward[from]; IF dd > 1 THEN ERROR; IF dd < 1 THEN RETURN; dd _ dd - 1; WHILE dd = 0 DO toKid: TFO.Ref; tn: TN.RefTextNode _ next; r: ROPE _ TN.NodeRope[tn]; toKid _ last.InsertNode[child: lastIsParent]; toKid.SetContents[r]; IF tn.comment THEN TiogaOps.PutProp[n: LOOPHOLE[toKid], name: $Comment, value: true]; last _ toKid; lastIsParent _ FALSE; [next, dd] _ Work[next, toKid]; ENDLOOP; dd _ dd + 1; }; [] _ Work[from, to]; END; RopeFromSubText: PROC [text: REF READONLY TEXT, startIndex, count: NAT] RETURNS [rope: ROPE] = { GetChar: PROC RETURNS [c: CHAR] = { c _ text[startIndex]; startIndex _ startIndex + 1; count _ count - 1; }; rope _ Rope.FromProc[count, GetChar]; }; END. ÎTiogaStreamsImpl.Mesa Last Edited by: Spreitzer, September 18, 1985 5:59:06 pm PDT PrepareForChar[sd]; sd.contents _ sd.contents.Concat[Rope.FromRefText[block].Substr[start: startIndex, len: count]]; Ê®˜Jšœ™J™K˜Kšœ˜K˜K˜ K˜Kšœ˜—K˜Kšœœœ˜3šœœœ˜%K˜!Kšœœœ˜Kšœœ˜Kšœœ˜!Kšœ œœ˜Kšœ œ˜Kšœ œ˜—K˜šŸœœ˜.Kš˜Kšœœœ˜šœ˜Kšœœ˜Kšœœ˜ Kšœ œ˜!Kš œœœœ œœ˜?K˜K˜Kšœ7˜7K˜Kšœ˜Kšœ˜—Kšœ˜—K˜šŸ œœ˜)Kš˜Kšœœ˜šŸœœ œ˜Kšœœ˜+Kšœ œœ*˜>šœœœ˜>Kšœ1˜1Kšœ˜—Kšœ"˜"K˜—šœ ˜ šœœ˜#šœ ˜ Kšœœ˜Kšœ˜K˜—Kšœœ˜Kšœ ˜ Kšœ˜—Kšœœ˜—Kšœ˜—K˜šŸ œœœœœœœœœœœ˜ˆKš˜šœœ˜7Kšœ˜Kšœœ˜Kšœ˜Kšœ ˜ Kšœœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜—K˜Kšœœ@˜HK˜K˜FK˜3K˜Kšœ˜—K˜Kšœœœœs˜ŸK˜š Ÿœœœœœ˜-Kš˜Kšœœ˜1šœœ˜Kšœœ$œ˜@šœœœ œ1˜VKšœ$˜$šœœ˜&Kšœ˜Kšœ ˜ K˜—K˜—šœ˜ K˜K˜6K˜——Kšœ˜—K˜šŸœœœœ œœœœ˜TKš˜Kšœœ˜1Kšœœ˜Kšœ œ˜$šœ˜Kšœœ˜šœœ œ˜,K˜K˜Kšœœœ˜!Kšœ˜—Kš œœœœœœ˜_šœœ˜'KšœH˜HK˜K˜—Kšœ˜—K™Kšœ`™`Kšœ˜—K˜š Ÿœœœœ œœ˜7Kš˜K˜KšœUœ˜ZKšœ˜—K˜šŸ œœœœœœœ˜=Kš˜Kšœœ˜.K˜Kšœ˜—K˜š Ÿ œœœœœ œ˜6Kš˜Kšœœ˜Kšœ˜Kšœ˜—K˜š Ÿœœ œœœ&œ˜XKšœœ˜3K˜šœœ˜Kšœœ0˜6Kšœœœ#˜6—K˜—K˜š Ÿ œœ œœ!œ˜LKšœœ˜"šœœœ˜&Kšœœ˜šœ˜ K˜:šœ˜Kš œœœ)œœ3˜ŠK˜—šœ(˜*Kšœœœ)œ%˜jK˜—Kšœœœ#˜6—Kšœ˜—K˜—K˜šŸœœœœœ*œœ˜^Kš˜Kšœœ˜.šœœ ˜Kš˜Kšœœœ˜K˜Kšœ˜—Kšœ*˜-K˜ Kšœ œ˜Kšœ˜Kšœœ˜šœœ ˜"K˜K˜ Kšœœ˜—Kšœ˜—K˜šŸœœ˜+Kšœœ˜ šœ œ˜šœ&œœ˜:Kš œ œœ œœ˜TKšœm˜pKšœ˜—Kšœ˜—Kšœ œœ˜K˜—K˜šŸ œœœœœœœœœœ˜~Kš˜Kšœœ˜.Kšœ œ ˜3Kšœ œœ ˜!Kšœ)˜)Kšœ˜—K˜Kš œœœœœœ˜+Kš œ œœœœ œœ˜9K˜Kšœœœ˜5šœœœ˜&Kšœœ˜"Kšœ œ˜Kšœœœ˜Kš œœœœœ˜Kšœœœ˜Kšœœ˜Kšœ œ œ˜7Kšœ œœ˜Kšœœœ˜Kš œœœ œœ˜+—K˜Kšœ œœœ ˜#Kšœ œœœ˜0Kšœœœ ˜Kšœ œ˜K˜šŸœœœœ˜=Kš˜Kšœ œœ˜Kšœœœ˜9šœ˜$K˜Kšœ ˜ Kšœ˜—šœ˜šœ˜Kšœ œœ1˜DKšœ ˜ —šœ˜Kšœœ&œ˜AKšœ˜——Kšœœœœ-˜OKšœœ˜Kšœ œ˜Kšœ˜šœ˜$Kšœ1˜1K˜ Kšœ˜—šœœ˜KšœM˜MK˜—Kšœ˜—K˜Kš œœœœœœ˜"K˜š Ÿ œœœœ œ˜7Kš˜K˜šŸœœœ œœœ œœ˜RKšœœ ˜Kšœœœ˜Kšœ œ˜Kšœœœ˜Kšœœœ˜K˜ šœ˜Kšœœ˜Kšœœ˜Kšœœœ˜K˜-Kšœ˜Kšœ œœ&˜UKšœœ˜#K˜Kšœ˜—K˜ Kšœ˜—K˜K˜Kšœ˜—K˜šŸœœœœœœœœ˜`šŸœœœœ˜#K˜K˜K˜K˜—K˜%K˜—K˜Kšœ˜—…—.\@Ø