-- DFDiffImpl.Mesa, last edit February 9, 1983 12:34 pm -- Pilot 6.0/ Mesa 7.0 DIRECTORY CWF: TYPE USING [SetWriteProcedure, WF0, WF1, WF2, WFCR], DFSubr: TYPE USING [AllocateDFSeq, CompareDFs, DFSeq, FreeDFSeq, ParseStream, SortByFileName], IO: TYPE USING[Handle, PutChar, UserAbort], Rope: TYPE USING[ROPE, Text], RopeInline: TYPE USING[InlineFlatten], UnsafeSTP: TYPE USING [Error, Handle], STPSubr: TYPE USING [GeneralOpen], Stream: TYPE USING [Delete, Handle], String: TYPE USING [AppendString], Subr: TYPE USING [AbortMyself, Any, errorflg, FileError, MakeTTYProcs, PrintGreeting, strcpy, SubrInit, SubrStop, TTYProcs], Time: TYPE USING [Current], UECP: TYPE USING[Argv, Parse], UserExec: TYPE USING[AcquireResource, AskUser, CommandProc, ExecHandle, GetStreams, RegisterCommand, ReleaseResource]; DFDiffImpl: PROGRAM IMPORTS CWF, DFSubr, IO, RopeInline, STP: UnsafeSTP, STPSubr, Stream, String, Subr, Time, UECP, UserExec = { -- MDS usage!! stdout: IO.Handle; -- end of mds MAXFILES: CARDINAL = 900; Main: UserExec.CommandProc = TRUSTED { ENABLE UNWIND => [] ← UserExec.ReleaseResource[$DFDiff]; h: Subr.TTYProcs; in, out: IO.Handle; [in, out] ← UserExec.GetStreams[exec]; [] ← UserExec.AcquireResource[$DFDiff, "DFDiff", exec]; h ← Subr.MakeTTYProcs[in, out, exec, MyConfirm]; DFDiffUsingProcs[h, event.commandLine]; [] ← UserExec.ReleaseResource[$DFDiff]; }; DFDiffUsingProcs: PROC[h: Subr.TTYProcs, commandLine: Rope.ROPE] = { sold: STRING ← [100]; snew: STRING ← [100]; shold, shnew: Stream.Handle; dfseqold, dfseqnew: DFSubr.DFSeq ← NIL; starttime: LONG CARDINAL; argv: UECP.Argv ← UECP.Parse[commandLine]; flat: Rope.Text; Cleanup: PROC = { DFSubr.FreeDFSeq[@dfseqold]; DFSubr.FreeDFSeq[@dfseqnew]; Subr.SubrStop[]; }; { ENABLE { UNWIND => Cleanup[]; Subr.AbortMyself => { CWF.WF0["\nDFDiff Aborted.\n"L]; GOTO leave; }; STP.Error => { CWF.WF0["FTP Error. "L]; IF error ~= NIL THEN CWF.WF1["message: %s\n"L,error]; Subr.errorflg ← TRUE; GOTO leave; }; }; stdout ← h.out; [] ← CWF.SetWriteProcedure[MyPutChar]; starttime ← Time.Current[]; Subr.SubrInit[256]; Subr.PrintGreeting["DFDiff"L]; dfseqold ← DFSubr.AllocateDFSeq[maxEntries: MAXFILES, zoneType: shared]; dfseqnew ← DFSubr.AllocateDFSeq[maxEntries: MAXFILES, zoneType: shared]; IF argv.argc < 3 THEN GOTO usage; flat ← RopeInline.InlineFlatten[argv[2]]; Subr.strcpy[sold, LOOPHOLE[flat]]; flat ← RopeInline.InlineFlatten[argv[3]]; Subr.strcpy[snew, LOOPHOLE[flat]]; IF NOT Subr.Any[sold, '.] THEN String.AppendString[sold, ".df"L]; IF NOT Subr.Any[snew, '.] THEN String.AppendString[snew, ".df"L]; CWF.WF1["Opening %s"L, sold]; [shold] ← STPSubr.GeneralOpen[sold, h ! Subr.FileError => GOTO err1]; CWF.WF1["Opening %s"L, snew]; [shnew] ← STPSubr.GeneralOpen[snew, h ! Subr.FileError => GOTO err2]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; DFSubr.ParseStream[shold, dfseqold, sold, NIL, TRUE, FALSE, FALSE, h]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; DFSubr.ParseStream[shnew, dfseqnew, snew, NIL, TRUE, FALSE, FALSE, h]; Stream.Delete[shold]; Stream.Delete[shnew]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; DFSubr.SortByFileName[dfseqold, 0, dfseqold.size-1, TRUE]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; DFSubr.SortByFileName[dfseqnew, 0, dfseqnew.size-1, TRUE]; CWF.WF2["Old file: %s, new file: %s\n"L, sold, snew]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; CompareDFSeqs[dfseqold, dfseqnew]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; DFSubr.FreeDFSeq[@dfseqold]; DFSubr.FreeDFSeq[@dfseqnew]; EXITS err1 => CWF.WF1["Error - can't open %s.\n"L, sold]; err2 => CWF.WF1["Error - can't open %s.\n"L, snew]; usage => CWF.WF0["Error - usage: DFDiff old-df-file new-df-file\n"L]; leave => NULL; }; starttime ← Time.Current[] - starttime; CWF.WF1["\nTotal elapsed time for DFDiff %lr."L,@starttime]; IF Subr.errorflg THEN CWF.WF0["\tErrors logged.\n"L]; CWF.WFCR[]; Cleanup[]; }; Choice: TYPE = {added, deleted, different}; CompareDFSeqs: PROC[dfseqold, dfseqnew: DFSubr.DFSeq] = { res: INTEGER; iold, inew: CARDINAL; FOR choice: Choice IN Choice DO SELECT choice FROM added => CWF.WF0["\nAdded:\n"L]; deleted => CWF.WF0["\nDeleted:\n"L]; different => CWF.WF0["\nDifferent:\n"L]; ENDCASE => ERROR; iold ← inew ← 0; WHILE iold < dfseqold.size OR inew < dfseqnew.size DO IF iold >= dfseqold.size THEN res ← 1 ELSE IF inew >= dfseqnew.size THEN res ← -1 ELSE res ← DFSubr.CompareDFs[@dfseqold[iold], @dfseqnew[inew], TRUE]; IF res < 0 THEN { IF choice=deleted THEN { CWF.WF1[" %-40s"L, dfseqold[iold].shortname]; IF dfseqold[iold].createtime ~= 0 THEN CWF.WF1[" %lt"L, @dfseqold[iold].createtime]; CWF.WFCR[]; }; iold ← iold + 1; } ELSE IF res > 0 THEN { IF choice = added THEN { CWF.WF1[" %-40s"L, dfseqnew[inew].shortname]; IF dfseqnew[inew].createtime ~= 0 THEN CWF.WF1[" %lt"L, @dfseqnew[inew].createtime]; CWF.WFCR[]; }; inew ← inew + 1; } ELSE {-- they are equivalent names IF dfseqold[iold].createtime ~= dfseqnew[inew].createtime AND choice = different THEN { CWF.WF1[" %-34s"L, dfseqnew[inew].shortname]; IF dfseqnew[inew].createtime ~= 0 THEN CWF.WF1[" new = %lt"L, @dfseqnew[inew].createtime]; CWF.WFCR[]; }; inew ← inew + 1; iold ← iold + 1; }; ENDLOOP; ENDLOOP; }; MyConfirm: PROC[in, out: IO.Handle, data: REF ANY, msg: Rope.ROPE, dch: CHAR] RETURNS[CHAR] = { value: ATOM; value ← UserExec.AskUser[msg: msg, exec: NARROW[data], keyList: LIST[$Yes, $No]]; -- order is important SELECT value FROM $No => RETURN['n]; $Yes => RETURN['y]; ENDCASE => ERROR; }; MyPutChar: PROC[ch: CHAR] = { stdout.PutChar[ch]; }; -- start code UserExec.RegisterCommand["DFDiff.~", Main]; }.