DIRECTORY BcdOps: TYPE USING [BcdBase], Commander: TYPE USING[CommandProc, Register], CWF: TYPE USING [SetCode, SetWriteProcedure, SWF1, SWF2, SWF3, WF0, WF1, WF2, WF3, WF4, WFCR], DFSubr: TYPE USING [AllocateDFSeq, Criterion, DF, DFSeq, FlattenDF, FreeDFSeq, InsertCRs, LookupDF, NextDF, ReadInDir, SortByCap, SortByFileName, StripLongName, TooManyEntries, WriteOut], Directory: TYPE USING [Error, Handle, ignore, Lookup, UpdateDates], File: TYPE USING [Capability, nullCapability, read, Unknown], FQ: TYPE USING[FileQuery, Result], IFSFile: TYPE USING [CantOpen, Close, Error, FileHandle, GetTimes, UnableToLogin], IO: TYPE USING [Handle, PutChar, PutF, rope, UserAborted, STREAM, UserAbort, ResetUserAbort, PutRope], IOMisc: TYPE USING[AskUser], LeafSubr: TYPE USING [Open, PrintLeafAccessFailure, PrintLeafProblem, RemoteMap, StopLeaf], LongString: TYPE USING [AppendString, EquivalentString], ProcBcds: TYPE USING [InnardsObject, InstallAddressesBcd, PrintDepends, ProcDep, ProcMod, ReadInSegmentsBcd, UnstallBcd], Resource: TYPE USING[Acquire, Release, AbortProc], Rope: TYPE USING[Fetch, Find, ROPE, Text, Cat], RopeInline: TYPE USING[InlineFlatten], Space: TYPE USING [Create, Delete, Handle, LongPointer, Map, nullHandle, Unmap, virtualMemory], UnsafeSTP: TYPE USING [Error], STPSubr: TYPE USING [StopSTP], Stream: TYPE USING [Delete, Handle], Subr: TYPE USING [AbortMyself, AllocateString, Any, CheckForModify, CopyString, debugflg, EndsIn, errorflg, FileError, FreeString, GetCreateDateWithSpace, GetRemoteFilenameProp, MakeTTYProcs, NewStream, PackedTime, PrintGreeting, strcpy, SubrStop, TTYProcs, Write], Time: TYPE USING [Current], TimeStamp: TYPE USING[Null, Stamp], UECP: TYPE USING[Argv, Parse], VerifyDFInterface: TYPE USING []; VerifyDFImpl: PROGRAM IMPORTS Commander, CWF, DFSubr, Directory, File, FQ, IFSFile, IO, IOMisc, LeafSubr, LongString, ProcBcds, Resource, Rope, RopeInline, Space, STP: UnsafeSTP, STPSubr, Stream, Subr, Time, UECP EXPORTS VerifyDFInterface = { stdout: IO.Handle; MAXFILES: CARDINAL = 1200; NPAGESINHUGEZONE: CARDINAL = 500; abortProc: Resource.AbortProc = TRUSTED{ in: IO.STREAM = NARROW[data, IO.STREAM]; abort _ in.UserAbort[]; IF abort THEN in.ResetUserAbort[]; }; Main: Commander.CommandProc = TRUSTED { ENABLE UNWIND => [] _ Resource.Release[$VerifyDF]; h: Subr.TTYProcs; in: IO.Handle = cmd.in; out: IO.Handle = cmd.out; success: BOOL _ FALSE; otherOwner: Rope.ROPE _ NIL; [success, otherOwner] _ Resource.Acquire[resource: $VerifyDF, owner: "VerifyDF", waitForIt: FALSE]; IF NOT success THEN { out.PutRope[Rope.Cat["Waiting for ", otherOwner, " to finish..."]]; [success, ] _ Resource.Acquire[resource: $VerifyDF, owner: "VerifyDF", waitForIt: TRUE, abortProc: abortProc, abortProcData: in ]; IF NOT success THEN { out.PutRope["ABORTED\n"]; RETURN; } ELSE out.PutRope["proceeding\n"]; }; h _ Subr.MakeTTYProcs[in, out, NIL, MyConfirm]; VerifyDFUsingProcs[h, cmd.commandLine]; [] _ Resource.Release[$VerifyDF]; }; VerifyDFUsingProcs: PROC[h: Subr.TTYProcs, commandLine: Rope.ROPE] = { strdffilename: LONG STRING _ Subr.AllocateString[100]; strbcdfilename: LONG STRING _ Subr.AllocateString[100]; starttime: Subr.PackedTime; printFlattened: BOOL _ FALSE; checkForOverwrite: BOOL _ TRUE; argv: UECP.Argv _ UECP.Parse[commandLine]; dffilename, bcdfilename, firstname, tok: Rope.ROPE; parm: CARDINAL; flat: Rope.Text; Cleanup: PROC = { STPSubr.StopSTP[]; LeafSubr.StopLeaf[]; Subr.FreeString[strdffilename]; Subr.FreeString[strbcdfilename]; Subr.SubrStop[]; }; { ENABLE { IFSFile.Error, IFSFile.UnableToLogin => { LeafSubr.PrintLeafProblem[reason]; GOTO leave; }; IFSFile.CantOpen => { LeafSubr.PrintLeafAccessFailure[reason]; GOTO leave; }; STP.Error => { CWF.WF0["FTP Error. "L]; IF error ~= NIL THEN CWF.WF2["message: %s, code %u in Stp.Mesa\n"L, error, @code]; GOTO leave; }; Subr.AbortMyself, IO.UserAborted => { h.out.ResetUserAbort[]; CWF.WF0["VerifyDF Aborted.\n"L]; GOTO leave; }; UNWIND => Cleanup[]; }; stdout _ h.out; [] _ CWF.SetWriteProcedure[MyPutChar]; Subr.debugflg _ Subr.errorflg _ FALSE; Subr.PrintGreeting["VerifyDF"L]; starttime _ Time.Current[]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; parm _ 1; DO IF parm >= argv.argc THEN GOTO usage; tok _ argv[parm]; SELECT tok.Fetch[0] FROM '-, '/ => SELECT tok.Fetch[1] FROM 'a, 'A => checkForOverwrite _ FALSE; 'f, 'F => { printFlattened _ TRUE; Subr.debugflg _ TRUE; }; ENDCASE => h.out.PutF["Unknown flag '%s'\n", IO.rope[tok]]; ENDCASE => EXIT; parm _ parm + 1; ENDLOOP; firstname _ argv[parm]; parm _ parm + 1; IF Rope.Find[s1: firstname, s2: ".bcd", case: FALSE] > 0 THEN { bcdfilename _ firstname; dffilename _ NIL; } ELSE { dffilename _ firstname; IF parm < argv.argc THEN bcdfilename _ argv[parm]; }; flat _ RopeInline.InlineFlatten[bcdfilename]; IF flat ~= NIL THEN Subr.strcpy[strbcdfilename, LOOPHOLE[flat]]; flat _ RopeInline.InlineFlatten[dffilename]; IF flat ~= NIL THEN Subr.strcpy[strdffilename, LOOPHOLE[flat]]; VerifyBcds[bcdfilename: strbcdfilename, dffilename: strdffilename, h: h, checkForOverwrite: checkForOverwrite, printFlattened: printFlattened, useHugeZone: TRUE, wantRTVersionID: 0 ! DFSubr.TooManyEntries => { CWF.WF0["Error - Too many entries in all the DF files.\n"L]; CWF.WF0["Try a smaller set of DF files.\n"L]; Subr.errorflg _ TRUE; CONTINUE; } ]; IF Subr.errorflg THEN CWF.WF0["There were Error(s) in the DF file(s).\n"L]; starttime _ Time.Current[] - starttime; CWF.WF1["\nTotal elapsed time for VerifyDF %lr\n"L, @starttime]; EXITS leave => NULL; usage =>CWF.WF0["Usage: VerifyDF DFFileName BCDFileName or VerifyDF BCDFileName or VerifyDF DFFileName\n"L]; }; Cleanup[]; }; VerifyBcds: PUBLIC PROC [bcdfilename, dffilename: LONG STRING, h: Subr.TTYProcs, checkForOverwrite, printFlattened, useHugeZone: BOOL, wantRTVersionID: CARDINAL] = { dfseq, dfseqother: DFSubr.DFSeq _ NIL; goaround: BOOL; ldspace: Space.Handle _ Space.nullHandle; Cleanup: PROC = { DFSubr.FreeDFSeq[@dfseq]; DFSubr.FreeDFSeq[@dfseqother]; IF ldspace ~= Space.nullHandle THEN Space.Delete[ldspace]; ldspace _ Space.nullHandle; }; { ENABLE UNWIND => Cleanup[]; dfseq _ DFSubr.AllocateDFSeq[maxEntries: MAXFILES, zoneType: IF useHugeZone THEN huge ELSE shared]; dfseqother _ DFSubr.AllocateDFSeq[maxEntries: MAXFILES, zoneType: shared]; IF dffilename ~= NIL AND dffilename.length > 0 THEN { IF NOT Subr.Any[dffilename, '.] THEN LongString.AppendString[dffilename, ".DF"L]; DFSubr.FlattenDF[dfseq: dfseq, dffilename: dffilename, h: h, setRecorder: TRUE, checkForOverwrite: checkForOverwrite, printStatus: Subr.debugflg]; IF dfseq.size = 0 THEN GOTO leave; }; IF printFlattened THEN { sfn: LONG STRING _ Subr.AllocateString[100]; root: LONG STRING _ Subr.AllocateString[100]; {ENABLE UNWIND => {Subr.FreeString[sfn]; Subr.FreeString[root]}; Subr.strcpy[root, dffilename]; IF Subr.EndsIn[root, ".df"L] THEN root.length _ root.length - 3; CWF.SWF1[sfn, "%s.Flat"L, root]; IF Subr.CheckForModify[sfn, h] THEN { sh: Stream.Handle _ Subr.NewStream[sfn, Subr.Write]; DFSubr.WriteOut[ dfseq: dfseq, topLevelFile: NIL, outputStream: sh, print: FALSE, altoCompatibility: FALSE, wrapUsingLists: FALSE]; Stream.Delete[sh]; CWF.WF1["Flattened DF file written on %s.\n"L, sfn]; }; }; -- of ENABLE UNWIND Subr.FreeString[sfn]; Subr.FreeString[root]; }; goaround _ TRUE; ldspace _ Space.Create[size: 1, parent: Space.virtualMemory]; Space.Map[ldspace]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; IF bcdfilename ~= NIL AND bcdfilename.length > 0 THEN { wantRTVersionID _ AnalBcd[bcdfilename, dfseq, dfseqother, h, ldspace, wantRTVersionID]; IF dffilename.length = 0 THEN { dfdep: DFSubr.DF _ DFSubr.NextDF[dfseqother]; -- add top-level .Bcd to needed list dfdep.shortname _ Subr.CopyString[bcdfilename, dfseqother.dfzone]; }; } ELSE { anal: BOOL _ FALSE; df: DFSubr.DF; FOR i: CARDINAL IN [0 .. dfseq.size) DO IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; df _ @dfseq[i]; IF df.topmark AND Subr.EndsIn[df.shortname, ".bcd"L]THEN { wantRTVersionID _ AnalBcd[df.shortname, dfseq, dfseqother, h, ldspace, wantRTVersionID]; anal _ TRUE; }; ENDLOOP; IF NOT anal THEN { CWF.WF1["Error - no '+' entries in %s.\n"L, dffilename]; Subr.errorflg _ TRUE; RETURN; }; }; WHILE goaround DO goaround _ FALSE; FOR i: CARDINAL IN [0.. dfseq.size) DO IF NOT dfseq[i].eval AND dfseq[i].need THEN { IF Subr.EndsIn[dfseq[i].shortname, ".bcd"L] OR NOT Subr.Any[dfseq[i].shortname, '.] THEN wantRTVersionID _ AnalBcd[dfseq[i].shortname, dfseq, dfseqother, h, ldspace, wantRTVersionID]; dfseq[i].eval _ TRUE; goaround _ TRUE; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; }; ENDLOOP; ENDLOOP; CheckReadOnlyFiles[dfseq, h, ldspace]; CheckForCommonBlunders[dfseq]; IF dfseqother.size > 0 THEN { shortname: LONG STRING _ Subr.AllocateString[100]; miss: LONG STRING _ Subr.AllocateString[100]; {ENABLE UNWIND => {Subr.FreeString[shortname]; Subr.FreeString[miss]}; CWF.WF0["Missing Entries:\n"L]; [] _ DFSubr.StripLongName[dffilename, NIL, NIL, shortname]; IF shortname.length > 0 THEN CWF.SWF1[miss, "MissingEntries.%s$"L, shortname] ELSE Subr.strcpy[miss, "MissingEntries.DF$"L]; IF Subr.CheckForModify[miss, h] THEN { sh: Stream.Handle; DFSubr.SortByCap[dfseqother, 0, dfseqother.size-1]; FillInCreateDates[dfseqother, ldspace, h]; DFSubr.SortByFileName[dfseqother, 0, dfseqother.size-1, FALSE]; DFSubr.InsertCRs[dfseqother]; sh _ Subr.NewStream[miss, Subr.Write]; DFSubr.WriteOut[dfseq: dfseqother, topLevelFile: NIL, outputStream: sh, print: TRUE]; Stream.Delete[sh]; CWF.WF1["List written on %s.\n"L, miss]; }; }; -- of ENABLE UNWIND Subr.FreeString[shortname]; Subr.FreeString[miss]; } ELSE CWF.WF0["\nNo files were omitted from the DF files.\n"L]; EXITS leave => NULL; }; Cleanup[]; }; AnalBcd: PROC [startsfn: LONG STRING, dfseq, dfseqother: DFSubr.DFSeq, h: Subr.TTYProcs, ldspace: Space.Handle, wantRTVersionID: CARDINAL] RETURNS[newRTVersionID: CARDINAL] = { dftop: DFSubr.DF; innardsobject: ProcBcds.InnardsObject _ [bcdheaderspace: Space.nullHandle]; sfn: LONG STRING _ Subr.AllocateString[100]; skip: BOOL _ FALSE; procMod: ProcBcds.ProcMod = { uns _ NIL; IF rtVersionID > 0 THEN { IF wantRTVersionID = 0 THEN newRTVersionID _ rtVersionID ELSE newRTVersionID _ wantRTVersionID; IF rtVersionID ~= newRTVersionID THEN CWF.WF1["Warning - there are two different RTBcd version stamps (RTBcd.VersionID) mentioned in this DF file. One of the files involved is %s.\n"L, sfn]; }; IF dftop ~= NIL THEN { dftop.eval _ TRUE; IF dftop.versionstamp ~= TimeStamp.Null AND dftop.versionstamp ~= bcdvers THEN { skip _ TRUE; CWF.WF4["Error - the version of %s listed in the DF file is stamped %a, but %s wants it to be of %a.\n"L, dftop.shortname, @bcdvers, dftop.recorder, @dftop.versionstamp]; Subr.errorflg _ TRUE; }; dftop.versionstamp _ bcdvers; Subr.FreeString[dftop.recorder, dfseq.dfzone]; dftop.recorder _ Subr.CopyString[dftop.shortname, dfseq.dfzone]; }; IF (dftop = NIL OR NOT dftop.readonly) AND sourcefile.length > 0 THEN { dfsrc: DFSubr.DF; dfsrc _ DFSubr.LookupDF[dfseq, sourcefile]; IF dfsrc = NIL AND DFSubr.LookupDF[dfseqother, sourcefile] = NIL THEN { CWF.WF3["Error - %s is the source file for %s\n\tbut %s is not in the df file(s).\n"L, sourcefile, sfn, sourcefile]; dfsrc _ DFSubr.NextDF[dfseqother]; dfsrc.shortname _ Subr.CopyString[sourcefile, dfseqother.dfzone]; dfsrc.createtime _ sourcevers.time; Subr.errorflg _ TRUE; }; IF dfsrc.createtime > 0 AND dfsrc.createtime ~= sourcevers.time THEN { CWF.WF4["Error - %s of %lt is the source file for %s,\n\tbut the DF file lists version of %lt.\n"L, dfsrc.shortname, @sourcevers.time, sfn, @dfsrc.createtime]; Subr.errorflg _ TRUE; }; dfsrc.eval _ TRUE; }; }; procDep: ProcBcds.ProcDep = { dfdep: DFSubr.DF; IF skip OR filename.length = 0 THEN RETURN; IF relcode ~= otherdepends AND relcode ~= canignore AND relcode ~= defstype THEN RETURN; IF dfseq.size = 0 OR (dfdep _ DFSubr.LookupDF[dfseq, filename]) = NIL THEN { IF DFSubr.LookupDF[dfseqother, filename] = NIL THEN { CWF.WF2[ "Error - %s is not in the DF file(s),\n\tbut %s depends on it.\n"L, filename, sfn]; Subr.errorflg _ TRUE; dfdep _ DFSubr.NextDF[dfseqother]; dfdep.shortname _ Subr.CopyString[filename, dfseqother.dfzone]; dfdep.versionstamp _ bcdvers; }; } ELSE { IF NOT dfdep.need THEN { IF dftop ~= NIL THEN dfdep.need _ NOT dftop.readonly ELSE dfdep.need _ TRUE; }; IF bcdvers = TimeStamp.Null OR LongString.EquivalentString[filename, sfn] THEN RETURN; IF dfdep.versionstamp = TimeStamp.Null THEN { dfdep.versionstamp _ bcdvers; Subr.FreeString[dfdep.recorder, dfseq.dfzone]; dfdep.recorder _ Subr.CopyString[sfn, dfseq.dfzone]; }; IF bcdvers # dfdep.versionstamp AND dfdep.recorder ~= NIL THEN { IF LongString.EquivalentString[dfdep.shortname, dfdep.recorder] THEN CWF.WF4[ "Error - %s is stamped %a\n but %s wants it to be %a.\n"L, dfdep.shortname, @dfdep.versionstamp, sfn, @bcdvers] ELSE { CWF.WF4[ "Error - %s wants %s of %a\n but %s"L, sfn, dfdep.shortname, @bcdvers, dfdep.recorder]; CWF.WF1[" wants it to be %a.\n"L, @dfdep.versionstamp]; }; Subr.errorflg _ TRUE; }; }; }; {ENABLE { UNWIND => { Subr.FreeString[sfn]; IF innardsobject.fh ~= NIL THEN IFSFile.Close[innardsobject.fh]; innardsobject.fh _ NIL; }; File.Unknown => { CWF.WF1["ERROR File.Unknown - problem reading %s.\n"L, sfn]; GOTO err; }; }; success: BOOL; newRTVersionID _ wantRTVersionID; Subr.strcpy[sfn, startsfn]; IF NOT Subr.Any[sfn, '.] THEN LongString.AppendString[sfn, ".Bcd"L]; dftop _ DFSubr.LookupDF[dfseq, sfn]; IF dftop ~= NIL AND dftop.readonly THEN GO TO return; -- don't analyze readonly things IF dftop ~= NIL THEN [innardsobject.cap, innardsobject.fh] _ CachedBcd[dftop, h, ldspace ! Subr.FileError => { IF error = wrongVersion THEN CWF.WF2[" File %s of %lt cannot be found.\n"L, sfn, @dftop.createtime] ELSE CWF.WF1[" File %s cannot be found.\n"L, sfn]; GOTO err }; IFSFile.UnableToLogin => IF reason = io THEN { CWF.WF1["Unable to analyze - no Leaf server on %s.\n"L, dftop.host]; GOTO err; }; ] ELSE { innardsobject.cap _ Directory.Lookup[ fileName: sfn, permissions: Directory.ignore ! Directory.Error => { CWF.WF1[" File %s cannot be fourd.\n"L, sfn]; GOTO err }]; CWF.WF1["Analyzing %s."L, sfn]; }; CWF.WFCR[]; ProcBcds.ReadInSegmentsBcd[@innardsobject]; ProcBcds.InstallAddressesBcd[@innardsobject]; [success] _ ProcBcds.PrintDepends[innards: @innardsobject, procMod: procMod, procDep: procDep, print: FALSE, calltwice: FALSE, less: TRUE, bcdfilename: sfn]; IF NOT success THEN { CWF.WF1["Error - couldn't analyze %s correctly.\n"L, sfn]; Subr.errorflg _ TRUE; }; IF innardsobject.fh ~= NIL THEN { IFSFile.Close[innardsobject.fh]; innardsobject.fh _ NIL; }; ProcBcds.UnstallBcd[@innardsobject]; EXITS err => Subr.errorflg _ TRUE; return => {}; }; -- of ENABLE UNWIND Subr.FreeString[sfn]; }; CachedBcd: PROC [df: DFSubr.DF, h: Subr.TTYProcs, ldspace: Space.Handle] RETURNS[cap: File.Capability _ File.nullCapability, fh: IFSFile.FileHandle _ NIL] = { localcreatetime: LONG CARDINAL; { cap _ Directory.Lookup[ fileName: df.shortname, permissions: Directory.ignore ! Directory.Error => GOTO notonlocal]; localcreatetime _ Subr.GetCreateDateWithSpace[cap, ldspace]; IF localcreatetime = df.createtime OR (df.createtime = 0 AND df.host = NIL) THEN { CWF.WF1["Analyzing %s."L, df.shortname]; cap _ Directory.UpdateDates[cap, File.read]; RETURN[cap, NIL]; }; EXITS notonlocal => NULL; }; IF LongString.EquivalentString[df.host, "Unknown"L] THEN ERROR Subr.FileError[notFound]; CWF.WF3["Analyzing [%s]<%s>%s."L, df.host, df.directory, df.shortname]; fh _ LeafOpenWithCreate[df.host, df.directory, df.shortname, df.version, df.createtime, df.criterion, h]; -- may raise Subr.FileError }; LeafOpenWithCreate: PROC [host, directory, shortname: LONG STRING, version: CARDINAL, createtime: LONG CARDINAL, criterion: DFSubr.Criterion, tty: Subr.TTYProcs] RETURNS [fh: IFSFile.FileHandle] = { sfn: LONG STRING _ Subr.AllocateString[100]; targetFileName: LONG STRING _ Subr.AllocateString[125]; {ENABLE UNWIND => {Subr.FreeString[sfn]; Subr.FreeString[targetFileName]}; IF version > 0 AND criterion = none AND createtime = 0 THEN CWF.SWF3[sfn, "<%s>%s!%u"L, directory, shortname, @version] ELSE CWF.SWF2[sfn, "<%s>%s"L, directory, shortname]; -- this gets !H fh _ LeafSubr.Open[host, sfn, tty, oldReadOnly]; IF createtime ~= 0 AND IFSFile.GetTimes[fh].create ~= createtime THEN { fres: FQ.Result; remoteVersion: CARDINAL; IFSFile.Close[fh]; [fres: fres, remoteVersion: remoteVersion] _ FQ.FileQuery[host, directory, shortname, version, createtime, FALSE, tty, targetFileName]; SELECT fres FROM foundCorrectVersion => { CWF.SWF3[sfn, "<%s>%s!%u"L, directory, shortname, @remoteVersion]; fh _ LeafSubr.Open[host, sfn, tty, oldReadOnly]; }; foundWrongVersion => ERROR Subr.FileError[wrongVersion]; notFound => ERROR Subr.FileError[notFound]; ENDCASE => ERROR; }; }; -- of ENABLE UNWIND Subr.FreeString[sfn]; Subr.FreeString[targetFileName]; }; CheckReadOnlyFiles: PROC[dfseq: DFSubr.DFSeq, h: Subr.TTYProcs, ldspace: Space.Handle] = { space: Space.Handle _ Space.Create[size: 1, parent: Space.virtualMemory]; fh: IFSFile.FileHandle; bcd: BcdOps.BcdBase; df: DFSubr.DF; cap: File.Capability; bcd _ Space.LongPointer[space]; CWF.WF0["(Examining ReadOnly files.)\n"L]; FOR i: CARDINAL IN [0 .. dfseq.size) DO IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; df _ @dfseq[i]; IF df.readonly AND Subr.EndsIn[df.shortname, "bcd"L] AND df.versionstamp ~= TimeStamp.Null THEN { ENABLE File.Unknown => { CWF.WF1["ERROR File.Unknown - problem reading %s.\n"L, df.shortname]; LOOP; }; df.eval _ TRUE; [cap, fh] _ CachedBcd[df, h, ldspace ! Subr.FileError => { IF error = wrongVersion THEN CWF.WF2[" File %s of %lt cannot be fourd.\n"L, df.shortname, @df.createtime] ELSE CWF.WF1[" File %s cannot be fourd.\n"L, df.shortname]; Subr.errorflg _ TRUE; LOOP; }; IFSFile.UnableToLogin => IF reason = io THEN { CWF.WF1["Unable to analyze - no Leaf server on %s.\n"L, df.host]; LOOP; }; ]; CWF.WFCR[]; IF fh = NIL THEN Space.Map[space, [cap, 1]] ELSE LeafSubr.RemoteMap[space, fh, 0]; IF bcd.version ~= df.versionstamp THEN { CWF.WF3["Error - %s of %lt has a version stamp of %a,\n"L, df.shortname, @df.createtime, @bcd.version]; CWF.WF2["\tbut %s wants one with version stamp %a.\n"L, df.recorder, @df.versionstamp]; Subr.errorflg _ TRUE; }; Space.Unmap[space]; IF fh ~= NIL THEN IFSFile.Close[fh]; }; ENDLOOP; Space.Delete[space]; }; FillInCreateDates: PROC[dfseq: DFSubr.DFSeq, ldspace: Space.Handle, h: Subr.TTYProcs] = { df: DFSubr.DF; bcd: BcdOps.BcdBase; space: Space.Handle _ Space.Create[size: 1, parent: Space.virtualMemory]; host: LONG STRING _ Subr.AllocateString[30]; directory: LONG STRING _ Subr.AllocateString[100]; fullname: LONG STRING _ Subr.AllocateString[125]; short: LONG STRING _ Subr.AllocateString[100]; FillDefs: PROC = { IF df.host = NIL THEN df.host _ Subr.CopyString["Unknown"L, dfseq.dfzone]; IF df.directory = NIL THEN df.directory _ Subr.CopyString["Unknown"L, dfseq.dfzone]; }; Cleanup: PROC = { Subr.FreeString[host]; Subr.FreeString[directory]; Subr.FreeString[fullname]; Subr.FreeString[short]; Space.Delete[space]; }; {ENABLE UNWIND => Cleanup[]; CWF.WF0["(Filling in create dates from files on local disk... "L]; DFSubr.ReadInDir[dfseq]; FOR i: CARDINAL IN [0 .. dfseq.size) DO { IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; df _ @dfseq[i]; IF NOT df.presentonlocaldisk THEN GOTO next; IF Subr.EndsIn[df.shortname, "bcd"L] AND df.createtime = 0 AND df.versionstamp ~= TimeStamp.Null THEN { Space.Map[space, [df.cap, 1]]; bcd _ Space.LongPointer[space]; IF df.versionstamp = bcd.version THEN { df.createtime _ Subr.GetCreateDateWithSpace[df.cap, ldspace]; Subr.GetRemoteFilenameProp[df.cap, fullname]; IF fullname.length > 0 THEN { [] _ DFSubr.StripLongName[fullname, host, directory, short]; IF LongString.EquivalentString[short, df.shortname] AND host.length > 0 AND directory.length > 0 THEN { IF df.host ~= NIL THEN Subr.FreeString[df.host, dfseq.dfzone]; df.host _ Subr.CopyString[host, dfseq.dfzone]; IF df.directory ~= NIL THEN Subr.FreeString[df.directory, dfseq.dfzone]; df.directory _ Subr.CopyString[directory, dfseq.dfzone]; Space.Unmap[space]; LOOP; -- avoid FillDefs } }; }; Space.Unmap[space]; } ELSE IF df.createtime ~= 0 AND df.createtime = Subr.GetCreateDateWithSpace[df.cap, ldspace] THEN { Subr.GetRemoteFilenameProp[df.cap, fullname]; IF fullname.length > 0 THEN { [] _ DFSubr.StripLongName[fullname, host, directory, short]; IF LongString.EquivalentString[short, df.shortname] AND host.length > 0 AND directory.length > 0 THEN { IF df.host ~= NIL THEN Subr.FreeString[df.host, dfseq.dfzone]; df.host _ Subr.CopyString[host, dfseq.dfzone]; IF df.directory ~= NIL THEN Subr.FreeString[df.directory, dfseq.dfzone]; df.directory _ Subr.CopyString[directory, dfseq.dfzone]; LOOP; -- avoid FillDefs } }; }; GOTO next; EXITS next => FillDefs[]; }; ENDLOOP; }; -- of ENABLE UNWIND Cleanup[]; CWF.WF0["done.)\n"L]; }; CheckForCommonBlunders: PROC[dfseq: DFSubr.DFSeq] = { df: DFSubr.DF; p: BOOL; p _ FALSE; FOR i: CARDINAL IN [0 .. dfseq.size) DO df _ @dfseq[i]; IF NOT df.readonly AND df.releaseDirectory = NIL THEN { IF NOT p THEN { CWF.WF2["Warning - these files are in directories that are not ReadOnly and have no ReleaseAs or CameFrom clause.\n\t%s in %s"L, df.shortname, df.recorder]; p _ TRUE; } ELSE CWF.WF2[", %s in %s"L, df.shortname, df.recorder]; }; ENDLOOP; IF p THEN CWF.WFCR[]; p _ FALSE; p _ FALSE; FOR i: CARDINAL IN [0 .. dfseq.size) DO df _ @dfseq[i]; IF NOT df.cameFrom AND df.releaseDirectory ~= NIL AND (Count[df.releaseDirectory, '>] > 1 OR Subr.EndsIn[df.releaseDirectory, ".df"L]) THEN { IF NOT p THEN { CWF.WF2["Warning - the ReleaseAs clauses for these files may be incorrect.\n\t%s in %s"L, df.shortname, df.recorder]; p _ TRUE; } ELSE CWF.WF2[", %s in %s"L, df.shortname, df.recorder]; }; ENDLOOP; IF p THEN CWF.WFCR[]; p _ FALSE; FOR i: CARDINAL IN [0 .. dfseq.size) DO df _ @dfseq[i]; IF NOT df.eval AND (Subr.EndsIn[df.shortname, ".Mesa"L] OR Subr.EndsIn[df.shortname, ".Bcd"L] OR Subr.EndsIn[df.shortname, ".Config"L]) AND NotDuplicated[dfseq, i] THEN { IF NOT p THEN { CWF.WF2["Warning - these files are not needed by any top-level bcd files.\n\t%s in %s"L, df.shortname, df.recorder]; p _ TRUE; } ELSE CWF.WF2[", %s in %s"L, df.shortname, df.recorder]; }; ENDLOOP; IF p THEN CWF.WFCR[]; }; NotDuplicated: PROC [dfseq: DFSubr.DFSeq, i: CARDINAL] RETURNS [BOOL] = { dfi, dfj: DFSubr.DF; dfi _ @dfseq[i]; IF dfi.createtime = 0 THEN RETURN[TRUE]; FOR j: CARDINAL IN [0 .. i) DO dfj _ @dfseq[j]; IF dfj.eval AND dfj.createtime = dfi.createtime AND LongString.EquivalentString[dfj.shortname, dfi.shortname] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; Count: PROC[s: LONG STRING, c: CHAR] RETURNS[nOcurrences: CARDINAL] = { nOcurrences _ 0; FOR i: CARDINAL IN [0 .. s.length) DO IF s[i] = c THEN nOcurrences _ nOcurrences + 1; ENDLOOP; }; CWFAProc: PROC[lp: LONG POINTER, fmt: LONG STRING, wp: PROC[CHARACTER]] = { pts: LONG POINTER TO TimeStamp.Stamp _ lp; hex: PACKED ARRAY [0 .. 12) OF [0 .. 16) _ LOOPHOLE[pts^]; FOR i: CARDINAL IN [0 .. 12) DO IF hex[i] IN [0 .. 9] THEN wp['0 + hex[i]] ELSE wp['A + (hex[i] - 10)]; ENDLOOP; }; MyConfirm: PROC[in, out: IO.Handle, data: REF ANY, msg: Rope.ROPE, dch: CHAR] RETURNS[CHAR] = { value: ATOM; value _ IOMisc.AskUser[msg: msg, in: in, out: out, keyList: LIST[$Yes, $No, $All, $Quit]]; -- order is important SELECT value FROM $All => RETURN['a]; $No => RETURN['n]; $Quit => RETURN['q]; $Yes => RETURN['y]; ENDCASE => ERROR; }; MyPutChar: PROC[ch: CHAR] = { stdout.PutChar[ch]; }; Commander.Register[ key: "VerifyDF", proc: Main, doc: "verify consistency and completeness of a .df file"]; CWF.SetCode['a, CWFAProc]; }. àVerifyDFImpl.Mesa last edit February 4, 1983 11:36 am by Schmidt last edit April 12, 1983 12:33 pm by Paul Rovner last edit May 23, 1983 6:51 pm by Russ Atkinson Usage: VerifyDF dffile where there is at least one "+" in the df file or alternatively VerifyDF bcdfile or alternatively VerifyDF dffile bcdfile if no extension is present on the first argument, assume it is a DF file; an optional /f after VerifyDF and before the args causes verifydf to print the flattened DF file on Flattened.dffile.DF note that calling any procedure in VerifyDFInterface will cause a start trap that will register "VerifyDF"; it is ok to call this from the Simple Exec MDS usage!! end of mds PROC [data: REF ANY] RETURNS[abort: BOOL]; PROC [cmd: Handle] set up WF stuff bcdfilename and dffilename may be stored in! assumes a HugeZone already exists and is available if wantRTVersionID = 0 then simply checks agreement now analyze the BCD; the algorithm used is as follows: initally all .need flags are FALSE, all .eval flags are false for each file we discover, the corresponding .need flag is set to TRUE on the nxt goround, a file is analyzed if .need is TRUE and .eval is FALSE after analysis, the .eval flag is set to TRUE also prints unused entries now print out extra missing entries Analyze Bcd versionstamp rule: versionstamp is set by procMod or first call on procDep, subsequent calls to procDep do not change it dftop, sfn passed from the open check RTBcd.VersionID if not readonly, ask about sourcefile filename will probably have ".bcd" at the end look at otherdepends, canignore, and defstype only sfn, dfseq, dfseqother, skip, and dftop passed in from outside forces analysis only if not READONLY check its the right version enter who recorded this entry if fh is NIL, is local, otherwise remote looks on remote server for file with createtime, enumerates if necessary may raise Subr.FileError look at ReadOnly files to see if their create times agree with their functional stamps fill in create dates for entries where we know the version stamp but don't know their create dates; involves looking on the local disk this is the bcd version stamp check various features of the DF file Directory XXX ReadOnly XXX ReleaseAs YYY doesn't work because Imports look like ReadOnly XXX ReleaseAs YYY FOR i: CARDINAL IN [0 .. dfseq.size) DO df _ @dfseq[i]; IF df.readonly AND df.releaseDirectory ~= NIL AND NOT df.cameFrom THEN { IF NOT p THEN { CWF.WF2["Warning - these files are in directories that are ReadOnly and also have ReleaseAs clauses.\n\t%s in %s"L, df.shortname, df.recorder]; p _ TRUE; } ELSE CWF.WF2[", %s in %s"L, df.shortname, df.recorder]; }; ENDLOOP; IF p THEN CWF.WFCR[]; ReleaseAs Cedar>Top>X.DF print out warnings about wrong RTBcd version stamps start code ʘJ˜šœ™Jšœ.™.Jšœ0™0Jšœ/™/—J˜šœ™Jšœ™Jšœ.™.J™Jšœ™Jšœ™J™Jšœ™Jšœ™—™JšœÁ™ÁJ˜Jšœ–™–J˜—šÏk ˜ Jšœœœ ˜Jšœ œœ˜-šœœ˜JšœHœ˜N—šœœ˜JšœœŒ˜©—Jšœ œœ.˜CJšœœœ-˜=Jšœœœ˜"Jšœ œœ?˜Ršœœ˜Jšœ+œ&˜W—Jšœœœ ˜šœ œ˜JšœF˜F—Jšœ œœ"˜8šœ œ˜Jšœe˜e—Jšœ œœ˜2Jšœœœœ ˜/Jšœ œœ˜&šœœ˜JšœM˜M—Jšœ œœ ˜Jšœ œœ ˜Jšœœœ˜$šœœ˜Jšœù˜ù—Jšœœœ ˜Jšœ œœ˜#Jšœœœ˜Jšœœœ˜!J˜—šœ˜š˜Jš œ œœ œMœ*˜¶—Jšœ˜—˜šœ ™ Jšœœ˜Jšœ ™ —J˜Jšœœ˜Jšœœ˜!J˜—Jšœ œ˜(šœ*™*Jš œœœœœœ˜(J˜Jšœœ˜"J˜J˜—šœœ˜'Jšœ™Jšœœ%˜2J˜Jšœœ˜Jšœœ˜Jšœ œœ˜Jšœœœ˜˜=J˜Jšœ œ˜—šœœ˜šœ˜J˜C˜3J˜Jšœ œ˜J˜J˜J˜—šœœ œ˜J˜Jšœ˜Jšœœ˜#—J˜J˜——Jšœœ ˜/J˜'J˜!J˜J˜—šÏnœœ%œ˜FJšœœœ˜6Jšœœœ˜7J˜Jšœœœ˜Jšœœœ˜Jšœœœ˜*Jšœ.œ˜3Jšœœ˜J˜J˜šžœœ˜J˜J˜Jšœ˜Jšœ ˜ J˜J˜J˜—˜šœ˜˜)J˜"Jšœ˜ J˜—˜J˜(Jšœ˜ J˜—šœ ˜Jšœ˜šœ œœ˜Jšœ:˜=—Jšœ˜ J˜—šœœ˜%J˜Jšœ˜ Jšœ˜ J˜—Jšœ˜J˜J˜—Jšœ™J˜Jšœœ˜&Jšœ œ˜&J˜ J˜Jšœœœ˜1J˜J˜ š˜Jšœœœ˜%J˜šœ˜šœ ˜ šœ˜˜ Jšœœ˜—˜ Jšœœ˜Jšœœ˜J˜—Jšœ&œ ˜;——Jšœœ˜—J˜Jšœ˜—J˜J˜šœ,œœ˜?J˜Jšœ œ˜J˜—šœ˜J˜Jšœœ˜2J˜J˜—J˜-Jšœ œœœ˜@J˜,Jšœ œœœ˜?Jšœ,™,˜IJ˜FJšœ œ˜%˜Jšœ9˜Jš˜Jšœ œ˜J˜J˜ J˜J˜—šžœ˜ Jšœ œœ]œ˜}Jšœœ˜%Jšœ ™ Jšœœ˜J˜KJšœœœ˜,Jšœœœ˜J˜šœ™Jšœ™Jšœ6™6Jšœ™J˜—˜Jšœ™Jšœœ˜ Jšœ™šœœ˜Jšœœ˜8Jšœ"˜&šœœ˜&šœ‘˜”J˜——J˜šœ œœ˜Jšœ œ˜šœ&œœ˜PJšœœ˜ šœf˜iJ˜J˜%—Jšœœ˜J˜—J˜J˜.J˜@J˜——š œ œœœœœ˜JJšœ%™%Jšœœ˜J˜+Jšœ œœ+˜@šœ˜šœS˜VJ˜—J˜"˜.J˜—J˜#Jšœœ˜J˜—šœœ%œ˜Fšœ`˜cJ˜;—Jšœœ˜J˜—Jšœ œ˜J˜—J˜J˜—˜Jšœ-™-Jšœ2™2Jšœ>™>Jšœœ˜Jšœœœœ˜+šœœ˜4Jšœœœ˜$—šœœ.˜Ešœ˜šœ)˜.šœ˜šœ˜JšœC˜CJ˜—Jšœœ˜J˜"˜,J˜—J˜J˜——J˜—šœ˜šœœ œ˜Jšœ$™$Jšœ œœœ˜4Jšœœ˜J˜—J™Jšœ™šœœ,œ˜OJšœ˜—šœ%œ˜-J˜Jšœ™J˜.J˜4J˜—šœœœœ˜@šœ=˜?šœ˜šœ˜JšœA˜AJ˜4——šœ˜šœ˜Jšœ-˜-J˜0—Jšœ4˜7J˜——Jšœœ˜J˜—J˜——J˜J˜—šœœ˜ šœ˜ Jšœ˜Jšœœœ!˜@Jšœœ˜J˜—˜Jšœ9˜—šœœ œ˜Jšœ7˜:Jšœœ˜J˜—šœœœ˜!J˜ Jšœœ˜J˜—J˜$š˜Jšœœ˜Jšœ ˜ —JšœŸœ˜—Jšœ˜Jšœ˜J˜—šž œ˜Jšœ œ+˜9JšœFœ˜UJšœ(™(Jšœœœ˜˜˜J˜5Jšœœ ˜&—J˜<š œ!œœ œœ˜RJšœ%˜(J˜,Jšœœ˜J˜—Jšœœ˜J˜—šœ2œ˜9Jšœ˜—JšœD˜G˜HJšœ!Ÿ˜<—J˜J˜—šžœ˜Jš œœœ œœœ3œ˜­JšœH™HJšœ™Jšœœœ˜,Jšœœœ˜7šœœœ<˜Jšœ œœ˜6Jšœ8˜@Jšœœ-Ÿ˜D—J˜0šœœ+œ˜GJšœœ˜Jšœœ˜J˜šœ-œ˜KJšœ œ˜<—šœœ˜˜Jšœ?˜BJ˜0J˜—˜Jšœ˜#—˜ Jšœ˜—Jšœœ˜—J˜—JšœŸœ˜—Jšœ6˜6J˜J˜—šžœœB˜ZJšœV™VJ˜IJ˜J˜Jšœ œ˜J˜J˜Jšœ'˜*šœœœ˜'Jšœœœ˜1J˜Jšœ ˜Jšœ"˜%šœ#œ˜,šœ˜JšœB˜EJšœ˜J˜—Jšœ œ˜˜$˜šœœ˜šœ.˜1J˜——Jšœœ5˜=Jšœœ˜Jšœ˜J˜˜šœ œ˜Jšœ>˜AJšœ˜J˜———J˜—Jšœœ˜ šœœœ˜J˜—Jšœ"˜&šœ œ˜(šœ7˜:J˜,—šœ4˜7J˜—Jšœœ˜J˜—J˜Jšœœœ˜$J˜—Jšœ˜—J˜J˜J˜—šžœœB˜YJšœ‡™‡Jšœ œ˜J˜J˜IJšœœœ˜,Jšœ œœ˜2Jšœ œœ˜1Jšœœœ˜.J˜šžœœ˜šœ œœ˜J˜4—šœœœ˜J˜9—J˜J˜—šžœœ˜Jšœ2˜2Jšœ2˜2J˜J˜J˜—šœœœ˜Jšœ?˜BJ˜šœœœ˜'˜Jšœœœ˜1J˜Jšœœœœ˜,šœ#œ˜;Jšœ#œ˜,J˜J˜Jšœ™šœœ˜(J˜=J˜-šœœ˜˜*J˜—šœ1˜3Jšœœœ˜3Jšœ œœ(˜>J˜.Jšœœœ-˜HJ˜8J˜JšœŸ˜J˜—J˜—J˜—J˜J˜—Jšœœ˜šœ>œ˜GJ˜-šœœ˜˜*J˜—Jšœ2˜4šœœœ˜3šœ œœ˜J˜'—J˜.šœœœ˜J˜,—J˜8JšœŸ˜J˜—J˜—J˜—Jšœ˜ Jšœ˜J˜—Jšœ˜—JšœŸœ˜—Jšœ ˜ Jšœ˜J˜J˜—šžœœ˜5Jšœ œ˜Jšœœ˜Jšœ%™%Jšœœ˜ Jšœ ™ šœœœ˜'J˜š œœ œœœ˜7šœœœ˜šœ}˜€J˜—Jšœœ˜ J˜—šœ˜Jšœ/˜2—J˜—Jšœ˜—Jšœœœœ˜Jšœœ˜ Jšœ™Jšœ&™&Jšœ™šœ'™'Jšœ™šœH™Hšœ™šœs™sJšœ™—Jšœ ™ Jšœ™—šœ™Jšœ2™2—Jšœ™—Jšœ™—Jšœ™Jšœœ˜ Jšœ™šœœœ˜'J˜Jšœœ ˜Jšœœ˜šœ%˜(Jšœ+œ˜3šœœœ˜šœV˜YJ˜—Jšœœ˜ J˜—šœ˜Jšœ/˜2—J˜—Jšœ˜—Jšœœœœ˜Jšœœ˜ Jšœ3™3šœœœ˜(J˜Jšœœ ˜šœ&˜)Jšœ$˜&Jšœ(˜*—šœœ˜"šœœœ˜šœU˜XJ˜—Jšœœ˜ J˜—š˜Jšœ/˜2—J˜—Jšœ˜—Jšœœœœ˜J˜J˜—š ž œœœœœ˜IJšœœ˜J˜Jšœœœœ˜(šœœœ ˜J˜šœ œ ˜/Jšœ;˜BJšœœ˜—Jšœ˜—Jšœœ˜ J˜J˜—šžœœœœœœœ˜GJ˜šœœœ˜%Jšœ œ˜/Jšœ˜—J˜J˜—šžœœœœœœœ œ˜KJšœœœœ˜*Jš œœœ œ œ˜:šœœœ ˜šœœ ˜Jšœ˜Jšœ˜—Jšœ˜—J˜J˜—šž œœ œœœ œœ˜MJšœœ˜Jšœœ˜ ˜3Jšœ œŸ˜>—šœ˜Jšœœ˜Jšœœ˜Jšœ œ˜Jšœœ˜Jšœœ˜—J˜J˜—šž œœœ˜J˜J˜J˜—šœ ™ ˜J˜J˜ J˜:—Jšœ˜—J˜J˜J˜—…—\ò„è