DIRECTORY Basics USING [Comparison], BasicTime USING [GMT, Now], Commander USING [CommandProc, Handle, Register], CommanderOps USING [Failed, NextArgument], DFUtilities USING [IncludeItem, ParseFromStream, ProcessItemProc], IO, PFS, PFSNames, Process USING [CheckForAbort], RedBlackTree USING [Compare, Create, EachNode, EnumerateIncreasing, GetKey, Insert, Lookup, Table], Rope; CompareDFwithDirImpl: CEDAR MONITOR IMPORTS BasicTime, Commander, CommanderOps, DFUtilities, IO, PFS, PFSNames, Process, RedBlackTree, Rope = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; PATH: TYPE = PFS.PATH; FileEntry: TYPE = REF FileEntryRep; FileEntryRep: TYPE = RECORD [ srcName: ROPE, status: FileEntryStatus ]; FileEntryStatus: TYPE = {dfOnly, dirOnly, both}; fileCount: ARRAY FileEntryStatus OF CARD ¬ ALL[0]; Switches: TYPE = PACKED ARRAY CHAR['a..'z] OF BOOL; bangH: ROPE ~ "!H"; startBangHPath: PATH ~ PFS.PathFromRope["*!H"]; DoIt: PROC[dfNameRope: ROPE, dir: ROPE, switches: Switches, out: STREAM] = { EachEntry: RedBlackTree.EachNode = { WITH data SELECT FROM entry: FileEntry => { IF entry.status # both THEN { SELECT entry.status FROM dfOnly => { out.PutF1["~~dfOnly: %g\n", [rope[entry.srcName]] ]; dfOnlyCount ¬ dfOnlyCount + 1; }; dirOnly => { out.PutF1[" **serverOnly: %g; ", [rope[entry.srcName]] ]; IF prev # NIL THEN out.PutF1["after %g\n", [rope[prev]] ] ELSE out.PutRope["at beginning\n"]; dirOnlyCount ¬ dirOnlyCount + 1; }; ENDCASE; }; fileCount[entry.status] ¬ fileCount[entry.status].SUCC; prev ¬ entry.srcName; Process.CheckForAbort[]; RETURN; }; ENDCASE => ERROR; }; VisitEntry: PROC [name: PATH] = { new: FileEntry ¬ NIL; ropeName: ROPE ¬ PFSNames.ShortNameRope[name]; Process.CheckForAbort[]; WITH RedBlackTree.Lookup[table, ropeName] SELECT FROM entry: FileEntry => RETURN; ENDCASE; WITH RedBlackTree.Lookup[table, ropeName] SELECT FROM entry: FileEntry => RETURN; ENDCASE; new ¬ NEW[FileEntryRep ¬ [ srcName: ropeName, status: dfOnly]]; RedBlackTree.Insert[table, new, ropeName]; }; VisitClosure: PROC [dfName: PATH, visitor: PROC [name: PATH]] = { ENABLE PFS.Error => IF ( error.code = $unknownServer ) OR ( error.code = $unknownFile ) THEN { out.PutF["\n-- ****PFS.Error[%g], in dfFile: %g\n", [rope[error.explanation]], [rope[PFS.RopeFromPath[dfName]]] ]; }; EachItem: DFUtilities.ProcessItemProc = { WITH item SELECT FROM incl: REF DFUtilities.IncludeItem => { path1: PATH ¬ PFS.PathFromRope[incl.path1]; CheckCount[]; visitor[path1]; }; ENDCASE => { i: INT ¬ 0; }; -- handy for setting breakpoints - (bj) }; prefix: PATH ¬ NIL; in: STREAM; in ¬ PFS.StreamOpen[ fileName: dfName ! PFS.Error => IF error.code = $unknownFile THEN { out.PutF["-- PFS.Error[%g] - from dfFile %g\n", [rope[error.explanation]], [rope[PFS.RopeFromPath[dfName]]] ]; in ¬ NIL; inFileNotFound ¬ TRUE; CONTINUE; } ELSE REJECT ]; IF in#NIL THEN { out.PutF["\n***** Building table from %g at %g\n", [rope[dfNameRope]], [time[BasicTime.Now[]]] ]; DFUtilities.ParseFromStream[in, EachItem -- global variable, hack for now! - (bj) ! UNWIND => in.Close[]]; in.Close[] }; }; CheckCount: PROC ~ { IF (count ¬ count + 1) MOD 10 # 0 THEN RETURN; IF count MOD 100 = 0 THEN { out.PutF1["(%g) ", [integer[count]] ]; } ELSE out.PutChar['.] }; count: INT ¬ 0; dfOnlyCount, dirOnlyCount: INT ¬ 0; table: RedBlackTree.Table ¬ RedBlackTree.Create[getKey: GetKey, compare: Compare]; inFileNotFound: BOOL ¬ FALSE; prev: ROPE ¬ NIL; VisitClosure[PFS.PathFromRope[dfNameRope.Concat[bangH]], VisitEntry]; IF inFileNotFound THEN RETURN; ExamineDirectory[dir, table, out, switches]; out.PutF1["\n***** Examining tree at %g\n", [time[BasicTime.Now[]]] ]; RedBlackTree.EnumerateIncreasing[table, EachEntry]; IF dfOnlyCount # 0 THEN out.PutF["\t==> %g files only in %g\n", [integer[dfOnlyCount]], [rope[dfNameRope]] ]; IF dirOnlyCount # 0 THEN out.PutF["\t==> %g files only in %g\n", [integer[dirOnlyCount]], [rope[dir]] ]; out.PutF1["\n{Done at %g}\n", [time[BasicTime.Now[]]] ]; }; ExamineDirectory: PROC[dir: ROPE, table: RedBlackTree.Table, out: STREAM, switches: Switches] = { CheckCount: PROC ~ { IF (count ¬ count + 1) MOD 10 # 0 THEN RETURN; IF count MOD 100 = 0 THEN { out.PutF1["(%g) ", [integer[count]] ]; } ELSE out.PutChar['.] }; NameInfoProc: PFS.InfoProc = { new: FileEntry; ropeName: ROPE; IF fileType = PFS.tDirectory THEN RETURN; ropeName ¬ PFSNames.ShortNameRope[fullFName]; CheckCount[]; IF switches['p] THEN { -- pcedar style df's hasDash: BOOL ¬ ( Rope.Find[ropeName, "-"] # -1 ); IF hasDash AND NOT Rope.Match["*-Suite.df", ropeName, FALSE] THEN RETURN; }; WITH RedBlackTree.Lookup[table, ropeName] SELECT FROM entry: FileEntry => { entry.status ¬ both; RETURN; }; ENDCASE; new ¬ NEW[FileEntryRep ¬ [ srcName: ropeName, status: dirOnly]]; RedBlackTree.Insert[table, new, ropeName]; }; count: INT ¬ 0; pos: INT ~ Rope.Find[dir, "*"]; out.PutF["\n\n***** Enumerating directory %g at %g\n", [rope[dir]], [time[BasicTime.Now[]]] ]; IF pos > 0 THEN PFS.EnumerateForInfo[PFS.PathFromRope[Rope.Concat[dir, bangH]], NameInfoProc] ELSE PFS.EnumerateForInfo[PFSNames.Cat[PFS.PathFromRope[dir], startBangHPath], NameInfoProc]; }; ShowTable: PROC [out: STREAM, table: RedBlackTree.Table] = { EachEntry: RedBlackTree.EachNode = { WITH data SELECT FROM entry: FileEntry => ShowEntry[out, entry]; ENDCASE => ERROR; }; RedBlackTree.EnumerateIncreasing[table, EachEntry]; }; ShowEntry: PROC [out: STREAM, entry: FileEntry] = { IO.PutF1[out, "[name: %g, state: ", [rope[entry.srcName]] ]; SELECT entry.status FROM dfOnly => out.PutRope["dfOnly]\n"]; dirOnly => out.PutRope["dirOnly]\n"]; both => out.PutRope["both]\n"]; ENDCASE; }; GetKey: RedBlackTree.GetKey = { RETURN [data]; }; Compare: RedBlackTree.Compare = { key: ROPE ¬ NIL; WITH k SELECT FROM ent: FileEntry => key ¬ ent.srcName; rope: ROPE => key ¬ rope; ENDCASE => ERROR; WITH data SELECT FROM ent: FileEntry => RETURN [Rope.Compare[key, ent.srcName, FALSE]]; ENDCASE; ERROR; }; CompareDFwithDir: Commander.CommandProc ~ { ProcessSwitches: PROC [arg: ROPE] ~ { sense: BOOL ¬ TRUE; FOR index: INT IN [0..Rope.Length[arg]) DO char: CHAR ¬ Rope.Fetch[arg, index]; SELECT char FROM '- => LOOP; '~ => {sense ¬ NOT sense; LOOP}; IN ['a..'z] => switches[char] ¬ sense; IN ['A..'Z] => switches[char + ('a-'A)] ¬ sense; ENDCASE; sense ¬ TRUE; ENDLOOP; }; out: STREAM ¬ cmd.out; dfName: ROPE; dirName: ROPE; switches: Switches ¬ ALL[FALSE]; DO arg: ROPE ¬ CommanderOps.NextArgument[cmd ! CommanderOps.Failed => { msg ¬ errorMsg; GO TO failed } ]; ch: CHAR; Process.CheckForAbort[]; IF arg = NIL THEN EXIT; ch ¬ Rope.Fetch[arg, 0]; SELECT TRUE FROM ( ch = '- ) AND ( arg.Length[] = 2 ) => ProcessSwitches[arg]; -- switch ( ch = '{ ) => LOOP; -- ignore ( ch = '} ) => LOOP; -- ignore ( ch = '$ ) => LOOP; -- ignore ENDCASE => IF dfName = NIL THEN dfName ¬ arg ELSE dirName ¬ arg; ENDLOOP; IF dfName = NIL THEN dfName ¬ "Cedar.df"; IF dirName = NIL THEN dirName ¬ "/Cedar/Top/"; DoIt[dfName, dirName, switches, out ! PFS.Error => { out.PutF["-- PFS.Error[%g] - quitting.\n\t\t(at %g)\n\n", [rope[error.explanation]], [time[BasicTime.Now[]]] ]; CONTINUE; }; ]; EXITS failed => {result ¬ $Failure}; }; docRope: ROPE ~ "CompareDFwithDir {dfName {-p} dirName }"; Commander.Register[ key: "CompareDFwithDir", proc: CompareDFwithDir, doc: docRope]; END.  CompareDFwithDirImpl.mesa Copyright Σ 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Willie-s, March 1, 1993 2:39 pm PST Types short name only indicates the status of the file Option variables Command Procedures [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE] called for each item in the table to do the comparing. explain the status of the file The mainline of DoIt Phase1, build up data base. Phase2, scan directory. Phase3, dump differences. [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE] [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key] [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison] When parsing the command line, be prepared for failure. The error is reported to the user Initialization Κ –(cedarcode) style•NewlineDelimiter ˜codešœ™Kšœ Οeœ=™HK™#K˜—šΟk ˜ Kšœžœ˜Kšœ žœžœ˜Kšœ žœ!˜0Kšœ žœ˜*Kšœ žœ1˜BKšžœ˜Kšžœ˜Kšœ ˜ Kšœžœ˜Kšœ žœQ˜cKšœ˜—K˜šΟnœžœž˜#Kšžœ2žœžœ'˜gK˜Kšœž˜—head™Kšžœžœžœ˜Kšžœžœžœžœ˜Kšžœžœžœžœ˜K˜Kšœ žœžœ˜#šœžœžœ˜šœ žœ˜Kšœ™—šœ˜K™ —K˜—Kšœžœ˜0Kš œ žœžœžœžœ˜2Kš œ žœžœžœžœ žœžœ˜3—šœ™Kšœžœ˜Kšœžœžœ˜/—™š Ÿœžœ žœžœžœ˜L•StartOfExpansion> -- [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE]šΟb œ˜$KšΠck:™:K™7šžœžœž˜˜šžœžœ˜K™šžœž˜˜ K˜4K˜K˜—˜ K˜:Kšžœžœžœ'žœ˜]K˜ K˜—Kšžœ˜—K˜—Kšœ2žœ˜7K˜Kšœ˜Kšžœ˜K˜—Kšžœžœ˜—K˜K˜—šŸ œžœžœ˜!Kšœžœ˜Kšœ žœ ˜.Kšœ˜šžœ&žœž˜5Kšœžœ˜Kšžœ˜—K˜šžœ&žœž˜5Kšœžœ˜Kšžœ˜—šœžœ˜Kšœ˜Kšœ˜—Kšœ*˜*K˜K˜—š Ÿ œžœ žœ žœžœ˜Aš žœžœ žœ!žœžœ˜^KšœUžœ˜rK˜—K˜šΠbnœ!˜)šžœžœž˜šœžœ˜&Kšœžœžœ˜+K˜ Kšœ˜K˜—Kšžœ žœ Οc'˜C—K˜K˜Kšœžœžœ˜Kšœžœ˜ šœžœ ˜šœ˜šœžœ žœžœ˜2KšœQžœ˜nKšœžœ˜ Kšœžœ˜Kšžœ˜ K˜——Kšžœž˜ K˜—šžœžœžœ˜Kšœa˜ašœ)£(˜QKšœžœ˜—Kšœ ˜ Kšœ˜—K˜—šŸ œžœ˜Kšžœžœžœžœ˜.šžœžœ žœ˜K˜&K˜Kšžœ˜—K˜K˜——K™K˜Kšœžœ˜Kšœžœ˜#K–@[getKey: RedBlackTree.GetKey, compare: RedBlackTree.Compare]˜RKšœžœžœ˜Kšœžœžœ˜K˜Kšœ™Kšœ žœ5˜EKšžœžœžœ˜K˜Kšœ™K˜,K™Kšœ™K˜FKšœ3˜3K™šžœž˜K˜U—šžœž˜K˜O—K˜8K˜K˜—šŸœžœžœ"žœ˜ašŸ œžœ˜Kšžœžœžœžœ˜.šžœžœ žœ˜K˜&K˜Kšžœ˜—K˜—šŸ œžœ ˜Kšœ˜Kšœ žœ˜Kšžœ žœ žœžœ˜)Kšœ-˜-K˜ šžœžœ£˜,Kšœ žœ%˜2Kš žœ žœžœ$žœžœžœ˜IK˜—šžœ&žœž˜5šœ˜Kšœ˜Kšžœ˜Kšœ˜—Kšžœ˜—šœžœ˜Kšœ˜Kšœ˜—Kšœ*˜*K˜—Kšœžœ˜Kšœžœ˜K˜^šžœ ž˜Kšžœžœ5˜Mšžœ˜Kšžœžœ3˜X——K˜K˜—šŸ œžœžœ ˜<–> -- [data: RedBlackTree.UserData] RETURNS [stop: BOOL _ FALSE]šœ$˜$Kš‘:™:šžœžœž˜Kšœ*˜*Kšžœžœ˜—K˜—Kšœ3˜3K˜K˜—šŸ œžœžœ˜3Kšžœ:˜<šžœž˜Kšœ#˜#Kšœ%˜%Kšœ˜Kšžœ˜—K˜K˜—–< -- [data: RedBlackTree.UserData] RETURNS [RedBlackTree.Key]šŸœ˜Kš‘8™8Kšžœ˜K˜K˜—–R -- [k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison]šŸœ˜!Kš‘N™NKšœžœžœ˜šžœžœž˜Kšœ$˜$Kšœžœ˜Kšžœžœ˜—šžœžœž˜Kšœžœ!žœ˜AKšžœ˜—Kšžœ˜K˜K˜—šŸœ˜+šŸœžœžœ˜%Kšœžœžœ˜šžœžœžœž˜*Kšœžœ˜$šžœž˜Kšœžœ˜ Kšœžœžœ˜ Kšžœ$˜&Kšžœ.˜0Kšžœ˜—Kšœžœ˜ Kšžœ˜—K˜—Kšœžœ ˜Kšœžœ˜ Kšœ žœ˜šœžœžœ˜ K˜—šž˜šœžœLžœžœ ˜fKšœZ™Z—Kšœžœ˜ K˜Kšžœžœžœžœ˜K˜šžœžœž˜Kšœ žœ/£ ˜GKšœžœ£ ˜Kšœžœ£ ˜Kšœžœ£ ˜Kš žœžœ žœžœžœ˜@Kšžœ˜K˜——Kšžœ žœžœ˜)Kšžœ žœžœ˜.˜#šœžœ ˜Kšœo˜oKšžœ˜ K˜—Kšœ˜—šž˜K˜—K˜K˜——–x[key: ROPE, proc: Commander.CommandProc, doc: ROPE _ NIL, clientData: REF ANY _ NIL, interpreted: BOOL _ TRUE]™K˜Kšœ žœU˜bšœS˜SK˜——K˜Kšžœ˜Kš£˜—…—²,=