-- FindBadModules.mesa -- Last modified by Sandman on 24-Feb-83 11:11:29 DIRECTORY BcdDefs, BcdOps, Environment, Exec, FileName, FileTransfer, Format, MSegment USING [Address, Create, Delete, Handle], MStream, PrincOps, Stream; FindBadModules: PROGRAM IMPORTS Exec, FileName, FileTransfer, Format, MSegment, MStream, Stream = BEGIN BYTE: TYPE = PrincOps.BYTE; PrefixHandle: TYPE = PrincOps.PrefixHandle; BcdBase: TYPE = BcdOps.BcdBase; pagesPerBuffer: CARDINAL = 100; buffer: LONG POINTER; conn: FileTransfer.Connection ← NIL; execOut: Format.StringProc; exec: Exec.Handle; Run: Exec.ExecProc = { name, switches: LONG STRING ← NIL; pagesPerBuffer: Environment.PageCount = 100; bufferSegment: MSegment.Handle ← NIL; Finalize: PROC = { IF bufferSegment # NIL THEN { MSegment.Delete[bufferSegment]; bufferSegment ← buffer ← NIL}; IF conn # NIL THEN { FileTransfer.Close[conn]; FileTransfer.Destroy[conn]; conn ← NIL}; IF name # NIL THEN name ← Exec.FreeTokenString[name]; IF switches # NIL THEN switches ← Exec.FreeTokenString[switches]}; BEGIN ENABLE { ABORTED => GO TO aborted; FileTransfer.Error --[code]-- => SELECT code FROM retry => GOTO timedOut; unknown => GOTO fileTransferProblem; ENDCASE; UNWIND => Finalize[]}; exec ← h; execOut ← Exec.OutputProc[h]; bufferSegment ← MSegment.Create[pages: pagesPerBuffer, release: []]; buffer ← MSegment.Address[bufferSegment]; conn ← FileTransfer.Create[]; FileTransfer.SetProcs[ conn: conn, clientData: NIL, messages: PutMessages]; DO [name, switches] ← Exec.GetToken[h]; switches ← Exec.FreeTokenString[switches]; IF name = NIL THEN EXIT; Collect[name]; IF Exec.CheckForAbort[h] THEN {outcome ← abort; EXIT}; ENDLOOP; outcome ← normal; EXITS aborted => { outcome ← abort; Format.CR[execOut]; Format.Line[execOut, "...aborted"L]}; timedOut => { outcome ← error; Format.CR[execOut]; Format.Line[execOut, "...connection timed out!"L]}; fileTransferProblem => { outcome ← error; Format.CR[execOut]; Format.Line[execOut, "...unknown FileTransfer problem!"L]}; END; -- of ENABLE Finalize[]}; PutMessages: FileTransfer.MessageProc = { IF level = fatal THEN { execOut["Fatal error: "L]; IF s1 # NIL THEN execOut[s1]; IF s2 # NIL THEN execOut[s2]; IF s3 # NIL THEN execOut[s3]; IF s4 # NIL THEN execOut[s4]}}; Collect: PROC [name: LONG STRING] = { OPEN FileTransfer; ENABLE Error => IF code = skip THEN CONTINUE; vfn: FileName.VFN ← FileName.AllocVFN[name]; stream: Stream.Handle; stream ← ReadStream[conn, vfn ! UNWIND => FileName.FreeVFN[vfn]]; WHILE stream # NIL DO ENABLE UNWIND => FileName.FreeVFN[vfn]; stream.options.signalEndOfStream ← TRUE; Format.Char[execOut, '.]; CheckFile[stream ! BadFile => { Format.Text[execOut, "\n*** "L]; Format.Line[execOut, FileTransfer.GetStreamName[stream]]; CONTINUE}]; stream ← ReadNextStream[stream ! Error => IF code = skip THEN CONTINUE] ENDLOOP; FileName.FreeVFN[vfn]}; CheckFile: PROC [stream: Stream.Handle] = { tooLong: BOOLEAN ← TRUE; bcd: BcdOps.BcdBase ← buffer; mtb, sgb: BcdDefs.Base; codebase: PrincOps.PrefixHandle; mth: BcdOps.MTHandle; sgh: BcdOps.SGHandle; IF Exec.CheckForAbort[exec] THEN ERROR ABORTED; [] ← Stream.GetBlock[ stream, [buffer, 0, pagesPerBuffer*Environment.bytesPerPage] ! Stream.EndOfStream => {tooLong ← FALSE; CONTINUE}]; IF ~tooLong THEN { bcd ← LOOPHOLE[buffer, BcdOps.BcdBase]; IF bcd.versionIdent # BcdDefs.VersionID THEN GOTO obsoleteBcd; IF bcd.definitions THEN GOTO definitions; IF bcd.tableCompiled THEN GOTO tableCompiled; IF bcd.nConfigs # 0 THEN GOTO binderBcd; IF bcd.nPages > pagesPerBuffer THEN GOTO tooLong; mtb ← LOOPHOLE[bcd + bcd.mtOffset]; mth ← @mtb[FIRST[BcdDefs.MTIndex]]; sgb ← LOOPHOLE[bcd + bcd.sgOffset]; sgh ← @sgb[mth.code.sgi]; -- Bcd's code segment table entry IF sgh.pages + sgh.base > pagesPerBuffer THEN GOTO tooLong; IF sgh.file # BcdDefs.FTSelf THEN GOTO punt; -- tablecompiled, or ... codebase ← LOOPHOLE[buffer + (sgh.base-1)*Environment.wordsPerPage]; sgh ← @sgb[mth.sseg]; -- Bcd's symbol segment table entry IF sgh.file # BcdDefs.FTSelf THEN GOTO punt; -- tablecompiled, or ... IF sgh.pages + sgh.base > pagesPerBuffer THEN GOTO tooLong; IF mth.linkLoc # dontcare THEN ERROR BadFile}; EXITS tooLong => {}; definitions => {}; tableCompiled => {}; obsoleteBcd => {}; binderBcd => {}; punt => {}}; BadFile: ERROR = CODE; -- MAIN BODY CODE Exec.AddCommand[name: "FindBadModules.~", proc: Run]; END.