home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 595.lha / TrashCompactor_v1.11 / tc.p < prev    next >
Text File  |  1991-12-07  |  16KB  |  434 lines

  1. PROGRAM GarbageCompactor;
  2.  
  3. {$I "Include:Utils/Break.i"}
  4. {$I "Include:Libraries/DOS.i"}
  5. {$I "Include:Utils/DateTools.i"}
  6. {$I "Include:Utils/StringLib.i"}
  7. {$I "Include:Utils/Parameters.i"}
  8.  
  9. {
  10.    Trash Compactor        version 1.11   December 7, 1991
  11.                           version 1.1    December 7, 1991
  12.                           version 1.0    November 26, 1991
  13.  
  14.    Stephan Zuercher    internet:  szuerche@jarthur.claremont.edu
  15.                        GEnie:     S.ZUERCHER
  16.  
  17.    A program that will check the trashcan for file that have been in the
  18.    trashcan for more than a specified number of days, deleting any files
  19.    that meet the requirement of having been there long enough.
  20.  
  21.    This program was inspired by a program on Norton Desktop (an add-on to
  22.    Microsoft's Windows for the IBM PC) that does pretty much the same thing
  23.    as this program.  
  24.  
  25.    Forgive me for not having written it in C.  I need the practice in Pascal
  26.    and PCQ also happens to be the only compiled programming language available
  27.    to me right now.
  28.  
  29.    Command line parameters:
  30.  
  31.      TrashCompactor [-#] [path1] [path2] ... [path10] [quiet]
  32.    
  33.    Where # is the number of days old a file must be before it gets sent to
  34.    Never-Never Land and path1, path2, ... path10 are up to ten different paths
  35.    to the various trashcans that may or may NOT be floating around your
  36.    system.  If the quiet switch is given, the program will NOT tell you that
  37.    it is deleting files.  If no parameters are given on the command line, the
  38.    program will default to 5 days old, SYS:Trashcan, and will tell you that it
  39.    is in fact deleting files.
  40.  
  41.    There is a maximum number of days old for -# parameter.  It is 28 days.
  42.    There is also a minimum number of days.  That's one day.  8)
  43.  
  44.    Version 1.11 We couldn't delete subdirectories of the trashcan.  It checked
  45.                 the date on the subdir before deletion, however, if _any_ 
  46.                 files had been deleted from the subdir, its date would be
  47.                 the current date and the subdir itself wouldn't get deleted.
  48.                 Solution:  Try to delete all subdirs.  If they're empty, then
  49.                            they disappear, otherwise they stay.  Not pretty,
  50.                            but it works.
  51.    Version 1.1  If there was more than one subdirectory in the Trashcan it
  52.                 would only find the first.  Argh.  I knew I  shouldn't have
  53.                 used the code from Find.p.  Well its rewritten now.  It should
  54.                 work.
  55.  
  56.    Version 1.0  Well, it runs.  Doesn't give back 200 bytes of memory, but I
  57.                 know where that is.
  58. }
  59.  
  60. TYPE
  61.   CLarray1 = ARRAY [1..12] OF String;
  62.   CLarray2 = ARRAY [1..10] OF String;
  63.  
  64. VAR
  65.   CLstrings   : CLarray2;
  66.   BeQuiet     : BOOLEAN;
  67.   MaxDaysOld,
  68.   DelYear,
  69.   count,
  70.   numdel,
  71.   totdel      : Short;
  72.   DelMonth,DelDay : BYTE;
  73.  
  74.  
  75. FUNCTION StringToInteger(t : String) : Integer;
  76.   
  77.   {  This function takes an integer value from a string and converts it into
  78.      a pascal integer.  Please NOT that it has been modified for TrashCompactor
  79.      by stopping before the negative sign that is prepended to each string
  80.      passed.  That means if you steal this routine for your own program you'll
  81.      have to modify it for negative numbers, or if you'll only be needing 
  82.      positive conversions, change the DOWNTO 1 in the FOR loop to DOWNTO 0.
  83.   }
  84.  
  85.   VAR
  86.     tot,x,count,place,factor,length : Integer;
  87.    
  88.   BEGIN { StringToInteger }
  89.     x := 0;   { Initialize variables }
  90.     tot := 0;
  91.     factor := 1;
  92.     length := strlen(t);
  93.     FOR count := length-1 DOWNTO 1 DO { Loop for last digit in number to first }
  94.       BEGIN
  95.         x := (ORD(t[count])-48) * factor;
  96.                                { Determine value of a digit }
  97.                                { Multiply x by the factor for the place value }
  98.         tot := tot + x;        { Add x to the current tot }
  99.         factor := factor * 10; { Multiply factor by 10, to get the value for
  100.                                  the next multiplication factor }
  101.       END;
  102.     StringToInteger := tot;
  103.   END; { StringToInteger }
  104.  
  105.  
  106. PROCEDURE GetCL(VAR CLstr : CLarray2;
  107.                 VAR DaysBack : Short; 
  108.                 VAR ShutUp : BOOLEAN);
  109.  
  110.   { This procedure gets the command line parameters, and returns an array
  111.     containing up to ten paths minus the other parameters.  The proceudre
  112.     also returns how many days old a file can be before it gets deleted and
  113.     whether output should be suppressed. }
  114.  
  115.   VAR
  116.     allCLstr    : CLarray1;
  117.     numparams,
  118.     count,
  119.     returncount : Short;
  120.     temp        : String;
  121.  
  122.   BEGIN
  123.     DaysBack := 5;
  124.     ShutUp := False;
  125.     FOR count := 1 TO 12 DO
  126.       allCLstr[count] := AllocString(128);
  127.     count := 0;
  128.     returncount := 0;
  129.     temp := AllocString(128);
  130.     REPEAT
  131.       BEGIN
  132.         count := count + 1;
  133.         GetParam(count,allCLstr[count]);
  134.       END
  135.     UNTIL (strlen(allCLstr[count]) < 1) OR (count = 12);
  136.     IF strlen(allCLstr[count]) < 1 THEN
  137.       numparams := count - 1
  138.     ELSE
  139.       numparams := count;
  140.     FOR count := 1 TO numparams DO
  141.       IF strnieq(allCLstr[count],"-",1) THEN
  142.         BEGIN
  143.           strcpy(temp,allCLstr[count]);
  144.           IF (temp[1] = 'h') OR (temp[1] = 'H') OR (temp[1] = '?') THEN
  145.             DaysBack := -42
  146.           ELSE
  147.             BEGIN
  148.               DaysBack := StringToInteger(temp);
  149.               IF DaysBack > 28 THEN DaysBack := 28;
  150.             END
  151.         END
  152.       ELSE
  153.         IF strnieq(allCLstr[count],"QUIET",5) THEN
  154.           ShutUp := True
  155.         ELSE
  156.           BEGIN
  157.             returncount := returncount + 1;
  158.             CLstr[returncount] := allCLstr[count];
  159.           END;
  160.     IF returncount = 0 THEN
  161.       CLstr[1] := strdup("SYS:Trashcan")
  162.     ELSE
  163.       IF returncount < 10 THEN
  164.         FOR returncount := returncount + 1 TO 10 DO
  165.           CLstr[returncount] := AllocString(1);
  166.   END; { Get CL }
  167.  
  168.  
  169.  
  170. PROCEDURE GetDeleteDate(    DaysBack        : SHORT;
  171.                         VAR DelMonth,DelDay : BYTE;
  172.                         VAR DelYear         : SHORT);
  173.  
  174.   VAR
  175.      SysDate,
  176.      DelDate         : DateDescription;
  177.                         
  178.   BEGIN
  179.     TimeDesc(SysDate);                  { Get System Date.  If this isn't set  }
  180.     WITH SysDate DO                     { before execution, thou art reamed... }
  181.       BEGIN
  182.         IF (Year/4) = (Year DIV 4) THEN { Is this a leap year?  If so... make  }
  183.           DaysInMonth[1] := 29;         { # of days in Feb = 29 instead of 28  }
  184.         IF Day > DaysBack THEN                   
  185.           BEGIN
  186.             DelDay := Day - DaysBack;   { If we are >DaysBack into the month,  }
  187.             DelMonth := Month;          { just back up the date x days to find }
  188.             DelYear := Year;            { what date to delete file before      }
  189.           END { Block }
  190.         ELSE
  191.           IF Month > 1 THEN             { Otherwise if this isn't Jan, we back }
  192.             BEGIN                       { into the previous month, keeping the }
  193.               DelDay := (Day-DaysBack) + DaysInMonth[Month-2];
  194.               DelMonth := Month - 1;    { year.  Note DaysInMonth is zero based}
  195.               DelYear := Year;          { but Month isn't.  Go figure...       }
  196.             END { Block }
  197.           ELSE
  198.             BEGIN                       { Otherwise we get to back up into the }
  199.               DelDay := (Day-DaysBack) + DaysInMonth[11];
  200.               DelMonth := 12;           { previous year!  Month *has* to be Dec}
  201.               DelYear := Year - 1       { in case you care to know...          }
  202.             END; { Block }
  203.       END; { With Block }
  204.   END;
  205.  
  206. FUNCTION CheckDateAndDelete(  path : String;
  207.                             FIBptr : FileInfoBlockPtr) : BOOLEAN;
  208.  
  209.   VAR
  210.     pathname,
  211.     filename  : String;
  212.     DOSError,
  213.     datediff  : Integer;
  214.     DD        : DateDescription;
  215.     DeleteIt  : BOOLEAN;
  216.     dirlock   : FileLock;
  217.  
  218.   BEGIN
  219.     DeleteIt := FALSE;              { set up some stuff... }
  220.     pathname := AllocString(140); 
  221.     filename := AllocString(31);  
  222.     strcpy(pathname,path);                      { path is dir file is in     }
  223.     strcpy(filename,ADR(FIBptr^.fib_FileName)); { get filename from FIB      }
  224.     strcat(pathname,"/");                       { put a / on the end of dir  }
  225.     strcat(pathname,filename);                  { put filename on end of dir }
  226.     StampDesc(FIBptr^.fib_Date,DD);             { get date from file         }
  227.     WITH DD DO
  228.       IF DelYear > Year THEN                    { check date against global  }
  229.         DeleteIt := TRUE                        { DelDates                   }
  230.       ELSE
  231.         IF DelYear = Year THEN
  232.           IF DelMonth > Month THEN
  233.             DeleteIt := TRUE
  234.           ELSE 
  235.             IF DelMonth = Month THEN
  236.               IF DelDay > Day THEN
  237.                 DeleteIt := TRUE;
  238.     IF NOT BeQuiet THEN              { Print out the filename if we're allowed }
  239.       Write(pathname,' ');
  240.     IF DeleteIt THEN                 { Delete file if its old enough. }
  241.       BEGIN
  242.         IF DeleteFile(pathname) THEN
  243.           BEGIN
  244.             IF NOT BeQuiet THEN      { Inform user of deletion }
  245.               WriteLn('\e[33;1mdeleted.\e[31;40;0m');
  246.           END
  247.         ELSE
  248.           BEGIN
  249.             DeleteIt := FALSE;  { Problem... }
  250.             DOSError := IOErr;
  251.             IF (DOSError = ERROR_DELETE_PROTECTED) THEN
  252.               BEGIN
  253.                 IF BeQuiet THEN         { We tell the user about deletion   }
  254.                   Write(pathname,' ');  { Protection even if we're supposed }
  255.                                         { to be quiet...                    }
  256.                 WriteLn('protected from deletion.');
  257.               END
  258.             ELSE
  259.               IF NOT BeQuiet THEN    { Inform user of error }
  260.                 WriteLn('not deleted.  \e[33;1mError #',DOSError,'\e[31;40;0m');
  261.           END;
  262.       END
  263.     ELSE
  264.       IF NOT BeQuiet THEN
  265.         WriteLn('not deleted.  File too new.');
  266.     CheckDateAndDelete := DeleteIt;
  267.   END;
  268.  
  269. PROCEDURE DeleteDir(pathname : String);
  270.  
  271.   { We try to delete the directory.  Assuming its empty it works, otherwise,
  272.     it not empty and we don't do anything.  In version 1.1, this procedure
  273.     didn't exist.  I used a call to CheckDateAndDelete and checked FIBptr within
  274.     that function to see if this was a directory.  It it was, the function
  275.     didn't do any string manipulation to get a pathname, because the correct
  276.     one was already in the calling parameters.  Only one problem, deleting a
  277.     file within a directory changes its date.  That means that subdirectories
  278.     in the trashcan NEVER got deleted unless they were empty to begin with.
  279.     Now we try to delete all subdirs.  If they're empty they're gone, if not
  280.     then we leave them.  Simple. }
  281.  
  282.   VAR
  283.     DOSError : Integer;
  284.  
  285.   BEGIN
  286.     IF NOT BeQuiet THEN
  287.       Write(pathname,' ');
  288.     IF NOT DeleteFile(pathname) THEN
  289.       BEGIN
  290.         DOSError := IOErr;
  291.         IF DOSError <> ERROR_DIRECTORY_NOT_EMPTY THEN
  292.           BEGIN
  293.             IF NOT BeQuiet THEN
  294.               WriteLn('not deleted.  \e[33;1mError #',DOSError,'\e[31;40;0m');
  295.           END
  296.         ELSE
  297.           IF NOT BeQuiet THEN
  298.             WriteLn('not deleted.');
  299.       END
  300.     ELSE
  301.       IF NOT BeQuiet THEN
  302.         WriteLn('\e[33mdeleted.\e[31;40;0m');
  303.   END; { DeleteDir }
  304.     
  305.             
  306. FUNCTION CleanUpDir(dir : string) : Short;
  307.  
  308.   { This function runs down the dir list using ExNext...If it finds a 
  309.     directory, it calls itself recursively.  After it goes through a
  310.     directory, it tries to delete it if files were deleted from within it }
  311.  
  312.   VAR
  313.     flock,
  314.     dirlock     : FileLock;
  315.     FIBptr      : FileInfoBlockPtr;
  316.     DoAnother,
  317.     barf        : BOOLEAN;
  318.     DOSError    : Integer;
  319.     count,
  320.     subdircount : Short;
  321.     newdir      : String;
  322.   
  323.   BEGIN
  324.     count := 0;
  325.     flock := Lock(dir,ACCESS_READ);
  326.     IF flock = NIL THEN  { Couldn't get lock:  dir doesn't exist! }
  327.         CleanUpDir := -1;
  328.     New(FIBptr);
  329.     IF NOT Examine(flock,FIBptr) THEN  { Can't get info on flock!? }
  330.       BEGIN
  331.         Unlock(flock);  
  332.         CleanUpDir := 0;
  333.       END;
  334.     IF FIBptr^.fib_DirEntryType < 0 THEN { This isn't a directory, its a file! }
  335.       BEGIN
  336.         Unlock(flock);
  337.         CleanUpDir := -2;
  338.       END;
  339.     REPEAT
  340.       BEGIN
  341.         DoAnother := ExNext(flock, FIBptr);
  342.         IF CheckBreak THEN
  343.           DoAnother := FALSE;
  344.         IF DoAnother THEN
  345.           BEGIN
  346.             IF FIBptr^.fib_DirEntryType < 0 THEN  { we've got a file... }
  347.               BEGIN
  348.                 IF CheckDateAndDelete(dir,FIBptr) THEN
  349.                   count := count + 1;
  350.               END
  351.             ELSE
  352.               BEGIN    { Another directory... }
  353.                 newdir := AllocString(109);
  354.                 strcpy(newdir,dir);
  355.                 strcat(newdir,"/");
  356.                 strcat(newdir,ADR(FIBptr^.fib_FileName));
  357.                 subdircount := CleanUpDir(newdir);
  358.                 count := count + subdircount;
  359.                 IF subdircount > 0 THEN
  360.                   BEGIN
  361.                     dirlock := Lock(newdir,ACCESS_READ);
  362.                     IF dirlock = NIL THEN
  363.                       BEGIN
  364.                         WriteLn('Unable to lock ',newdir);
  365.                         Exit(25);
  366.                       END;
  367.                     IF NOT Examine(dirlock,FIBptr) THEN
  368.                       BEGIN
  369.                         WriteLn('Unable to examine ',newdir);
  370.                         Exit(25);
  371.                       END;
  372.                     Unlock(dirlock);
  373.                     DeleteDir(newdir);
  374.                   END;
  375.               END
  376.           END
  377.         ELSE
  378.           BEGIN
  379.             DOSError := IOErr;  { This might not be bad... }
  380.             IF (DOSError <> ERROR_NO_MORE_ENTRIES) AND NOT CheckBreak THEN
  381.               WriteLn('\nError #',DOSError,' has occurred.');
  382.           END;
  383.       END;
  384.     UNTIL NOT DoAnother;
  385.     Unlock(flock);
  386.     CleanUpDir := count;
  387.   END;
  388.  
  389.  
  390. BEGIN
  391.   GetCL(CLstrings,MaxDaysOld,BeQuiet);
  392.   IF (MaxDaysOld = -42) OR strieq(CLstrings[1],"H") 
  393.                                       OR strieq(CLstrings[1],"?") THEN
  394.     BEGIN
  395.       WriteLn;
  396.       WriteLn('\e[33;1mTrashCompactor\e[31;40;0m by Stephan Zuercher');
  397.       WriteLn('Version 1.11 on December 7, 1991');
  398.       WriteLn;
  399.       WriteLn('Usage:  TrashCompactor -# [path1] [path2] ... [path10] [QUIET]');
  400.       WriteLn;
  401.       WriteLn('Where   #   = age of files in days before deletion occurs.');
  402.       WriteLn('              The default is 5 days.');
  403.       WriteLn('      path# = one of ten possible directories to treat as');
  404.       WriteLn('              Trashcans.  Default is SYS:Trashcan.');
  405.       WriteLn('      QUIET = a switch that controls the whether the program');
  406.       WriteLn('              outputs information about file deletion to the');
  407.       WriteLn('              screen.');
  408.       Exit(20);
  409.     END;
  410.  
  411.   GetDeleteDate(MaxDaysOld,DelMonth,DelDay,DelYear);
  412.  
  413.   count := 1;
  414.   numdel := 0;
  415.   totdel := 0;
  416.   WHILE (StrLen(CLStrings[count]) > 0) AND NOT CheckBreak DO
  417.     BEGIN
  418.       numdel := CleanUpDir(CLStrings[count]);
  419.       IF numdel >= 0 THEN
  420.         totdel := totdel + numdel
  421.       ELSE
  422.         BEGIN
  423.           Write(CLStrings[count]);
  424.           IF numdel = -2 THEN
  425.             WriteLn(' is NOT a directory.')
  426.           ELSE
  427.             WriteLn(' does NOT exist.');
  428.         END;
  429.       count := count + 1;
  430.     END;
  431.   IF NOT BeQuiet THEN WriteLn(totdel,' files deleted.');
  432.     
  433. END.
  434.