DoIt:
PROC[dfNameRope:
ROPE, dir:
ROPE, switches: Switches, out:
STREAM] = {
EachEntry: RedBlackTree.EachNode = {
[data: RedBlackTree.UserData] RETURNS [stop: BOOL ← FALSE]
called for each item in the table to do the comparing.
WITH data
SELECT
FROM
entry: FileEntry => {
IF entry.status # both
THEN {
explain the status of the file
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['.]
};
The mainline of DoIt
count: INT ¬ 0;
dfOnlyCount, dirOnlyCount: INT ¬ 0;
table: RedBlackTree.Table ¬ RedBlackTree.Create[getKey: GetKey, compare: Compare];
inFileNotFound: BOOL ¬ FALSE;
prev: ROPE ¬ NIL;
Phase1, build up data base.
VisitClosure[PFS.PathFromRope[dfNameRope.Concat[bangH]], VisitEntry];
IF inFileNotFound THEN RETURN;
Phase2, scan directory.
ExamineDirectory[dir, table, out, switches];
Phase3, dump differences.
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 = {
[data: RedBlackTree.UserData] RETURNS [stop: BOOL ← FALSE]
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;
};
Compare: RedBlackTree.Compare = {
[k: RedBlackTree.Key, data: RedBlackTree.UserData] RETURNS [Basics.Comparison]
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 } ];
When parsing the command line, be prepared for failure. The error is reported to the user
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};
};