<> <> <> <> <> <> <> <<>> <> <> <<>> <> <> <<>> <> <> 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; <Top>X.DF>> 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]; }.