DIRECTORY Commander USING [CommandProc, Register], EditedStream USING [Rubout], FS USING [StreamOpen], Icons USING [IconFlavor, NewIconFromFile], InputFocus USING [Focus, GetInputFocus, PopInputFocus, PushInputFocus], IO, Process USING [Detach, Pause, MsecToTicks, SetTimeout, SecondsToTicks, Abort, CheckForAbort, DisableTimeout], Rope USING [ROPE, Find, Match, Equal], RuntimeError USING [UNCAUGHT], LogViewer, TypeScript USING [Create, PutRope], ViewerClasses USING [Viewer], ViewerIO USING [CreateViewerStreams, GetViewerFromStream], ViewerOps USING [PaintViewer, OpenIcon, EnumerateViewers, EnumProc], ViewerTools USING [SetSelection]; LogViewerImpl: CEDAR MONITOR IMPORTS Commander, EditedStream, FS, Icons, InputFocus, IO, Process, Rope, RuntimeError, TypeScript, ViewerIO, ViewerOps, ViewerTools EXPORTS LogViewer = BEGIN ROPE: TYPE = Rope.ROPE; UserAbort: PUBLIC SIGNAL = CODE; TimedOut: PUBLIC SIGNAL = CODE; viewer: ViewerClasses.Viewer _ NIL; in, out: IO.STREAM _ NIL; normalName: ROPE = "Log Viewer"; inputName: ROPE = "Log Viewer [Input Expected]"; normalIcon, inputIcon: Icons.IconFlavor; del: ROPE = "\177"; log: IO.STREAM; shouldFlush: BOOL _ FALSE; occupied: BOOL _ FALSE; --module occupied next: CONDITION _ [timeout: Process.MsecToTicks[4000]]; --another client might try entering Enter: ENTRY PROC [] = { ENABLE UNWIND => NULL; WHILE occupied DO WAIT next ENDLOOP; occupied _ TRUE; }; Leave: ENTRY PROC [] = { ENABLE UNWIND => NULL; occupied _ FALSE; BROADCAST next; }; EnterReader: PROC [] = { v: ViewerClasses.Viewer; Lock[]; Enter[]; v _ viewer; WHILE v=NIL OR v.destroyed DO InternalCreate[FALSE]; v _ viewer ENDLOOP; v.inhibitDestroy _ TRUE; WHILE v=NIL OR v.destroyed DO InternalCreate[TRUE]; v _ viewer ENDLOOP; v.icon _ inputIcon; v.name _ inputName; ViewerOps.PaintViewer[v, caption]; ViewerTools.SetSelection[v]; InputFocus.PushInputFocus[v, $LogViewer]; }; LeaveReader: PROC [] = { v: ViewerClasses.Viewer _ viewer; foc: InputFocus.Focus _ InputFocus.GetInputFocus[]; IF v#NIL THEN { v.icon _ normalIcon; v.name _ normalName; v.inhibitDestroy _ FALSE; --conveniant here; usefull in all places where called ViewerOps.PaintViewer[v, caption]; }; IF foc#NIL AND foc.info = $LogViewer THEN InputFocus.PopInputFocus[]; Leave[]; Free[]; }; ProcList: TYPE = LIST OF PROC; lockList: ProcList _ NIL; freeList: ProcList _ NIL; AddLock: PUBLIC ENTRY PROC [lock, free: PROC] = { ENABLE UNWIND => NULL; IF free#NIL THEN freeList _ CONS[free, freeList]; IF lock#NIL THEN IF lockList=NIL THEN lockList _ LIST[lock] ELSE FOR l: ProcList _ lockList, l.rest DO IF l.rest=NIL THEN {l.rest _ LIST[lock]; EXIT} ENDLOOP; }; Lock: PROC = { FOR l: ProcList _ lockList, l.rest WHILE l#NIL DO l.first[! RuntimeError.UNCAUGHT => CONTINUE] ENDLOOP }; Free: PROC = { FOR l: ProcList _ freeList, l.rest WHILE l#NIL DO l.first[! RuntimeError.UNCAUGHT => CONTINUE] ENDLOOP }; ReaderProtected: PROC [p: PROC] = { ENABLE UNWIND => LeaveReader[]; EnterReader[]; p[]; LeaveReader[]; }; Create: PROC [protected: BOOL] = { InternalCreate[protected] }; InternalCreate: PROC [protected: BOOL] = { FindOldGuys: ViewerOps.EnumProc = { MakeOrphan: PROC [v: ViewerClasses.Viewer] = { IF v#NIL THEN { v.inhibitDestroy _ FALSE; v.icon _ typescript; v.name _ "orphaned split log viewer"; IO.PutRope[log, "log viewer orphaned\n"]; IO.Flush[log]; ViewerOps.PaintViewer[v, caption]; TypeScript.PutRope[v, "\n... log viewer orphaned ...\n"]; }; }; IF ~v.destroyed AND v.file=NIL AND v.class.flavor=$Typescript THEN IF Rope.Equal[v.name, normalName] OR Rope.Equal[v.name, inputName] THEN MakeOrphan[v ! RuntimeError.UNCAUGHT => CONTINUE]; }; ReallyCreate: PROC [] = { v: ViewerClasses.Viewer _ TypeScript.Create[info: [name: normalName, inhibitDestroy: protected, iconic: FALSE, icon: normalIcon, column: right]]; [in: in, out: out] _ ViewerIO.CreateViewerStreams[name: normalName, viewer: v, editedStream: TRUE]; viewer _ v; IO.PutRope[log, "log viewer created\n"]; IO.Flush[log]; }; oldOut: IO.STREAM _ out; oldIn: IO.STREAM _ in; IF oldOut#NIL AND oldIn#NIL AND ~protected THEN { v: ViewerClasses.Viewer; err: BOOL _ FALSE; v _ ViewerIO.GetViewerFromStream[oldOut]; IF v#NIL AND ~v.destroyed AND (v=ViewerIO.GetViewerFromStream[oldIn]) THEN { IO.Flush[oldOut ! RuntimeError.UNCAUGHT => {err _ TRUE; CONTINUE}]; IF ~err THEN IO.Reset[oldOut ! RuntimeError.UNCAUGHT => {err _ TRUE; CONTINUE}]; IF ~err THEN IO.Reset[oldIn ! RuntimeError.UNCAUGHT => {err _ TRUE; CONTINUE}]; IF ~err THEN { v.icon _ normalIcon; IF ~v.destroyed THEN { [in: in, out: out] _ ViewerIO.CreateViewerStreams[name: normalName, viewer: v, editedStream: TRUE]; viewer _ v; IO.PutRope[log, "usage of different LogViewer viewer\n"]; IO.Flush[log]; RETURN; }; }; }; }; ViewerOps.EnumerateViewers[FindOldGuys ! RuntimeError.UNCAUGHT => CONTINUE]; ReallyCreate[] }; InternalPut: PROC [text: ROPE] = { IF viewer=NIL OR viewer.destroyed THEN InternalCreate[FALSE]; IO.PutRope[out, text ! IO.Error => { IF ec=StreamClosed THEN { InternalCreate[TRUE]; IO.PutRope[out, text]; CONTINUE } }]; IO.PutRope[log, text]; shouldFlush _ TRUE; }; PutRope: PUBLIC PROC [text: ROPE] = { ENABLE UNWIND => Leave[]; Enter[]; InternalPut[text]; Leave[] }; PutRopes: PUBLIC PROC [t1, t2, t3: ROPE] = { ENABLE UNWIND => Leave[]; Enter[]; InternalPut[t1]; InternalPut[t2]; InternalPut[t3]; Leave[] }; PutF: PUBLIC PROC [format: ROPE _ NIL, v1, v2, v3, v4, v5: IO.Value] = { ENABLE UNWIND => Leave[]; Enter[]; IF viewer=NIL OR viewer.destroyed THEN InternalCreate[FALSE]; IO.PutF[out, format, v1, v2, v3, v4, v5 ! IO.Error => { IF ec=StreamClosed THEN { InternalCreate[TRUE]; IO.PutF[out, format, v1, v2, v3, v4, v5]; CONTINUE } } ]; IO.PutF[log, format, v1, v2, v3, v4, v5]; shouldFlush _ TRUE; Leave[] }; PutF1: PUBLIC PROC [format: ROPE _ NIL, value: IO.Value] = { ENABLE UNWIND => Leave[]; Enter[]; IF viewer=NIL OR viewer.destroyed THEN InternalCreate[FALSE]; IO.PutF1[out, format, value ! IO.Error => { IF ec=StreamClosed THEN { InternalCreate[TRUE]; IO.PutF1[out, format, value]; CONTINUE } } ]; IO.PutF[log, format, value]; shouldFlush _ TRUE; Leave[] }; RequestRope: PUBLIC PROC [prompt: ROPE _ NIL, timeOut: NAT] RETURNS [ROPE] = { RETURN [IF timeOut=0 THEN RequestRope0[prompt] ELSE RequestRope1[prompt, timeOut]] }; IOState: TYPE = {ok, repeat, abort, undef}; InternalGetLine: PROC [promp: ROPE] RETURNS [line: ROPE, state: IOState_ok] = { ENABLE { IO.Error => IF ec=StreamClosed THEN {state_repeat; CONTINUE}; EditedStream.Rubout => {state_abort; IO.Reset[in]; CONTINUE}; RuntimeError.UNCAUGHT => {state_repeat; CONTINUE}; }; IF viewer.iconic THEN ViewerOps.OpenIcon[viewer]; InternalPut[promp]; IO.Flush[out ! RuntimeError.UNCAUGHT => CONTINUE]; ViewerTools.SetSelection[viewer]; line _ IO.GetLineRope[in]; IF Rope.Find[line, del]>=0 THEN state_abort; }; RequestRope0: PROC [prompt: ROPE _ NIL] RETURNS [r: ROPE] = { DoIt: PROC [] = {[r, state] _ InternalGetLine[prompt]}; state: IOState; DO ReaderProtected[DoIt]; SELECT state FROM ok => RETURN; repeat => PutRope["XXX\n"]; abort => {PutRope[" ..user abort\n"]; SIGNAL UserAbort} ; ENDCASE => {PutRope[" ..??\n"]; SIGNAL UserAbort}; ENDLOOP; }; xProcess: PROCESS; xStateCondition: CONDITION; xState: IOState _ undef; xResult: ROPE; RequestRope1: PUBLIC PROC [prompt: ROPE, timeOut: NAT] RETURNS [result: ROPE] = { state: IOState; DoIt: PROC [] = { xState _ undef; IF timeOut=0 THEN TRUSTED {Process.DisableTimeout[@xStateCondition]} ELSE TRUSTED { Process.SetTimeout[@xStateCondition, Process.SecondsToTicks[timeOut]] }; ForkRopeGetter[prompt]; TRUSTED {JOIN xProcess}; state _ xState; result _ xResult; IF state=ok THEN IF Rope.Find[result, del]>=0 THEN state _ abort }; DO ReaderProtected[DoIt]; SELECT state FROM ok => RETURN; repeat => PutRope["XXX\n"]; abort => {PutRope[" ..user abort\n"]; SIGNAL UserAbort} ; undef => SIGNAL TimedOut ENDCASE => {PutRope[" ..??\n"]; SIGNAL UserAbort}; ENDLOOP }; ForkRopeGetter: ENTRY PROC [prompt: ROPE_NIL] = { ENABLE UNWIND => NULL; xProcess _ FORK ForkedTryToGetRope[prompt]; WAIT xStateCondition; IF xState#ok AND xState#abort THEN TRUSTED {Process.Abort[xProcess]}; }; SetGlobalState: ENTRY PROC [s: IOState] = { ENABLE UNWIND => NULL; Process.CheckForAbort[]; xState _ s; BROADCAST xStateCondition; }; ForkedTryToGetRope: PROC [prompt: ROPE_NIL] = { ReallyTryToGetRope: PROC [prompt: ROPE] = { d: IOState; DoIt: PROC [] = { ENABLE { UNWIND => IO.Reset[in]; IO.Error => IF ec=StreamClosed THEN {d_repeat; IO.Reset[in]; CONTINUE}; EditedStream.Rubout => {d_abort; IO.Reset[in]; CONTINUE}; }; InternalPut[prompt]; IF viewer.iconic THEN ViewerOps.OpenIcon[viewer]; xResult _ IO.GetLineRope[in]; d _ ok; }; DO d _ undef; DoIt[]; IF d=ok OR d=abort THEN {SetGlobalState[d]; RETURN}; IF d=repeat THEN InternalPut["XXX\n"] ENDLOOP; }; ReallyTryToGetRope[prompt ! ABORTED => GOTO NeverMind] EXITS NeverMind => NULL; }; CreateStream: PUBLIC PROC [] RETURNS [stream: IO.STREAM] = { IF viewer=NIL OR viewer.destroyed THEN Create[FALSE]; RETURN[IO.CreateStream[streamProcs: myStreamProcs, streamData: NIL]]; }; myStreamProcs: REF IO.StreamProcs _ IO.CreateStreamProcs[ variety: $output, class: $LogViewer, putChar: MyPutChar, putBlock: MyPutBlock, unsafePutBlock: MyUnsafePutBlock, flush: MyFlush, eraseChar: MyEraseChar, reset: MyFlush, close: MyClose ]; MyPutChar: PROC [self: IO.STREAM, char: CHAR] = { ENABLE UNWIND => Leave[]; Enter[]; IO.PutChar[out, char ! IO.Error => { IF ec=StreamClosed THEN { InternalCreate[TRUE]; IO.PutChar[out, char]; CONTINUE } }]; IO.PutChar[log, char]; shouldFlush _ TRUE; Leave[]; }; MyPutBlock: PROC [self: IO.STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = { ENABLE UNWIND => Leave[]; Enter[]; IO.PutBlock[out, block, startIndex, count ! IO.Error => { IF ec=StreamClosed THEN { InternalCreate[TRUE]; IO.PutBlock[out, block, startIndex, count]; CONTINUE } }]; IO.PutBlock[log, block, startIndex, count]; shouldFlush _ TRUE; Leave[]; }; MyUnsafePutBlock: PROC [self: IO.STREAM, block: IO.UnsafeBlock] = { ENABLE UNWIND => Leave[]; Enter[]; IO.UnsafePutBlock[out, block ! IO.Error => { IF ec=StreamClosed THEN { InternalCreate[TRUE]; IO.UnsafePutBlock[out, block]; CONTINUE } }]; IO.UnsafePutBlock[log, block]; shouldFlush _ TRUE; Leave[]; }; MyFlush: PROC [self: IO.STREAM] = { IO.Flush[log]; }; MyEraseChar: PROC [self: IO.STREAM, char: CHAR] = { }; MyClose: PROC [self: IO.STREAM, abort: BOOL] = { IO.Flush[log]; }; CreateLog: PROC [] = { log _ FS.StreamOpen[fileName: "LogViewer.log", accessOptions: create, keep: 5]; IO.PutF1[log, "log file for LogViewer created %g\n", IO.time[]] }; Command: Commander.CommandProc = { IF Rope.Match["*open*", cmd.commandLine, FALSE] THEN { PutRope["open LogViewer viewer\n"]; --side effect: creates viewer ViewerOps.OpenIcon[viewer]; }; IF Rope.Match["*new*", cmd.commandLine, FALSE] THEN { oldLog: IO.STREAM _ log; PutRope["start new LogViewer.log file\n"]; CreateLog[]; IO.Close[oldLog]; }; }; CheckInhibitDestroy: ENTRY PROC [] = { v: ViewerClasses.Viewer _ viewer; IF v#NIL AND ~occupied THEN v.inhibitDestroy _ FALSE; }; Flusher: PROC [] = { flush: BOOL; DO Process.Pause[Process.SecondsToTicks[40]]; IF flush _ shouldFlush THEN { shouldFlush _ FALSE; IO.Flush[log ! RuntimeError.UNCAUGHT => CONTINUE]; }; CheckInhibitDestroy[]; ENDLOOP }; CreateLog[]; normalIcon _ Icons.NewIconFromFile["LogViewer.icons", 0 ! RuntimeError.UNCAUGHT => CONTINUE]; inputIcon _ Icons.NewIconFromFile["LogViewer.icons", 1 ! RuntimeError.UNCAUGHT => CONTINUE]; Commander.Register["///Commands/LogViewer", Command, "usage {LogViewer ~ | open | new}"]; TRUSTED {Process.Detach[FORK Flusher]}; END. LogViewerImpl.mesa Copyright c 1983, 1986 by Xerox Corporation. All rights reserved. Created by Christian Jacobi August 3, 1983 9:54 am Last edited by: Christian Jacobi, September 2, 1986 1:52:44 pm PDT --using a backing file for viewer makes log unaccessible --whether log file should be flushed -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --locking procedures -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --creation of viewer --its ok to risk creating accidently too many streams or viewer's --since this won't cause any wedge but only discomfort [orphaned viewers lying around] --afterwards in any case: viewer #NIL (doesnt really mean good, but certainly not NIL) --try re-using old pieces, but only if not from input --we dare trying to reuse a split viewer, --but first we try whether it wont cause errors --try to mark other [split] viewers as bad --the actual creation -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --short cuts --asking for viewer.destroyed helps to discover bad splits, but is not mandatory --actual inline usage allow client usage of formatting --actual inline usage to allow client usage of formatting -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --input procedures -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --stream output stuff -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --log and commands --directly flushing after each output would make LogViewer far to slow 1#code "cedar" styleK "cedar" style m7BK "cedar" style22K "cedar" styleBK "cedar" style "cedar" stylek K "cedar" style (K "cedar" style  K "cedar" styleK "cedar" style"-K "cedar" style 7GK "cedar" styleK "cedar" style`mK "cedar" style)K "cedar" style K "cedar" style K "cedar" style #K "cedar" style K "cedar" style ,:K "cedar" style 8GK "cedar" style !K "cedar" style "cedar" stylen K "cedar" styleKK "cedar" style K "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style !K "cedar" style  K "cedar" styleK "cedar" style#K "cedar" style K "cedar" styleK "cedar" style  K "cedar" style $3K "cedar" style((K "cedar" style K "cedar" style "cedar" styleK "cedar" style8 "cedar" style K "cedar" style$K "cedar" styleK "cedar" style;;K "cedar" styleK "cedar" styleK "cedar" style c)K "cedar" style +#]K "cedar" style "cedar" styleK "cedar" styleK "cedar" style $K "cedar" style K "cedar" styleK "cedar" style "cedar" styleK "cedar" styleK "cedar" style K "cedar" style K "cedar" styleK "cedar" style "cedar" style K "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style K "cedar" style  HK "cedar" styleK "cedar" style  GK "cedar" styleK "cedar" styleK "cedar" style""K "cedar" styleK "cedar" style))K "cedar" styleK "cedar" style "cedar" style K "cedar" style!!K "cedar" style33 "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style5OK "cedar" style"K "cedar" styleK "cedar" styleEK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style K "cedar" styleK "cedar" styleK "cedar" style "cedar" style 1K "cedar" styleK "cedar" style 1 "cedar" styleK "cedar" style  * "cedar" style "cedar" style %K "cedar" style  .K "cedar" styleK "cedar" styleK "cedar" style "cedar" style "cedar" style 1K "cedar" style,K "cedar" styleK "cedar" styleK "cedar" style "cedar" style "cedar" style 1K "cedar" style,K "cedar" styleK "cedar" styleK "cedar" style "cedar" style#K "cedar" styleK "cedar" style""K "cedar" styleK "cedar" styleK "cedar" style;;K "cedar" styleK "cedar" style "cedar" style "K "cedar" styleBBK "cedar" styleWWK "cedar" styleK "cedar" styleK "cedar" style "cedar" style *K "cedar" styleNbW "cedar" style # "cedar" style . "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style%%K "cedar" style( 8K "cedar" style""K "cedar" style99K "cedar" styleK "cedar" style "cedar" style B "cedar" style GK "cedar" style2K "cedar" style "cedar" style K "cedar" styleh$K "cedar" style]cK "cedar" style K "cedar" style&(K "cedar" style K "cedar" styleK "cedar" style5K "cedar" styleK "cedar" style "cedar" style  2K "cedar" styleK "cedar" styleK "cedar" style)) "cedar" style )MK "cedar" style**K "cedar" style//K "cedar" style CK "cedar" style  PK "cedar" style  O "cedar" styleK "cedar" style "cedar" styleK "cedar" style]cK "cedar" style K "cedar" style8 HK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style*K "cedar" style6LK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style88K "cedar" style K "cedar" style "cedar" style " "cedar" style =K "cedar" styleQQ "cedar" style $ "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style#*K "cedar" styleK "cedar" style "cedar" style %K "cedar" style K "cedar" style##K "cedar" styleK "cedar" style "cedar" style ,K "cedar" style K "cedar" styleCCK "cedar" styleK "cedar" style "cedar" style   HK "cedar" style77K "cedar" style K "cedar" styleK "cedar" style = "cedar" style&( "cedar" style  "cedar" styleK "cedar" styleK "cedar" style')K "cedar" styleK "cedar" styleK "cedar" styleK "cedar" styleK "cedar" style6=K "cedar" styleK "cedar" style "cedar" style