DIRECTORY BasicTime USING [GMT, Now, nullGMT], FS USING [StreamOpen], IO USING [Close, PutChar, PutRope], PasPrivate, PasPrivateVars, Process USING [Yield], RefText USING [AppendChar], Rope USING [Balance, Concat, Fetch, FromChar, FromRefText, Length]; PasOut: CEDAR PROGRAM IMPORTS BasicTime, FS, IO, PasPrivateVars, Process, RefText, Rope EXPORTS PasPrivate = BEGIN OPEN PasPrivate, PasPrivateVars; lastTimeFileWasOutput: BasicTime.GMT _ BasicTime.nullGMT; FlushOutBuf: PROCEDURE = BEGIN q: OutputQueuePtr = outQStk[outLevel]; IF outBuf.length # 0 THEN BEGIN q.contents _ Rope.Concat[q.contents, Rope.FromRefText[outBuf]]; outBuf.length _ 0; END; END; -- of FlushOutBuf CharToQueue: PUBLIC PROCEDURE [c: CHARACTER, q: OutputQueuePtr _ NIL] = BEGIN IF q = NIL THEN q _ outQStk[outLevel]; IF q = outQStk[outLevel] THEN BEGIN IF outBuf.length = outBuf.maxLength THEN FlushOutBuf[]; [] _ RefText.AppendChar[to: outBuf, from: c]; -- new char will fit cause we just checked END ELSE q.contents _ Rope.Concat[q.contents, Rope.FromChar[c]]; END; -- of CharToQueue CharToQueueStart: PUBLIC PROCEDURE [c: CHARACTER, q: OutputQueuePtr _ NIL] = BEGIN IF q = NIL THEN q _ outQStk[outLevel]; q.contents _ Rope.Concat[Rope.FromChar[c], q.contents]; END; -- of CharToQueueStart StringToQueue: PUBLIC PROCEDURE [s: ROPE, q: OutputQueuePtr _ NIL] = BEGIN IF q = NIL THEN q _ outQStk[outLevel]; IF q = outQStk[outLevel] THEN BEGIN sLen: NAT _ s.Length[]; bufLen: NAT _ outBuf.length; IF sLen + bufLen > outBuf.maxLength THEN FlushOutBuf[]; IF sLen + bufLen > outBuf.maxLength THEN -- still too big {q.contents _ Rope.Concat[q.contents, s]; RETURN}; FOR i:NAT IN [0..sLen) DO outBuf[bufLen+i] _ s.Fetch[i]; ENDLOOP; outBuf.length _ bufLen+sLen; END ELSE q.contents _ Rope.Concat[q.contents, s]; END; -- of StringToQueue StringToQueueStart: PUBLIC PROCEDURE [s: ROPE, q: OutputQueuePtr _ NIL] = BEGIN IF q = NIL THEN q _ outQStk[outLevel]; q.contents _ Rope.Concat[s, q.contents]; END; -- of StringToQueueStart MergeQueue: PUBLIC PROCEDURE [ from: OutputQueuePtr, to: OutputQueuePtr _ NIL] = BEGIN IF to = NIL THEN to _ outQStk[outLevel]; IF to = outQStk[outLevel] OR from = outQStk[outLevel] THEN FlushOutBuf[]; to.contents _ Rope.Concat[to.contents, from.contents]; ClearQueue[from]; END; -- of MergeQueue MergeQueueStart: PUBLIC PROCEDURE [ from: OutputQueuePtr, to: OutputQueuePtr _ NIL] = BEGIN IF to = NIL THEN to _ outQStk[outLevel]; IF to = outQStk[outLevel] OR from = outQStk[outLevel] THEN FlushOutBuf[]; to.contents _ Rope.Concat[from.contents, to.contents]; ClearQueue[from]; END; -- of MergeQueueStart CopyQueue: PUBLIC PROCEDURE [ from: OutputQueuePtr, to: OutputQueuePtr _ NIL] = BEGIN -- not especially efficient IF to = NIL THEN to _ outQStk[outLevel]; IF to = outQStk[outLevel] OR from = outQStk[outLevel] THEN FlushOutBuf[]; to.contents _ Rope.Concat[to.contents, from.contents]; END; -- of CopyQueue ClearQueue: PUBLIC PROCEDURE [q: OutputQueuePtr _ NIL] = BEGIN IF q = NIL THEN q _ outQStk[outLevel]; IF q = outQStk[outLevel] THEN FlushOutBuf[]; IF q.fileName.Length[] # 0 THEN BEGIN s: STREAM; TRUSTED {WHILE lastTimeFileWasOutput = BasicTime.Now[] DO Process.Yield[] ENDLOOP}; s _ FS.StreamOpen[q.fileName, $create]; s.PutRope[q.contents]; s.Close[]; TRUSTED {lastTimeFileWasOutput _ BasicTime.Now[]}; commandHandle.out.PutChar['.]; END; q.contents _ ""; q.fileName _ ""; END; -- of ClearQueue BalanceQueue: PUBLIC PROCEDURE [q: OutputQueuePtr _ NIL] = BEGIN IF q = NIL THEN q _ outQStk[outLevel]; IF q = outQStk[outLevel] THEN FlushOutBuf[]; q.contents _ Rope.Balance[base: q.contents]; END; -- of BalanceQueue PushOut: PUBLIC PROCEDURE [q: OutputQueuePtr _ NIL] = BEGIN IF outLevel # 0 THEN FlushOutBuf[]; outLevel _ outLevel + 1; IF q = NIL THEN outQStk[outLevel] _ Z.NEW[OutputQueue_[contents: "", fileName: ""]] ELSE BEGIN outQStk[outLevel] _ q END; END; CopyAndPopOut: PUBLIC PROCEDURE RETURNS [OutputQueuePtr] = BEGIN q: OutputQueuePtr _ outQStk[outLevel]; FlushOutBuf[]; outQStk[outLevel] _ NIL; outLevel _ outLevel - 1; RETURN[q]; END; PopOut: PUBLIC PROCEDURE = BEGIN ClearQueue[outQStk[outLevel]]; outLevel _ outLevel - 1; END; END. -- of PasOut -- |file: PasOut.mesa modified by Ramshaw, January 20, 1984 4:04 pm written by McCreight, October 3, 1980 12:23 PM Normal queues are represented as ropes. As an efficiency hack, the top queue on the stack of output queues has outBuf, a REF TEXT, included at its end. Thus, the common case of appending to the end of the top queue on the stack doesn't demand an allocation. Êó˜Jšœ™Jšœ.™.Jšœ/™/J˜šÏk ˜ Jšœ œœ˜$Jšœœ˜Jšœœ˜#J˜ J˜Jšœœ ˜Jšœœ˜Jšœœ9˜CJ˜—šœœ˜Jšœ œ)œ ˜VJ˜Jš˜J˜Jšœ˜ J˜Jšœ!œ˜9J˜—JšœM™MJšœJ™JJšœK™KJšœ™˜šÏn œ œ˜Jš˜J˜&šœ˜Jš˜J˜?J˜Jšœ˜—JšœÏc˜J˜—š ž œœ œ œœ˜GJš˜Jšœœœ˜'šœ˜Jšœ˜Jšœ"œ˜7Jšœ/Ÿ*˜YJš˜Jšœ8˜<—JšœŸ˜J˜—š žœœ œ œœ˜LJš˜Jšœœœ˜'J˜7JšœŸ˜J˜—š ž œœ œœœ˜DJš˜Jšœœœ˜&šœ˜Jš˜Jšœœ˜Jšœœ˜Jšœ"œ˜7šœ"œŸ˜:Jšœ*œ˜2—šœœœ ˜J˜Jšœ˜—J˜Jš˜Jšœ)˜-—JšœŸ˜J˜—š žœœ œœœ˜IJš˜Jšœœœ˜&J˜(JšœŸ˜J˜J˜—šž œœ œ˜Jšœ+œ˜1Jš˜Jšœœœ˜(Jšœœœ˜IJ˜6J˜JšœŸ˜J˜—šžœœ œ˜#Jšœ+œ˜1Jš˜Jšœœœ˜(Jšœœœ˜IJ˜6J˜JšœŸ˜J˜J˜—šž œœ œ˜Jšœ+œ˜1JšœŸ˜!Jšœœœ˜(Jšœœœ˜IJ˜6JšœŸ˜J˜J˜—šž œœ œœ˜8Jš˜Jšœœœ˜&Jšœœ˜,šœœ˜ Jš˜Jšœœ˜ Jšœœ)œœ˜SJ˜'J˜J˜ Jšœ+˜2J˜Jšœ˜—J˜J˜JšœŸ˜J˜J˜—šž œœ œœ˜:Jš˜Jšœœœ˜&Jšœœ˜,J˜,JšœŸ˜J˜J˜—šžœœ œœ˜5Jš˜Jšœœ˜#J˜Jš œœœœœ*˜SJšœœœ˜%Jšœ˜J˜J˜—šž œœ œœ˜:Jšœ˜J˜&J˜Jšœœ˜J˜Jšœ˜ Jšœ˜J˜J˜—šžœœ œ˜Jšœ9œ˜BJ˜J˜—JšœŸ˜J˜J˜——…—pß