-- DFDeleteImpl.Mesa, last edit February 9, 1983 11:57 am -- Pilot 6.0/ Mesa 7.0 DIRECTORY CWF: TYPE USING [FWF0, FWF1, SetWriteProcedure, WF0, WF1, WFCR], DFSubr: TYPE USING [AllocateDFSeq, DF, DFSeq, FlattenDF, FreeDFSeq, ReadInDir, SortByCap, SortByFileName], LongString: TYPE USING [AppendString], IO: TYPE USING[Handle, PutChar, PutF, rope, UserAbort], Rope: TYPE USING[Fetch, Length, ROPE, Text], RopeInline: TYPE USING[InlineFlatten], STPSubr: TYPE USING [StopSTP], Stream: TYPE USING [Delete, Handle, PutChar], Subr: TYPE USING [AbortMyself, Any, CheckForModify, debugflg, errorflg, GetCreateDate, MakeTTYProcs, NewStream, PackedTime, PrintGreeting, strcpy, SubrStop, TTYProcs, Write], Time: TYPE USING [Current], UECP: TYPE USING[Argv, Parse], UserExec: TYPE USING[AcquireResource, AskUser, CommandProc, GetStreams, RegisterCommand, ReleaseResource]; DFDeleteImpl: PROGRAM IMPORTS CWF, DFSubr, IO, LongString, Rope, RopeInline, STPSubr, Stream, Subr, Time, UECP, UserExec = { -- MDS usage!! stdout: IO.Handle; -- end of mds -- max number of files in all DF file we want to ignore MAXDELETEFILE: CARDINAL = 800; Main: UserExec.CommandProc = TRUSTED { ENABLE UNWIND => [] ← UserExec.ReleaseResource[$DFDelete]; h: Subr.TTYProcs; in, out: IO.Handle; [in, out] ← UserExec.GetStreams[exec]; [] ← UserExec.AcquireResource[$DFDelete, "DFDelete", exec]; h ← Subr.MakeTTYProcs[in, out, exec, MyConfirm]; DFDeleteUsingProcs[h, event.commandLine]; [] ← UserExec.ReleaseResource[$DFDelete]; }; -- this is the procedure called by the Simple Executive DFDeleteUsingProcs: PROC[h: Subr.TTYProcs, commandLine: Rope.ROPE] = { dfseq: DFSubr.DFSeq ← NIL; tok: Rope.ROPE; starttime: Subr.PackedTime; alsoDeleteReadOnly: BOOL ← FALSE; argv: UECP.Argv ← UECP.Parse[commandLine]; Cleanup: PROC = { DFSubr.FreeDFSeq[@dfseq]; STPSubr.StopSTP[]; Subr.SubrStop[]; }; stdout ← h.out; [] ← CWF.SetWriteProcedure[MyPutChar]; starttime ← Time.Current[]; Subr.errorflg ← Subr.debugflg ← FALSE; Subr.PrintGreeting["DFDelete"L]; dfseq ← DFSubr.AllocateDFSeq[maxEntries: MAXDELETEFILE, zoneType: shared]; { ENABLE { Subr.AbortMyself => { CWF.WF0["DFDelete Aborted.\n"L]; GOTO leave; }; UNWIND => Cleanup[]; }; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; FOR p: CARDINAL IN [1 .. argv.argc) DO tok ← argv[p]; IF tok.Fetch[0] = '/ THEN { IF tok.Fetch[1] = 'r THEN alsoDeleteReadOnly ← TRUE ELSE h.out.PutF["Unknown switch '%s'.\n", IO.rope[tok]]; } ELSE { str: STRING ← [100]; flat: Rope.Text ← RopeInline.InlineFlatten[tok]; Subr.strcpy[str, LOOPHOLE[flat]]; IF NOT Subr.Any[str, '.] THEN LongString.AppendString[str, ".DF"L]; DFSubr.FlattenDF[dfseq: dfseq, dffilename: str, h: h]; }; ENDLOOP; IF tok.Length[] = 0 THEN GOTO usage; STPSubr.StopSTP[]; IF dfseq.size = 0 THEN GOTO leave; DFSubr.ReadInDir[dfseq]; DFSubr.SortByCap[dfseq, 0, dfseq.size-1]; FOR i: CARDINAL IN [0 .. dfseq.size) DO dfseq[i].need ← NOT dfseq[i].readonly OR alsoDeleteReadOnly; ENDLOOP; -- only ReadWrite files are marked need = TRUE CWF.WF0["Reading create dates on local disk ... "L]; CheckCreateDates[dfseq]; CWF.WF0["Done.\n"L]; DFSubr.SortByFileName[dfseq, 0, dfseq.size-1, TRUE]; GenerateDelete[dfseq, alsoDeleteReadOnly, h]; EXITS usage => CWF.WF0["Usage: DFDelete dffile(s).\n"L]; leave => NULL; }; starttime ← Time.Current[] - starttime; CWF.WF1["\nTotal elapsed time for DFDelete %lr."L,@starttime]; IF Subr.errorflg THEN CWF.WF0["\tErrors logged.\n"L]; CWF.WFCR[]; Cleanup[]; }; CheckCreateDates: PROC[dfseq: DFSubr.DFSeq] = { df: DFSubr.DF; FOR i: CARDINAL IN [0 .. dfseq.size) DO df ← @dfseq[i]; IF df.need AND df.presentonlocaldisk AND df.createtime ~= 0 THEN { IF Subr.GetCreateDate[df.cap] ~= df.createtime THEN df.need ← FALSE; }; ENDLOOP; }; GenerateDelete: PROC[dfseq: DFSubr.DFSeq, alsoDeleteReadOnly: BOOL, h: Subr.TTYProcs] = { linesh: Stream.Handle ← NIL; df: DFSubr.DF; WP: PROC[ch: CHAR] = { h.out.PutChar[ch]; Stream.PutChar[linesh, ch]; }; FOR i: CARDINAL IN [0 .. dfseq.size) DO df ← @dfseq[i]; IF df.need AND df.presentonlocaldisk AND df.createtime ~= 0 THEN { IF linesh = NIL THEN { CWF.WF1["(You should delete these files since %s\n"L, IF alsoDeleteReadOnly THEN ""L ELSE "they appeared non-ReadOnly and "L]; CWF.WF0["their createdates are equal to those in the DF file(s).)\n"L]; IF NOT Subr.CheckForModify["Line.CM"L, h] THEN SIGNAL Subr.AbortMyself; CWF.WF0["Execute: "L]; linesh ← Subr.NewStream["Line.CM"L, Subr.Write]; CWF.FWF0[WP, "Delete "L]; }; CWF.FWF1[WP, "%s "L, dfseq[i].shortname]; }; ENDLOOP; IF linesh ~= NIL THEN { Stream.Delete[linesh]; CWF.WF0["\n\n(Delete command also written on 'Line.CM'.)\n"L]; }; }; 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, $All, $Local, $Quit]]; -- order is important SELECT value FROM $All => RETURN['a]; $Local => RETURN['l]; $No => RETURN['n]; $Quit => RETURN['q]; $Yes => RETURN['y]; ENDCASE => ERROR; }; MyPutChar: PROC[ch: CHAR] = { stdout.PutChar[ch]; }; UserExec.RegisterCommand["DFDelete.~", Main]; }.