<> <> <> DIRECTORY Commander USING [CommandProc, Register], FS, FSRope USING [StreamFromRope], IO, Process USING [Detach], RefText, Rope USING [ROPE], ViewerClasses USING [Viewer], ViewerIO USING [CreateViewerStreams], ViewerOps USING [FindViewer, OpenIcon], ViewerTools USING [TiogaContents, TiogaContentsRec], WalnutKernelDefs USING [LogEntry, MsgLogEntry], WalnutOps USING [CreateMsg], WalnutStream USING [Open, FindNextEntry, PeekEntry, ReadEntry], WalnutWindow USING [OutCome, QueueCall]; ScanFileForMsgs: CEDAR PROGRAM IMPORTS Commander, FS, FSRope, IO, Process, RefText, ViewerIO, ViewerOps, WalnutOps, WalnutStream, WalnutWindow = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; out: STREAM _ NIL; TSStream: PROC[name: ROPE] RETURNS [IO.STREAM] = { v: ViewerClasses.Viewer _ ViewerOps.FindViewer[name]; out: IO.STREAM _ ViewerIO.CreateViewerStreams[name, v].out; IF v#NIL THEN IF v.iconic THEN ViewerOps.OpenIcon[v]; RETURN[out]; }; SetupScan: PROC[commandLine: ROPE] = { clStream: STREAM _ FSRope.StreamFromRope[commandLine]; strm: STREAM; length, startPos, endPos: INT; file: ROPE; outCome: WalnutWindow.OutCome; out: STREAM _ TSStream["Walnut Rescue"]; numMsgs: INT _ 0; Scan: PROC RETURNS[doReset: BOOL] = { strm.SetIndex[startPos]; numMsgs _ DoScan[strm, out, startPos, endPos]; RETURN[TRUE]; }; out.PutRope["\n\n************************************************************\n"]; out.PutF["\t\tScanForMsgs, started @ %g\n", IO.time[] ]; strm _ WalnutStream.Open[name: file, readOnly: TRUE ! FS.Error => CONTINUE]; file _ clStream.GetTokenRope[IO.IDProc ! IO.EndOfStream => CONTINUE].token; IF file = NIL THEN { out.PutRope["No input file specified - quitting\n"]; RETURN; }; strm _ WalnutStream.Open[name: file, readOnly: TRUE ! FS.Error => CONTINUE]; IF strm = NIL THEN { out.PutF["Could not open %g - quitting ..\n", IO.rope[file] ]; RETURN }; startPos _ clStream.GetInt[ ! IO.EndOfStream => { startPos _ 0; CONTINUE}]; endPos _ clStream.GetInt[ ! IO.EndOfStream => { endPos _ LAST[INT]; CONTINUE}]; length _ strm.GetLength[]; IF endPos > length THEN endPos _ length; IF startPos >= length THEN { out.PutF[" StartPos (%g) is >= length (%g) - quitting ..\n", IO.int[startPos], IO.int[length]]; strm.Close[]; RETURN; }; out.PutF["\n Scanning the file %g, looking at [%g .. %g]\n\n", IO.rope[file], IO.int[startPos], IO.int[endPos] ]; outCome _ WalnutWindow.QueueCall[Scan]; SELECT outCome FROM ok => out.PutF[" Call completed ok at %g\n", IO.time[] ]; flushed => out.PutF[" Call was flushed (%g)\n", IO.time[] ]; notRunning => out.PutF[" Walnut is not running at %g\n", IO.time[] ]; ENDCASE => NULL; IF outCome = ok THEN out.PutF[" %g messages were read from %g\n", IO.int[numMsgs], IO.rope[file] ]; strm.Close[]; }; DoScan: PROC[strm, out: STREAM, startPos, endPos: INT] RETURNS[numMsgs: INT] = { ident: ATOM; le: WalnutKernelDefs.LogEntry; mle: WalnutKernelDefs.MsgLogEntry; msgID: REF TEXT _ NEW[TEXT[RefText.line]]; body: ViewerTools.TiogaContents _ NEW[ViewerTools.TiogaContentsRec]; bodyContents: REF TEXT _ NEW[TEXT[5*RefText.page]]; bodyFormatting: REF TEXT _ NEW[TEXT[5*RefText.page]]; length: INT; nonMsgCount: INT _ 0; numMsgs _ 0; DO at: INT _ WalnutStream.FindNextEntry[strm]; IF at > endPos THEN { out.PutF["\nNext entry (%g) is beyond endPos (%g)\n", IO.int[at], IO.int[endPos] ]; RETURN }; IF at = -1 THEN { out.PutRope["\n No more entries\n"]; RETURN }; [ident, msgID, length] _ WalnutStream.PeekEntry[strm]; IF ident = NIL THEN { out.PutF["PeekEntry says no valid entry at %g - quitting", IO.int[at] ]; RETURN }; IF ident # $CreateMsg THEN { IF (nonMsgCount _ nonMsgCount + 1) MOD 10 = 0 THEN out.PutF["{%g}", IO.int[nonMsgCount]] ELSE out.PutChar['!]; strm.SetIndex[at + length]; LOOP; }; le _ WalnutStream.ReadEntry[strm: strm, quick: TRUE].le; mle _ NARROW[le]; IF mle.formatLen # 0 THEN { strm.SetIndex[mle.entryStart+mle.textOffset-1]; bodyContents _ TextFromStream[strm, mle.textLen+1, bodyContents]; bodyFormatting _ TextFromStream[strm, mle.formatLen, bodyFormatting]; } ELSE { strm.SetIndex[mle.entryStart+mle.textOffset]; bodyContents _ TextFromStream[strm, mle.textLen, bodyContents]; bodyFormatting.length _ 0; }; body.contents _ RefText.TrustTextAsRope[bodyContents]; body.formatting _ RefText.TrustTextAsRope[bodyFormatting]; WalnutOps.CreateMsg[RefText.TrustTextAsRope[msgID], body]; IF (numMsgs _ numMsgs + 1) MOD 10 = 0 THEN out.PutF["(%g)", IO.int[numMsgs]] ELSE out.PutChar['.]; ENDLOOP; }; TextFromStream: PROC[strm: STREAM, len: INT, text: REF TEXT] RETURNS[REF TEXT] = { natLen: NAT _ len; bytesRead: INT; IF text = NIL OR len > text.maxLength THEN text _ RefText.New[natLen]; bytesRead _ strm.GetBlock[block: text, startIndex: 0, count: natLen]; IF bytesRead < natLen THEN text.length _ 0; RETURN[text] }; ScanForMsgs: Commander.CommandProc = TRUSTED { Process.Detach[FORK SetupScan[cmd.commandLine]] }; Commander.Register["ScanForMsgs", ScanForMsgs, "Scan a file for walnut msgs; syntax is \"ScanForMsgs file startPos( _ 0) endPos( _ endOfFile)\""]; END. <>