-- DeleteAllImpl.Mesa, last edit February 6, 1983 9:17 pm -- Pilot 6.0/ Mesa 7.0 -- Switch Meaning -- /a do NOT confirm the deletes (and CheckForOverwrite is FALSE) -- /n do NOT use BasicCoPilotVolumeFiles.DF (or BasicClientVolumeFiles.DF) DIRECTORY CWF: TYPE USING [SetWriteProcedure, SWF1, WF0, WF1, WF3, WFCR], DFSubr: TYPE USING [AllocateDFSeq, DF, DFSeq, FlattenDF, FreeDFSeq, LookupDF, NextDF, SortByFileName], Directory: TYPE USING [DeleteFile], File: TYPE USING [Capability, Unknown], IO: TYPE USING[Handle, PutChar, PutFR, PutRope, string, UserAbort], LongString: TYPE USING [EquivalentString], Rope: TYPE USING[ROPE, Text], RopeInline: TYPE USING[InlineFlatten], UnsafeSTP: TYPE USING [Error, Handle], STPSubr: TYPE USING [GeneralOpen, StopSTP], Stream: TYPE USING [Delete, EndOfStream, Handle], Subr: TYPE USING [AbortMyself, CheckForModify, CopyString, debugflg, EndsIn, EnumerateDirectory, errorflg, FileError, GetID, MakeTTYProcs, PackedTime, PrintGreeting, strcpy, SubrStop, SubStrCopy, TTYProcs], Time: TYPE USING [Current], UECP: TYPE USING[Argv, Parse], UserExec: TYPE USING[AcquireResource, AskUser, CommandProc, ExecHandle, GetStreams, RegisterCommand, ReleaseResource], Volume: TYPE USING [GetType, systemID, Type]; DeleteAllImpl: PROGRAM IMPORTS CWF, DFSubr, Directory, File, IO, LongString, Rope, RopeInline, STP: UnsafeSTP, STPSubr, Stream, Subr, Time, UECP, UserExec, Volume = { -- MDS USAGE !!! useremotedeletelist: BOOL; dontconfirm: BOOL; argv: UECP.Argv; parm: CARDINAL _ 1; stdout: IO.Handle; -- endof MDS usage -- max number of files on local disk maxdirsize: CARDINAL = 1100; -- total # entries from Basic...VolumeFiles.DF MAXSTANDARDDELETEFILE: CARDINAL = 1200; -- max number of files in each DF file we want to ignore (listed on command file) MAXDELETEFILE: CARDINAL = 1200; Main: UserExec.CommandProc = TRUSTED { ENABLE UNWIND => [] _ UserExec.ReleaseResource[$DeleteAll]; h: Subr.TTYProcs; in, out: IO.Handle; [in, out] _ UserExec.GetStreams[exec]; [] _ UserExec.AcquireResource[$DeleteAll, "DeleteAll", exec]; h _ Subr.MakeTTYProcs[in, out, exec, MyConfirm]; DeleteAllUsingProcs[h, event.commandLine]; [] _ UserExec.ReleaseResource[$DeleteAll]; }; DeleteAllUsingProcs: PROC[h: Subr.TTYProcs, commandLine: Rope.ROPE] = { dfseq: DFSubr.DFSeq; tok: STRING _ [100]; starttime: Subr.PackedTime; elapt: LONG CARDINAL; Cleanup: PROC = { DFSubr.FreeDFSeq[@dfseq]; }; useremotedeletelist _ TRUE; stdout _ h.out; [] _ CWF.SetWriteProcedure[MyPutChar]; dontconfirm _ FALSE; starttime _ Time.Current[]; Subr.errorflg _ Subr.debugflg _ FALSE; Subr.PrintGreeting["DeleteAll"L]; dfseq _ DFSubr.AllocateDFSeq[maxEntries: maxdirsize, zoneType: shared]; { ENABLE { STP.Error => { CWF.WF0["FTP Error. "L]; IF error ~= NIL THEN CWF.WF1["message: %s\n"L, error]; Subr.errorflg _ TRUE; GOTO leave; }; Subr.AbortMyself => { CWF.WF0["DeleteAll Aborted.\n"L]; GOTO leave; }; UNWIND => Cleanup[]; }; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; argv _ UECP.Parse[commandLine]; DeleteAll[dfseq, h]; EXITS leave => NULL; }; STPSubr.StopSTP[]; elapt _ starttime; elapt _ Time.Current[] - elapt; CWF.WF1["\nTotal elapsed time for DeleteAll %lr."L,@elapt]; IF Subr.errorflg THEN CWF.WF0["\tErrors logged.\n"L]; CWF.WFCR[]; Cleanup[]; Subr.SubrStop[]; }; DeleteAll: PROC[dfseq: DFSubr.DFSeq, h: Subr.TTYProcs] = { i, ndel: CARDINAL; header: BOOL _ FALSE; short: STRING _ [100]; -- if look.presentonlocaldisk is true, don't delete it FillInDFSeq[dfseq]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; FOR i IN [0.. dfseq.size) DO dfseq[i].presentonlocaldisk _ FALSE;-- assume we will delete file ENDLOOP; DFSubr.SortByFileName[dfseq, 0, dfseq.size - 1]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; MatchAgainstFile[dfseq, h]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; IF useremotedeletelist THEN HandleRemoteDeleteList[dfseq, h]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; -- determine which are to be deleted FOR i IN [0..dfseq.size) DO -- check against built in list just in case IF NOT dfseq[i].presentonlocaldisk THEN dfseq[i].presentonlocaldisk _ MatchesDontDeleteList[dfseq[i].shortname]; ENDLOOP; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; -- print out list of those to be left on disk CWF.WF0["These files will be left on the disk:\n"L]; FOR i IN [0..dfseq.size) DO IF dfseq[i].presentonlocaldisk THEN CWF.WF1["%s "L, dfseq[i].shortname]; ENDLOOP; -- print out list of those to be deleted CWF.WF0["\n\nThese files will be deleted:\n\n"L]; FOR i IN [0..dfseq.size) DO IF NOT dfseq[i].presentonlocaldisk THEN { IF NOT header THEN { CWF.WF0["Delete.~"L]; header _ TRUE; }; -- these will be deleted CWF.WF1[" %s"L, dfseq[i].shortname]; }; ENDLOOP; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; IF NOT dontconfirm THEN CWF.WF0["\n\nType 'y' or CR to delete, 'n' to skip, and 'q' to quit.\n"L]; ndel _ 0; FOR i IN [0..dfseq.size) DO IF NOT dfseq[i].presentonlocaldisk THEN { r: Rope.ROPE; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; r _ IO.PutFR["Delete %s ", IO.string[dfseq[i].shortname]]; IF NOT dontconfirm THEN { ch: CHAR; ch _ h.Confirm[h.in, h.out, h.data, r, 'y]; IF ch = 'q THEN { EXIT; }; IF ch ~= 'y THEN { LOOP; }; } ELSE h.out.PutRope[r]; CWF.WF0["Yes ... "L]; -- deletes the file Subr.strcpy[short, dfseq[i].shortname]; IF NOT Subr.CheckForModify[short, h] THEN { CWF.WF0[" ... can't be modified.\n"L]; LOOP; }; Directory.DeleteFile[dfseq[i].shortname ! File.Unknown => { -- bugs in directory package CWF.WF0["File/Directory Error.\n"L]; CONTINUE; } ]; CWF.WF0["Done.\n"L]; ndel _ ndel + 1; }; ENDLOOP; CWF.WF1["%u files deleted.\n"L, @ndel]; }; -- returns TRUE if the file should not be deleted -- these files are NOT deleted by DeleteAll MatchesDontDeleteList: PROC[p: LONG STRING] RETURNS[bool: BOOL] = { OPEN LongString; bool _ FALSE; IF EquivalentString[p, "Binder.Log"L] OR EquivalentString[p, "Compiler.Log"L] OR EquivalentString[p, "Debug.Log"L] OR EquivalentString[p, "Debuggee.outload"L] OR EquivalentString[p, "Debugger.outload"L] OR EquivalentString[p, "DeleteAll.Bcd"L] OR EquivalentString[p, "Executive.Bcd"L] OR EquivalentString[p, "Executive.DontDeleteMe"L] OR EquivalentString[p, "FileTool.logD"L] OR EquivalentString[p, "SimpleExec"L] OR EquivalentString[p, "SimpleExec.Log"L] OR EquivalentString[p, "user.cm"L] THEN bool _ TRUE; }; HandleRemoteDeleteList: PROC[dfdirseq: DFSubr.DFSeq, h: Subr.TTYProcs] ={ sfn: STRING _ [100]; type: Volume.Type; dfseq: DFSubr.DFSeq _ NIL; { ENABLE UNWIND => DFSubr.FreeDFSeq[@dfseq]; dfseq _ DFSubr.AllocateDFSeq[maxEntries: MAXSTANDARDDELETEFILE, zoneType: shared]; type _ Volume.GetType[Volume.systemID]; CWF.SWF1[sfn, "[Indigo]DFFiles>Basic%sVolumeFiles.DF"L, IF type = normal THEN "Client"L ELSE "CoPilot"L]; CWF.WF1["Using delete list from '%s'\n"L, sfn]; DFSubr.FlattenDF[dfseq: dfseq, dffilename: sfn, checkForOverwrite: NOT dontconfirm, h: h]; DontDeleteTheseDFFiles[dfdirseq, dfseq, h]; DFSubr.FreeDFSeq[@dfseq]; CWF.WFCR[]; }}; MatchAgainstFile: PROC[dfdirseq: DFSubr.DFSeq, h: Subr.TTYProcs] = { tok: STRING _ [100]; flat: Rope.Text; WHILE parm < argv.argc DO flat _ RopeInline.InlineFlatten[argv[parm]]; Subr.strcpy[tok, LOOPHOLE[flat]]; IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; IF tok[0] = '@ THEN { -- is an escaped at-sign sh: Stream.Handle; Subr.SubStrCopy[tok, tok, 1]; [sh] _ STPSubr.GeneralOpen[filename: tok, h: h ! Subr.FileError => { CWF.WF1["Error - Can't open '%s'\n"L, tok]; GOTO out } ]; IF Subr.EndsIn[tok, ".df"L] THEN { dfseq: DFSubr.DFSeq _ NIL; { ENABLE UNWIND => DFSubr.FreeDFSeq[@dfseq]; dfseq _ DFSubr.AllocateDFSeq[maxEntries: MAXDELETEFILE, zoneType: shared]; DFSubr.FlattenDF[dfseq: dfseq, dffilename: tok, checkForOverwrite: NOT dontconfirm, h: h]; DontDeleteTheseDFFiles[dfdirseq, dfseq, h]; DFSubr.FreeDFSeq[@dfseq]; }} ELSE DontDeleteTheseFiles[sh, dfdirseq]; Stream.Delete[sh]; EXITS out => NULL; } ELSE IF tok[0] = '- OR tok[0] = '/ THEN { -- is an option SELECT tok[1] FROM 'a, 'A => dontconfirm _ TRUE; 'n, 'N => useremotedeletelist _ FALSE; ENDCASE =>CWF.WF1["Error - malformed argument '%s'.\n"L, tok]; } ELSE { df: DFSubr.DF; df _ DFSubr.LookupDF[dfdirseq, tok]; IF df = NIL THEN CWF.WF1["File %s is not on local disk.\n"L, tok] ELSE -- dont delete it df.presentonlocaldisk _ TRUE; }; ENDLOOP; }; DontDeleteTheseFiles: PROC[sh: Stream.Handle, dfseq: DFSubr.DFSeq] = { df: DFSubr.DF; str: STRING _ [100]; DO str.length _ 0; Subr.GetID[sh, str ! Stream.EndOfStream => { str.length _ 0; EXIT; } ]; IF str.length = 0 THEN LOOP; df _ DFSubr.LookupDF[dfseq, str]; IF df = NIL THEN CWF.WF1["File %s is not on local disk.\n"L, str] ELSE -- dont delete it df.presentonlocaldisk _ TRUE; ENDLOOP; }; -- dfdirseq is for the local directory -- dfseq is the exception list -- dfseq must already be filled DontDeleteTheseDFFiles: PROC[dfdirseq, dfseq: DFSubr.DFSeq, h: Subr.TTYProcs] = { df, dfdir: DFSubr.DF; host: LONG STRING; FOR i: CARDINAL IN [0.. dfseq.size) DO IF h.in.UserAbort[] THEN SIGNAL Subr.AbortMyself; df _ @dfseq[i]; IF df.host ~= NIL THEN host _ df.host; dfdir _ DFSubr.LookupDF[dfdirseq, df.shortname]; IF dfdir = NIL THEN { IF df.directory ~= NIL THEN CWF.WF3["File [%s]<%s>%s not on local disk.\n"L, host, df.directory, df.shortname] ELSE CWF.WF1["File %s not on local disk.\n"L, df.shortname]; } ELSE -- dont delete it dfdir.presentonlocaldisk _ TRUE; ENDLOOP; }; FillInDFSeq: PROC[dfseq: DFSubr.DFSeq] = { AddDir: PROC[cap: File.Capability, name: LONG STRING] RETURNS[BOOL]={ df: DFSubr.DF; df _ DFSubr.NextDF[dfseq]; IF df = NIL THEN { CWF.WF0["Too many files on local disk.\n"L]; RETURN[TRUE]; }; df.shortname _ Subr.CopyString[name, dfseq.dfzone]; df.presentonlocaldisk _ TRUE; df.cap _ cap; RETURN[FALSE]; }; Subr.EnumerateDirectory[AddDir]; CWF.WF1["%u files on the local disk.\n"L, @dfseq.size]; }; 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["DeleteAll.~", Main]; }.