home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / disks / tools / dupfinder / src / dupfinder.c
C/C++ Source or Header  |  1981-06-29  |  9KB  |  318 lines

  1. #define __USE_SYSBASE
  2.  
  3. #include <exec/execbase.h>
  4. #include <exec/memory.h>
  5. #include <dos/exall.h>
  6. #include <libraries/utgui.h>
  7. #include <clib/exec_protos.h>
  8. #include <clib/dos_protos.h>
  9. #include <clib/utgui_protos.h>
  10. #include <clib/alib_protos.h>
  11. #include <pragmas/exec_pragmas.h>
  12. #include <pragmas/dos_pragmas.h>
  13. #include <pragmas/utgui_pragmas.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16.  
  17. #define BUFSIZE 2000
  18.  
  19. static UBYTE *version_string = "$VER: DupFinder 1.0 (24.4.95)";
  20.  
  21. UBYTE *template = "PATH/A/M,NAMES/S,MINSIZE=MIN/N,NOICONS=NOINFO/S,PRI/N";
  22.  
  23. enum {
  24.     PATH,
  25.     NAMES,
  26.     MINSIZE,
  27.     NOICONS,
  28.     PRI,
  29.     NUM_ARGS
  30. };
  31.  
  32. typedef struct l {
  33.     BPTR dir;
  34.     struct ExAllControl *eac;
  35.     struct ExAllData *entry;
  36.     struct l *next; 
  37. } list;
  38.  
  39. extern void * __asm AsmCreatePool(register __d0 ULONG, register __d1 ULONG, register __d2 ULONG, register __a6 struct ExecBase *);
  40. extern void __asm AsmDeletePool(register __a0 void *, register __a6 struct ExecBase *);
  41. extern void * __asm AsmAllocPooled(register __a0 void *, register __d0 ULONG, register __a6 struct ExecBase *);
  42. extern void __asm AsmFreePooled(register __a0 void *, register __a1 void *, register __d0 ULONG, register __a6 struct ExecBase *);
  43.  
  44. UWORD exall(struct ExecBase *SysBase, struct DosLibrary *DOSBase, list **myold, char *path, ULONG *numfiles, void *pool);
  45. __inline BOOL compare(BOOL first, BPTR thisdir, struct ExAllData *this, BPTR otherdir, struct ExAllData *other, LONG *arg_array, struct DosLibrary *DOSBase, struct ExecBase *SysBase, void *pool);
  46.  
  47. int __saveds main(void)
  48. {
  49.     struct ExecBase *SysBase = *(struct ExecBase **)4L;
  50.     struct RDArgs *rdargs=NULL;
  51.     LONG arg_array[NUM_ARGS];
  52.     struct DosLibrary *DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME, 37L);
  53.     struct Library *UTGuiBase = OpenLibrary("utgui.library", 1L);
  54.     struct ExAllData *this, *other;
  55.     list *mylist, *mynew, *myold;
  56.     char **trav; //, this_string[256], other_string[256];
  57.     void *pool;
  58.     UWORD ret;
  59.     APTR    progbar = NULL;
  60.     ULONG    files = 0L, filenum;
  61.     LONG oldpri=256;
  62.     BOOL first;
  63.  
  64.     if(!DOSBase) return(20L);
  65.  
  66.     if(!(pool = AsmCreatePool(MEMF_ANY, 10240, 5120, SysBase)))
  67.         goto quit;
  68.     
  69.     if(!(mylist = myold = AsmAllocPooled(pool, sizeof(list), SysBase))) goto quit;
  70.     mylist->next = NULL;
  71.     mylist->entry = NULL;
  72.     memset(arg_array, 0, sizeof(LONG)*NUM_ARGS);
  73.     if(!(rdargs = ReadArgs(template, arg_array, NULL))){
  74.         Printf("Usage: dupfinder <path1> [<path2> ...] [names] [minsize=<bytes>]\n"
  75.                  "                 [noicons] [pri=<priority>]\n");
  76.         goto quit;
  77.     }
  78.  
  79.     if(arg_array[PRI])
  80.         oldpri = SetTaskPri(FindTask(0), *(LONG *)arg_array[PRI]);
  81.  
  82.     for(trav = (char **)arg_array[PATH];*trav;trav++){
  83.         if(ret = exall(SysBase, DOSBase, &myold, *trav, &files, pool)){
  84.             if(ret != 2)
  85.                 Printf("ExAll() failed\n");
  86.             goto quit;
  87.         }
  88.     }
  89.  
  90.     if(UTGuiBase)
  91.         progbar = ugOpenProgressBar("DupFinder", PB_ProgressText, "Comparing files...", PB_Total, files, PB_InactiveWin, TRUE, TAG_DONE);
  92.  
  93.     for(mynew = mylist->next, filenum = 0; mynew; mynew = mynew->next){
  94.         for(this = mynew->entry; this; this=this->ed_Next, ++filenum){
  95.             first = TRUE;
  96.             if(progbar)
  97.                 ugUpdateProgressBar(progbar, PB_Current, filenum, TAG_DONE);
  98.             if(this->ed_Next) other = this->ed_Next;
  99.             else if(mynew->next) other = (mynew->next)->entry;
  100.             else break;
  101.             myold = mynew;
  102.             for(;; other->ed_Next ? (other = other->ed_Next)
  103.                  : (myold->next ? (other = (myold = myold->next)->entry)
  104.                  : (other = NULL))){
  105.                 if(!other) break;
  106.                 if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C){
  107.                     Printf("***Break\n");
  108.                     goto quit;
  109.                 }
  110.                 if(compare(first, mynew->dir, this, myold->dir, other, arg_array, DOSBase,
  111.                     SysBase, pool)) first = FALSE;
  112.             }
  113.             if(!first) Printf("\n");
  114.         }
  115.     }
  116.  
  117. quit:
  118.     if(progbar)
  119.         ugCloseProgressBar(progbar);
  120.  
  121.     for(myold = mynew = mylist; myold; myold=mynew){
  122.         if(mynew) mynew=mynew->next;
  123.         if(myold != mylist && myold->eac){
  124.             FreeDosObject(DOS_EXALLCONTROL, myold->eac);
  125.             UnLock(myold->dir);
  126.         }
  127.     }
  128.     AsmDeletePool(pool, SysBase);
  129.     if(oldpri!=256) SetTaskPri(FindTask(0), oldpri);
  130.     if(rdargs) FreeArgs(rdargs);
  131.     CloseLibrary(UTGuiBase);
  132.     CloseLibrary((struct Library *)DOSBase);
  133.     return(0L);
  134. }
  135.  
  136.  
  137. UWORD exall(struct ExecBase *SysBase, struct DosLibrary *DOSBase, list **myold, char *path, ULONG *numfiles, void *pool)
  138. {
  139.     list *mynew;
  140.     int more;
  141.     char *buffer, *nfl_buf;
  142.     struct ExAllData *entry;
  143.     BPTR mylock;
  144.     struct ExAllControl *eac;
  145.     BOOL first=TRUE, broken=FALSE;
  146.     UWORD ret;
  147.  
  148.     if(!(mylock = Lock(path, ACCESS_READ))){
  149.         Printf("Can't lock \"%s\".\n", path);
  150.         return(1);
  151.     }
  152.  
  153.     if(!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL))){
  154.         UnLock(mylock);
  155.         return(1);
  156.     }
  157.     eac->eac_LastKey = 0;
  158.     do {
  159.         if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C){
  160.             if(DOSBase->dl_lib.lib_Version >= 39){
  161.                 Printf("***Break\n");
  162.                 UnLock(mylock);
  163.                 FreeDosObject(DOS_EXALLCONTROL, eac);
  164.                 return(2);
  165.             }
  166.             else broken = TRUE;
  167.         }
  168.         if(buffer = AsmAllocPooled(pool, BUFSIZE, SysBase))
  169.             more = ExAll(mylock, (struct ExAllData *)buffer, BUFSIZE, ED_SIZE, eac);
  170.         if(!buffer || (!more && (IoErr() !=ERROR_NO_MORE_ENTRIES))){
  171.             FreeDosObject(DOS_EXALLCONTROL, eac);
  172.             UnLock(mylock);
  173.             return(1);  // Something seriously wrong.
  174.         }
  175.         if(eac->eac_Entries==0){
  176.             FreeDosObject(DOS_EXALLCONTROL, eac);
  177.             UnLock(mylock);
  178.             return(0);
  179.         }
  180.         *numfiles += eac->eac_Entries;
  181.  
  182.         if(!(mynew = AsmAllocPooled(pool, sizeof(list), SysBase))){
  183.             FreeDosObject(DOS_EXALLCONTROL, eac);
  184.             UnLock(mylock);
  185.             return(1);
  186.         }
  187.         memset(mynew, 0, sizeof(list));
  188.         (*myold)->next = mynew;
  189.         if(first) mynew->eac = eac;
  190.         first = FALSE;
  191.         mynew->entry = (struct ExAllData *) buffer;
  192.         mynew->dir = mylock;
  193.         *myold = mynew;
  194.  
  195.         if(!broken && (nfl_buf = AsmAllocPooled(pool, 256, SysBase))){
  196.             for(entry = mynew->entry; entry; entry=entry->ed_Next)
  197.             if(entry->ed_Type == ST_USERDIR){
  198.                 NameFromLock(mylock, nfl_buf, 255);
  199.                 AddPart(nfl_buf, entry->ed_Name, 255);
  200.                 if(ret = exall(SysBase, DOSBase, myold, nfl_buf, numfiles, pool)){
  201.                     if(ret != 2)
  202.                         Printf("Couldn't check \"%s\"\n", nfl_buf);
  203.                     AsmFreePooled(pool, nfl_buf, 256, SysBase);
  204.                     return(ret);
  205.                 }
  206.             }
  207.             AsmFreePooled(pool, nfl_buf, 256, SysBase);
  208.         }
  209.     } while(more);
  210.     if(broken){
  211.         Printf("***Break\n");
  212.         return(2);
  213.     }
  214.     return(0);
  215. }
  216.  
  217. #define BSIZE 32768
  218.  
  219. __inline BOOL compare(BOOL first, BPTR thisdir, struct ExAllData *this, BPTR otherdir,
  220.                       struct ExAllData *other, LONG *arg_array,
  221.                       struct DosLibrary *DOSBase, struct ExecBase *SysBase, void *pool)
  222. {
  223.     char other_string[256], this_string[256];
  224.     static char *other_buffer = NULL, *this_buffer = NULL;
  225.     int actual = this->ed_Size, bsize = 512;
  226.     BPTR fh_this, fh_other;
  227.  
  228.     // Compare files
  229.     if(this->ed_Type!=ST_FILE
  230.         || !this->ed_Size
  231.         || (!arg_array[NAMES] && this->ed_Size != other->ed_Size)
  232.         || (arg_array[MINSIZE] ? (this->ed_Size < *(LONG *)arg_array[MINSIZE]) : FALSE))
  233.         return(FALSE);
  234.  
  235.     if(this->ed_Size != other->ed_Size){
  236.         if(!stricmp(this->ed_Name, other->ed_Name)){
  237.             NameFromLock(thisdir, this_string, 255);
  238.             AddPart(this_string, this->ed_Name, 255);
  239.             NameFromLock(otherdir, other_string, 255);
  240.             AddPart(other_string, other->ed_Name, 255);
  241.             if(!strcmp(this_string, other_string)) return(FALSE);
  242.             if(first) Printf("\"%s\"  ;identical to\n\"%s\" ;name only\n",
  243.                                   this_string, other_string);
  244.             else Printf("\"%s\" ;name only\n", other_string);
  245.             return(TRUE);
  246.         }
  247.         return(FALSE);
  248.     }
  249.  
  250.     NameFromLock(thisdir, this_string, 255);
  251.     AddPart(this_string, this->ed_Name, 255);
  252.     NameFromLock(otherdir, other_string, 255);
  253.     AddPart(other_string, other->ed_Name, 255);
  254.  
  255.     if(!strcmp(this_string, other_string)) return(FALSE);
  256.  
  257.     if(arg_array[NOICONS] && (strlen(this_string)>5
  258.         && !stricmp(&this_string[strlen(this_string)-5], ".info")))
  259.         return(FALSE);
  260.  
  261.     if(!(fh_this = Open(this_string, MODE_OLDFILE))){
  262.         Printf("Can't open \"%s\".\n", this_string);
  263.         return(FALSE);
  264.     }
  265.     if(!(fh_other = Open(other_string, MODE_OLDFILE))){
  266.         Printf("Can't open \"%s\".\n", other_string);
  267.         Close(fh_this);
  268.         return(FALSE);
  269.     }
  270.  
  271.     if(!this_buffer)
  272.         if(!(this_buffer = AsmAllocPooled(pool, BSIZE, SysBase))){
  273.             PutStr("Out of memory.\n");
  274.             return(FALSE);
  275.         }
  276.     if(!other_buffer)
  277.         if(!(other_buffer = AsmAllocPooled(pool, BSIZE, SysBase))){
  278.             PutStr("Out of memory.\n");
  279.             return(FALSE);
  280.         }
  281.  
  282.     while(actual>0){
  283.         if(Read(fh_this, this_buffer, bsize)!=-1){
  284.             if(Read(fh_other, other_buffer, bsize)!=-1){
  285.                 if(memcmp(this_buffer, other_buffer, (actual<bsize) ? actual : bsize)){
  286.                     Close(fh_other);
  287.                     Close(fh_this);
  288.                     if(arg_array[NAMES] && !strcmp(this->ed_Name, other->ed_Name)){
  289.                         if(first) Printf("\"%s\"  ;identical to\n\"%s\" ;name only\n",
  290.                                               this_string, other_string);
  291.                         else Printf("\"%s\" ;name only\n", other_string);
  292.                         return(TRUE);
  293.                     }
  294.                     return(FALSE);
  295.                 }
  296.             } else {
  297.                 Printf("Error reading from \"%s\" (error: %ld)\n", other_string, IoErr());
  298.                 Close(fh_other);
  299.                 Close(fh_this);
  300.                 return(FALSE);
  301.             }
  302.         } else {
  303.             Printf("Error reading from \"%s\" (error: %ld)\n", this_string, IoErr());
  304.             Close(fh_other);
  305.             Close(fh_this);
  306.             return(FALSE);
  307.         }
  308.         actual-=bsize;
  309.         bsize = BSIZE;
  310.     }
  311.     if(first) Printf("\"%s\"  ;identical to\n\"%s\"\n", this_string, other_string);
  312.     else Printf("\"%s\"\n", other_string);
  313.     other->ed_Type = ~ST_FILE;
  314.     Close(fh_other);
  315.     Close(fh_this);
  316.     return(TRUE);
  317. }
  318.