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)