peter@sugar.UUCP (Peter da Silva) (10/06/87)
Here is a disk cataloger! I personally have been needing this for quite some time! Thanx Peter! Doc : This archive contains the following files... : 'catalog.man' : 'catalog.c' : 'PatMatch.c' : 'Makefile' : To extract them, run the following through /bin/sh echo x - catalog.man sed 's/^X//' > catalog.man << '//END' XNAME X X CATALOG -- build file catalog. X X XSYNOPSIS X X CATALOG [TO|IN catalog] [ADD] [MULTI] volumes [FIND patterns] [LIST] X X XDESCRIPTION X X This is a CLI-based program that builds a useful little catalog of X all the files on your disks. The catalog itself is kept in text X format, so you can edit it if need be. The syntax of the command is: X X TO|IN catalog Specify the name of the file to read the catalog X from and/or write it to. X X [ADD] volumes Specify the volumes to search for files. The X keyword ADD is optional. X X MULTI Search the specified volumes multiple times. X generally you want to use a device name for the X volume name when you do this. e.g. "MULTI df1:". X X FIND patterns Search the catalog file for the specified patterns. X Patterns are a superset of AmigaDOS patterns: you can X specify, for example, (#?.h)|(#?.c) to search for a X file ending in .h or .c. X X LIST List the contents of the catalog in a convenient X format. X X XFILES X X disk.catalog for default catalog file. X X XBUGS X X None known. X X XAUTHOR X X Peter da Silva. X Pattern Matching code by Jeff Lydiatt X X XNOTES X X At some point this will be updated to use a variation of my X STDFILE/INSTANT-APPLICATION interface. It would also be desirable X to be able to DELETE based on a pattern, allowing such things as: X X CATALOG ADD MULTI df0: DELETE #?.(info)|(zing) X X Also, sorting or searching by directory might be desirable. X X Insertion into the catalog is slow. A faster implementation using X a binary tree instead of a linked list would definitely be desirable. //END echo x - catalog.c sed 's/^X//' > catalog.c << '//END' X/* catalog -- cli-based disk catalog -- Peter da Silva */ X X/* Usage: X * X * Catalog [TO|IN catalog] [ADD] [MULTI] volumes [FIND patterns] [LIST] X */ X#include <intuition/intuition.h> X#include <exec/memory.h> X#include <libraries/dos.h> X#include <stdio.h> X#include <ctype.h> X#define BPTR long X Xchar *catalog = 0; X#define DEFCATALOG "disk.catalog" X Xint loaded; Xint modified; Xint mode; Xint multi; X#define ADD 0 X#define FIND 1 X XUBYTE *AllocMem(); Xchar *malloc(); Xchar *strchr(); X Xmain(ac, av) Xint ac; Xchar **av; X{ X int i; X X if(ac<=1) { X printf("Usage:\n"); X printf("Catalog [TO|IN catalog] [ADD] [MULTI] volumes [FIND patterns] [LIST]\n\n"); X printf("Default catalog=\"%s\"\n", DEFCATALOG); X exit(0); X } X mode = ADD; X loaded = 0; X modified = 0; X multi = 0; X X for(i = 1; i < ac; i++) { X if(strmatch(av[i], "TO") || strmatch(av[i], "IN")) { X catalog = av[++i]; X } else if(strmatch(av[i], "FIND")) { X mode = FIND; X } else if(strmatch(av[i], "ADD")) { X mode = ADD; X } else if(strmatch(av[i], "LIST")) { X list(); X } else if(strmatch(av[i], "MULTI")) { X multi = 1; X } else { X switch(mode) { X case ADD: add(av[i]); break; X case FIND: find(av[i]); break; X } X } X } X if(modified) X dump_files(); X} X Xstruct _f { X char *file; X char *path; X long size; X char *note; X struct _f *next, *prev; X} *filelist = 0; X Xfreenode(n) Xstruct _f *n; X{ X if(n->file) X free(n->file); X if(n->path) X free(n->path); X if(n->note) X free(n->note); X free(n); X} X Xprintnode(n) Xstruct _f *n; X{ X printf("%-24s %8ld %s\n", n->file, n->size, n->path); X if(n->note) X printf("%24s %s\n", "", n->note); X} X Xadd_file(filename, pathname, filesize, filenote) Xchar *filename; Xchar *pathname; Xlong filesize; Xchar *filenote; X{ X struct _f *tmp, *ptr; X int cmp; X X tmp = malloc(sizeof(struct _f)); X if(!tmp) return 0; X tmp->next = tmp; X tmp->prev = tmp; X tmp->size = filesize; X tmp->file = 0; X tmp->path = 0; X tmp->note = 0; X tmp->file = malloc(strlen(filename)+1); X if(!tmp->file) { X freenode(tmp); X return 0; X } X strcpy(tmp->file, filename); X X tmp->path = malloc(strlen(pathname)+1); X if(!tmp->path) { X freenode(tmp); X return 0; X } X strcpy(tmp->path, pathname); X X if(filenote && filenote[0]) { X tmp->note = malloc(strlen(filenote)+1); X if(!tmp->note) { X freenode(tmp); X return 0; X } X strcpy(tmp->note, filenote); X } X X if(!filelist) { X filelist = tmp; X } else { X ptr = filelist; X X /* first check if you can insert it at the end of the list */ X /* if so, don't bother scanning. This should improve the */ X /* performance on inserting sorted lists */ X if((cmp = order(ptr->prev, tmp)) >= 0) { X do { X if((cmp=order(ptr, tmp)) >= 0) X break; X ptr = ptr->next; X } while(ptr != filelist); X } X X if(cmp==0) { X freenode(tmp); X } else { X tmp->prev = ptr->prev; X tmp->next = ptr; X ptr->prev->next = tmp; X ptr->prev = tmp; X if(ptr==filelist && cmp>=0) X filelist = tmp; X } X } X return 1; X} X Xorder(n1, n2) Xstruct _f *n1, *n2; X{ X int cmp; X X cmp = compare(n1->file, n2->file); X if(cmp==0) X cmp = compare(n1->path, n2->path); X return cmp; X} X Xdel_vol(vol) Xchar *vol; X{ X char *ptr, *nxt; X int just_moved; X X if(!filelist) X return 1; X X ptr = filelist; X do { X nxt = ptr->next; X just_moved = 0; X if(strncmp(vol, ptr->path, strlen(vol))) { X ptr->prev->next = ptr->next; X ptr->next->prev = ptr->prev; X freenode(ptr); X if(ptr==filelist) { X if(filelist==nxt) { X filelist = 0; X break; X } X filelist = nxt; X just_moved = 1; X } X } X ptr = nxt; X } while(!just_moved && ptr != filelist); X return 1; X} X Xdump_files() X{ X FILE *fp; X struct _f *ptr; X X if(catalog==0) X catalog = DEFCATALOG; X if(!(fp = fopen(catalog, "w"))) { X perror(catalog); X return 0; X } X X if(filelist) { X ptr = filelist; X do { X if(ptr->note) X fprintf(fp, "%s:%ld:%s:%s\n", X ptr->file, ptr->size, ptr->path, ptr->note); X else X fprintf(fp, "%s:%ld:%s\n", X ptr->file, ptr->size, ptr->path); X ptr = ptr->next; X } while(ptr != filelist); X } X X fclose(fp); X return 1; X} X Xint loaded_files, files, directories; X Xload_files() X{ X FILE *fp; X char *p; X char buffer[BUFSIZ]; X long filesize; X char *filename, *pathname, *filenote; X X if(catalog==0) X catalog = DEFCATALOG; X X if(!(fp = fopen(catalog, "r"))) { X perror(catalog); X return 0; X } X X loaded_files = 0; X while(fgets(buffer, BUFSIZ, fp)) { X buffer[strlen(buffer)-1] = 0; X filename = buffer; X p = strchr(buffer, ':'); X if(p) { X *p++ = 0; X filesize = atoi(p); X p = strchr(p, ':'); X if(p) { X *p++ = 0; X pathname = p; X p = strchr(p, ':'); /* skip ':' in path name */ X if(p) p = strchr(p+1, ':'); X if(p) { X *p++ = 0; X if(*p) X filenote = p; X else X filenote = 0; X } else X filenote = 0; X add_file(filename, pathname, filesize, filenote); X loaded_files++; X } X } X } X X printf("%s: %d files\n", catalog, loaded_files); X fclose(fp); X} X Xchar pathname[BUFSIZ]; X Xscan_disk() X{ X struct FileInfoBlock *FIB; X BPTR lock; X int len; X X if(!(lock=Lock(pathname, ACCESS_READ))) { X fprintf(stderr, "Can't access %s: error %d\n", X pathname, IoErr()); X return 0; X } X FIB = (struct FileInfoBlock *)AllocMem( X sizeof(struct FileInfoBlock), X MEMF_CLEAR); X if(!FIB) { X UnLock(lock); X return 0; X } X if(!Examine(lock, FIB)) { X fprintf(stderr, "Can't examine %s: error %d\n", X pathname, IoErr()); X UnLock(lock); X FreeMem(FIB, sizeof(struct FileInfoBlock)); X return 0; X } X if(FIB->fib_DirEntryType < 0) { X fprintf(stderr, "%s: is not a directory.\n"); X UnLock(lock); X FreeMem(FIB, sizeof(struct FileInfoBlock)); X return 0; X } X while(ExNext(lock, FIB)) { X if(FIB->fib_DirEntryType < 0) { X add_file( X FIB->fib_FileName, X pathname, X FIB->fib_Size, X FIB->fib_Comment); X files++; X } else { X len = strlen(pathname); X if(pathname[len-1] == ':') X strcpy(&pathname[len], FIB->fib_FileName); X else X sprintf(&pathname[len], "/%s", FIB->fib_FileName); X if(!scan_disk()) { X UnLock(lock); X FreeMem(FIB, sizeof(struct FileInfoBlock)); X return 0; X } X pathname[len] = 0; X directories++; X } X } X UnLock(lock); X FreeMem(FIB, sizeof(struct FileInfoBlock)); X return 1; X} X Xadd(vol) Xchar *vol; X{ X if(multi == 0) X _add(vol); X else { X while(1) { X char tmp[BUFSIZ]; X printf("Scan %s [Y]? ", vol); X gets(tmp); X if(tmp[0]=='n' || tmp[0]=='N') X break; X _add(vol); X } X } X} X X_add(vol) Xchar *vol; X{ X struct FileInfoBlock *FIB; X BPTR lock; X int len; X X if(!(lock=Lock(vol, ACCESS_READ))) { X fprintf(stderr, "Can't access %s: error %d\n", X vol, IoErr()); X return 0; X } X FIB = (struct FileInfoBlock *)AllocMem( X sizeof(struct FileInfoBlock), X MEMF_CLEAR); X if(!FIB) { X UnLock(lock); X return 0; X } X if(!Examine(lock, FIB)) { X fprintf(stderr, "Can't examine %s: error %d\n", X vol, IoErr()); X UnLock(lock); X FreeMem(FIB, sizeof(struct FileInfoBlock)); X return 0; X } X sprintf(pathname, "%s:", FIB->fib_FileName); X UnLock(lock); X FreeMem(FIB, sizeof(struct FileInfoBlock)); X X if(!loaded) { X load_files(); X loaded = 1; X } X del_vol(vol); X files = 0; X directories = 1; X if(scan_disk()) { X modified = 1; X printf("%s %d files %d directories.\n", X pathname, files, directories); X } X} X Xfind(s) Xchar *s; X{ X struct _f *ptr; X static WORD PatCode[128]; X X if(!loaded) { X load_files(); X loaded = 1; X } X X CmplPat(s, PatCode); X if(ptr = filelist) { X do { X if(Match(s, PatCode, ptr->file)) X printnode(ptr); X ptr = ptr->next; X } while(ptr != filelist); X } X} X Xlist() X{ X struct _f *ptr; X X if(!loaded) { X load_files(); X loaded = 1; X } X X if(ptr = filelist) { X do { X printnode(ptr); X ptr = ptr->next; X } while(ptr != filelist); X } X} X Xstrmatch(s1, s2) Xchar *s1, *s2; X{ X while(*s1) { X if(*s1!=*s2 && X ((islower(*s1) && toupper(*s1)!=*s2) || X (islower(*s2) && *s1!=toupper(*s2)) ) X ) { X return 0; X } X s1++; X s2++; X } X return !*s2; X} X Xcompare(s1, s2) XUBYTE *s1, *s2; X{ X UBYTE c1, c2; X X while(*s1 && *s2) { X c1 = *s1; X c2 = *s2; X if(isalpha(c1)) { X if(isalpha(c2)) { X if(isupper(c1)) X c1 = tolower(c1); X if(isupper(c2)) X c2 = tolower(c2); X } else X return 1; X } else if(isalpha(c2)) X return -1; X if(c1 > c2) X return 1; X if(c1 < c2) X return -1; X s1++; X s2++; X } X if(*s1) X return 1; X if(*s2) X return -1; X return 0; X} //END echo x - PatMatch.c sed 's/^X//' > PatMatch.c << '//END' X/* PatMatch.c - Implements AmigaDos Regular Expression Pattern Matching. X** X** This program will test whether a string is an AmigaDos regular expression X** It may be used to implement wild expressions such as: X** X** "copy #?.c to <dir>" to copy any file ending in .c X** X** The program has two entry points: CmplPat, and Match. X** X** CmplPat - takes a pattern and returns an auxilliary integer vector X** which is used by Match. The pattern is not modified in X** any way. CmplPat returns 1 if no errors were detected X** while compiling the pattern; otherwise it returns 0; X** X** Match - takes the pattern, the auxilliary vector, and the string X** to be matched. It returns 1 if the string matches the X** pattern; otherwise it returns 0; X** X** Translated from BCPL by: X** Jeff Lydiatt X** Richmond B.C. Canada X** 16 May 1986. X** X** Source: "A Compact Function for Regular Expression Pattern Matching", X** Software - Practice and Experience, September 1979. X** X** Useage: X** To test if "file.c" matches the regular expression "#?.c" X** char *Pat = "#?.c"; X** char *Str = "file.c"; X** WORD Aux[128]; X** X** if ( CmplPat( Pat, Aux ) == 0 ) X** { X** printf("Bad Wildcard Expression\n"); X** exit(1); X** } X** if ( Match( Pat, Aux, Str ) == 1 ) X** printf("String matches the pattern\n"); X** else X** printf("String does NOT match the pattern\n"); X**/ X X/*--- Included files ----*/ X X#include <stdio.h> X#include <exec/types.h> X#include <ctype.h> X X#define EOS '\0' X X/*--- Global Variables ---*/ X Xstatic char Ch; /* The current character in Pattern */ Xstatic char *Pat; /* Pointer to the Pattern */ Xstatic int *Aux; /* Pointer to returned auxilliary vector */ Xstatic int PatP; /* Current position in Pat */ Xstatic int Patlen; /* strlen(pat) */ Xstatic BOOL Errflag; /* TRUE if error */ Xstatic int *Work; /* Pointer to Active work area */ Xstatic int Wp; /* Current position in work */ Xstatic BOOL Succflag;/* True if "str" matches "pat" */ X X/*----------------------------------------------------------------*/ X/* The Interpreter */ X/*----------------------------------------------------------------*/ X Xstatic void Put(N) Xint N; X{ X register int *ip; X register int *to; X X if ( N == 0 ) X Succflag = TRUE; X else X { X for ( ip = &Work[ 1 ], to = &Work[ Wp ]; ip <= to; ip++) X if ( *ip == N ) X return; X Work[ ++Wp ] = N; X } X} X Xint Match( Pat, Aux, Str ) Xchar Pat[]; Xint Aux[]; Xchar Str[]; X{ X int W[ 128 ]; X int S = 0; X int I, N, Q, P, Strlength; X char K; X int strlen(); X void Put(); X X Work = W; X Wp = 0; X Succflag = FALSE; X Strlength = strlen( Str ); X Put( 1 ); X X if ( Aux[ 0 ] != 0 ) X Put( Aux[ 0 ] ); X X for(;;) X { X /* First complete the closure */ X for( N=1; N <= Wp; N++ ) X { X P = Work[ N ]; X K = Pat[ P-1 ]; X Q = Aux[ P ]; X switch( K ) X { X case '#': Put( P + 1 ); X case '%': Put( Q ); X default : break; X case '(': X case '|': Put( P + 1); X if ( Q != 0 ) X Put( Q ); X } X } X X if ( S >= Strlength ) X return Succflag; X if ( Wp == 0 ) X return FALSE; X Ch = Str[ S++ ]; X X /* Now deal with the match items */ X X N = Wp; X Wp = 0; X Succflag = FALSE; X X for ( I = 1; I <= N; I++) X { X P = Work[ I ]; X K = Pat[ P - 1 ]; X switch( K ) X { X case '#': X case '|': X case '%': X case '(': break; X case '\'': K = Pat[ P ]; X default : if ( _toupper( Ch ) != _toupper( K ) ) X break; X case '?': /* Successful match */ X Put ( Aux[ P ] ); X } /* End Switch */ X } /* End For I */ X } /* End for(;;) */ X} X X X/*----------------------------------------------------------------*/ X/* The Compiler */ X/*----------------------------------------------------------------*/ X Xstatic void Rch() /* Read next character from Pat */ X{ X if ( PatP >= Patlen ) X Ch = EOS; X else X Ch = Pat[ PatP++ ]; X} X Xstatic void Nextitem() /* Get next char from Pat; recognize the ' escape char */ X{ X if ( Ch == '\'' ) X Rch(); X Rch(); X} X Xstatic void Setexits( List, Val ) Xint List; Xint Val; X{ X int A; X X do X { X A = Aux[ List ]; X Aux[ List ] = Val; X List = A; X } X while ( List != 0 ); X} X Xstatic int Join( A, B ) Xint A, B; X{ X int T = A; X X if ( A == 0 ) X return B; X while ( Aux[ A ] != 0 ) X A = Aux[ A ]; X Aux[ A ] = B; X return T; X} X Xstatic int Prim() /* Parse a Prim symbol */ X{ X int A = PatP; X char Op = Ch; X int Exp(); X void Setexits(), Nextitem(); X X Nextitem(); X switch( Op ) X { X case EOS: X case ')': X case '|': Errflag = TRUE; X default : return A; X case '#': Setexits( Prim(), A ); return A; X case '(': A = Exp( A ); X if ( Ch != ')' ) X { X Errflag = TRUE; X } X Nextitem(); X return A; X } X} X Xstatic int Exp( AltP ) /* Parse an expression */ Xint AltP; X{ X int Exits = 0; X int A; X int Prim(), Exits(), Join(); X void Nextitem(), Setexits(); X X for (;;) X { X A = Prim(); X if ( Ch == '|' || Ch == ')' || Ch == EOS ) X { X Exits = Join( Exits, A ); X if ( Ch != '|' ) X return Exits; X Aux[ AltP ] = PatP; X AltP = PatP; X Nextitem(); X } X else X Setexits( A, PatP ); X } X} X Xint CmplPat( Pattern, CmplPattern) Xchar Pattern[]; Xint CmplPattern[]; X{ X int i, strlen(); X void Rch(), Setexits(); X X Pat = Pattern; X Aux = CmplPattern; X PatP = 0; X Patlen = strlen( Pat ); X Errflag = FALSE; X X for ( i = 0; i <= Patlen; i++ ) X Aux[ i ] = 0; X Rch(); X Setexits( Exp(0), 0 ); X return (!Errflag); X} //END echo x - Makefile sed 's/^X//' > Makefile << '//END' XOFILES= pr.o instant.o PatMatch.o VolList.o menu.o XCFILES= pr.c instant.c PatMatch.c VolList.c menu.c shar.c catalog.c XTEXT= Makefile readme XOTHERS= $(TEXT) pr X X.SUFFIXES: .c .o X X.c.o: X @-ram:c/del $*.o X cc +P -S -B -DAMIGA $*.c X Xall: pr X Xpr: $(OFILES) X @-ram:c/del pr X ln -o pr $(OFILES) -lcl32 X Xinstant.arc: $(CFILES) $(OTHERS) X @-ram:c/del instant.arc X arc a instant $(CFILES) $(OTHERS) X Xcatalog: catalog.o PatMatch.o X @-ram:c/del catalog X ln -o catalog catalog.o PatMatch.o -lcl32 X Xcatalog.arc: catalog.c PatMatch.c catalog catalog.man Makefile X @-ram:c/del catalog.arc X arc a catalog catalog catalog.c PatMatch.c Makefile catalog.man X Xshar: shar.o X @-ram:c/del shar X ln -o shar shar.o -lcl32 X Xinstant.shar: shar $(CFILES) $(TEXT) X @-ram:c/del instant.shar X shar >instant.shar $(CFILES) $(TEXT) X Xcatalog.shar: shar catalog.c PatMatch.c catalog.man Makefile X @-ram:c/del catalog.shar X shar >catalog.shar catalog.man catalog.c PatMatch.c Makefile X Xprint: $(CFILES) $(TEXT) X pr $(CFILES) $(TEXT) //END : end of archive. exit 0 -- -- Peter da Silva `-_-' ...!hoptoad!academ!uhnix1!sugar!peter -- 'U` ^^^^^^^^^^^^^^ Not seismo!soma (blush)