home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1222 < prev    next >
Internet Message Format  |  1990-12-28  |  6KB

  1. From: andrewt@watnow.waterloo.edu (Andrew Thomas)
  2. Newsgroups: alt.sources
  3. Subject: purge - Remove old emacs backup files safely
  4. Message-ID: <ANDREWT.90Apr23091019@watnow.waterloo.edu>
  5. Date: 23 Apr 90 14:10:19 GMT
  6.  
  7.  
  8. A couple of years ago I noticed that directories for really big
  9. projects edited using emacs tended to get cluttered by lots of .~n~
  10. files.  I started typing things like  rm *~, or rm *.~*~  to get rid
  11. of them, and noticed that a little typo had catastrophic effects.
  12.  
  13. I wrote this program, which I called "purge", in C to do this stuff
  14. for me.   At the time I didn't know awk or perl, so there is
  15. undoubtedly a shorter way to do it, but for what it's worth, here's my
  16. stuff.  No complaints about programming style please: I know it's a
  17. little sloppy.
  18.  
  19. What purge does:
  20.   1) Search a directory for all files ending in .~n~ or ~
  21.   2) establish that there is a more recently NUMBERED program of the
  22.      same name, either with a .~n~ extension or with no extension.
  23.      e.g.,  main.c.~2~  is newer than  main.c.~1~  and main.c  is
  24.         newer than both of them.
  25.      Purge does not check file dates, though it really should.
  26.   3) If a newer version can be found for a particular .~n~ or ~ file,
  27.      then remove that file and report it.
  28.   4) Has the following arguments:
  29.     directory name:  Purge this directory.
  30.     -c : confirm every file before erasing it.
  31.     -r : recursively purge, starting at named or current
  32.          directory.
  33.      Flags and directory names may appear anywhere.  Flags are not toggles.
  34.  
  35. The thing I like about this is that it won't make stupid mistakes like
  36. "rm *".  It also tries not to delete all copies of a file.  File names
  37. with wild cards in them are not globbed.
  38.  
  39. I make no claims to this code at all.  If you want to say you wrote
  40. it, go ahead.  I also take no responsibility for any of its actions.
  41.  
  42. I have been using this on a uVaxII running Ultrix 2.0,  a Sun 3
  43. running SUNOS3 and SUNOS4 and a SparcServer running SUNOS4.  I have
  44. never had it do something unexpected in two years or service.  That's
  45. more than I can say for my typing. :-)
  46.  
  47. compile with:
  48.   {g}cc -O -o purge purge.c
  49.  
  50. -------------------  purge.c -------------------
  51. #include <stdio.h>
  52. #include <strings.h>
  53. #include <ctype.h>
  54. #include <sys/types.h>
  55. #include <sys/dir.h>
  56. #include <sys/stat.h>
  57.  
  58. void Usage (s)
  59.   char*    s;
  60. {
  61.   fprintf (stderr, "Usage: %s [directory_name ...] [-c] [-r]\n", s);
  62.   fprintf (stderr, "       -c = confirm before erasing files\n");
  63.   fprintf (stderr, "       -r = recursively follow all subdirectories\n");
  64.   exit (1);
  65. }  
  66.  
  67. int main(argc, argv)
  68.      int    argc;
  69.      char    *argv[];
  70. {
  71.   int        confirm = 0, i, recurse = 0, got_one = 0;
  72.   
  73.   for (i=1; i<argc; i++)
  74.     {
  75.       switch (argv[i][0])
  76.     {
  77.     case '-':
  78.       switch (argv[i][1])
  79.         {
  80.         case 'c':
  81.           confirm = 1;
  82.           break;
  83.         case 'r':
  84.           recurse = 1;
  85.           break;
  86.         default:
  87.           Usage (argv[0]);
  88.           break;
  89.         }
  90.       break;
  91.     }
  92.     }
  93.   for (i=1; i<argc; i++) 
  94.     {
  95.       if (argv[i][0] != '-')
  96.     {
  97.       Do_Purge (argv[i], confirm, recurse);
  98.       got_one = 1;
  99.     }
  100.     }
  101.   if (!got_one) Do_Purge (".", confirm, recurse);
  102.   return (0);
  103. }
  104.  
  105. char* strsav(s)
  106.      char* s;
  107. {
  108.   char* t;
  109.   t = (char*)malloc(strlen(s)+1);
  110.   strcpy (t,s);
  111.   return (t);
  112. }
  113.  
  114. Do_Purge (directory, confirm, recurse)
  115.      char*        directory;
  116.      int        confirm;
  117.      int        recurse;
  118. {
  119.   DIR        *dirp;
  120.   struct direct    *entry;
  121.   char        *deletes[1000];
  122.   int        ndels = 0, i, slash = 0;
  123.   char        wholefile[160], instr[80], *this_file;
  124.   int        mycompare();
  125.     
  126.   if (!is_directory(directory))
  127.     {
  128.       fprintf (stderr, "File: %s - not a directory\n", directory);
  129.       return;
  130.     }
  131.   if ((dirp = opendir(directory)) == NULL)
  132.     {
  133.       fprintf (stderr, "Could not open directory: %s\n", directory);
  134.       return;
  135.     }
  136.   
  137.   if (directory[strlen(directory)-1] != '/') slash = 1;
  138.   for (entry = readdir(dirp); entry != NULL; entry = readdir(dirp))
  139.     {
  140.       sprintf (wholefile, "%s%s%s",
  141.            directory,
  142.            (slash ? "/" : ""),
  143.            entry->d_name);
  144.       if (recurse && is_directory(wholefile))
  145.     {
  146.       if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
  147.         {
  148.           Do_Purge (wholefile, confirm, recurse);
  149.         }
  150.       continue;
  151.     }
  152.       if (entry->d_name[strlen(entry->d_name)-1] == '~')
  153.     {
  154.       if (Has_More_Recent(entry, dirp))
  155.         {
  156.           deletes[ndels++] = strsav(wholefile);
  157.         }
  158.     }
  159.     }
  160.  
  161.   qsort (deletes, ndels, sizeof(char *), mycompare);
  162.  
  163.   for (i=0; i<ndels; i++)
  164.     {
  165.       this_file = deletes[i];
  166.       if (confirm)
  167.     {
  168.       fprintf (stdout, "Delete: %s ? (y/n/q/a) ", this_file);
  169.       fscanf (stdin, "%s", instr);
  170.       instr[0] = tolower(instr[0]);
  171.       if (instr[0] == 'a')
  172.         {
  173.           confirm = 0;
  174.           instr[0] = 'y';
  175.         }
  176.       else if (instr[0] == 'q')
  177.         {
  178.           i = ndels;
  179.         }
  180.     }
  181.       else
  182.     {
  183.       fprintf (stdout, "Delete: %s\n", this_file);
  184.       instr[0] = 'y';
  185.     }
  186.       if (instr[0] == 'y') unlink (this_file);
  187.     }
  188.   closedir (dirp);
  189. }
  190.  
  191. int mycompare(a, b)
  192.      char    **a, **b;
  193. {
  194.   return (strcmp(*a, *b));
  195. }
  196.  
  197. Has_More_Recent (thisentry, dirp)
  198.      struct    direct    *thisentry;
  199.      DIR    *dirp;
  200. {
  201.   long        spot;
  202.   struct direct *rentry;
  203.   char        candidate[160];
  204.   int        a;
  205.   char        *directory;
  206.  
  207.   strcpy (candidate, thisentry->d_name);
  208.   *index(candidate, '~') = '\0';
  209.   if (candidate[a=strlen(candidate)-1] == '.') candidate[a] = '\0';
  210.   
  211.   spot = telldir(dirp);
  212.   rewinddir (dirp);
  213.   for (rentry = readdir(dirp); rentry != NULL; rentry = readdir(dirp))
  214.     {
  215.       if (rentry != thisentry)
  216.     {
  217.       if (!strcmp(rentry->d_name, candidate))
  218.         {
  219.           seekdir (dirp, spot);
  220.           return (1);
  221.         }
  222.     }
  223.     }
  224.   seekdir (dirp, spot);
  225.   return (0);
  226. }
  227.  
  228. int is_directory (directory)
  229.      char* directory;
  230. {
  231.   struct stat stats;
  232.   stat (directory, &stats);
  233.   if (stats.st_mode & S_IFDIR) return (1);
  234.   else return (0);
  235. }
  236.  
  237. -----------------------------------------------
  238. --
  239.  
  240. Andrew Thomas
  241. andrewt@watnow.waterloo.edu    Systems Design Eng.    University of Waterloo
  242. "If a million people do a stupid thing, it's still a stupid thing." - Opus
  243.