home *** CD-ROM | disk | FTP | other *** search
- /*
-
- FileFind Amiga Version 1.5
-
- FF will search all directories on a filing device for occurances of a
- particular file. Supports both AmigaDOS and MS-DOS wildcards
- and is PURE - can be made resident.
-
-
- History:
-
- Version 1.1: Now will support the MS-DOS wildcard characters: "*" and "?"
- Also: smaller code and a little quicker execution.
-
- Version 1.2: Uses AmigaDOS' Lock(), Examine() & ExNext() instead of
- Lattice's dfind() & dnext(). AmigaDOS' routines are
- much faster and can be used recursively so it is not
- neccesary to use the heap to make a list of directories.
- Lattice's stcpm() is used to compare filenames that are
- found to the user-supplied wildcard. If stcpm() says that
- a filename matches, then the name is displayed. This
- change increases the speed of this routine by an average
- of 55%!!! One additional modification allows the user to
- specify a directory to look in. This effectively defines
- a branch of the directory tree to search in, rather than
- always starting at the root and scanning all directories
- on the disk. 4-10-88 Finished.... 4-22-88
-
- Version 1.3: Added Ctrl-CDEF handling. Re-compiled to take advantage of
- Lattice Version 5.02 direct shared library calls - this
- eliminates the need to link in the amiga.lib stub routines
- thereby shortening the executable code size (as well as
- providing a tiny speed increase). Added ANSI-C prototyping
- function calls. Pruned the code a little more. Took advantage
- of Lattice 5.02 registerized parameters for some functions
- and register type auto variables within functions. Removed all
- global variables to allow for pure code (Resident-able). Compiled
- with stack checking turned off (-v) and "merge duplicate strings"
- on (-cs) for smaller code size. Added printing of path names
- that are being searched. Added support for quoted arguments
- which may contain spaces.
- Finished: 07-26-89
-
- Version 1.4: Replaced Lattice's slightly inappropriate pattern matching
- routines with one of my own. It supports the following wildcard
- characters:
- ? - matches one of any character.
- #x - matches one or more occurances of "x", which can be
- any valid character.
- * - matches any number of any characters.
- #? - (really an instance of "#x") works same as "*".
- My routine was written specifically for filename pattern matching
- which makes it more appropriate for use in this program. It is
- a little larger than Lattice's but it appears to be faster, and
- it behaves like a filename wildcard pattern matching routine
- is supposed to, unlike Lattice's which is really an all-purpose
- regular expression parser. For example, with Lattice's routine,
- if the user entered "FF foo", Lattice would actually match "foo*",
- which probably not what the user really wanted to see. My routine
- would literally match "foo" if that is what was entered, or "foo*"
- if that is what was entered.
- Finished: 08/12/89
-
- Version 1.5: Added the Quiet (-q) and the Verbose (-v) switches.
- Corrected potential problem in the SKIP_NON_WHITE() macro which
- did not look-out for the end of the string. Changed MAX_PATH_LEN
- to 257 to be consistant with AmigaDOS' path length limit of 256
- characters - no room here for artificial constraints!
- Finished: 10/23/89
-
-
- Copyright © 1988, 1989 Ray Lambert
-
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <dos.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <exec/memory.h>
- #include <proto/dos.h>
- #include <proto/exec.h>
-
- #define VERSION "1.5 (pure!)\n"
- #define MAX_PATH_LEN 257
-
- #define SKIP_WHITE(s) while(*(s)==' ') (s)++
- #define SKIP_NON_WHITE(s) while((*(s)!=' ')&&(*(s)!='\0')) (s)++
- #define CLREOL conwrite("K")
-
- UBYTE bequiet; /* this global data is ok with Lattice's cres.o residentable
- startup module */
-
- /****/
-
- char * __asm strsrch(register __a0 char *str, register __a1 char *sstr)
- {
- register char *a;
- register char *b;
- register char *z;
- int slen=strlen(str);
- int sslen=strlen(sstr);
- if (sslen>slen) return(NULL);
- z=(char *)(str+(slen-sslen+1));
- for(; str<=z; str++)
- {
- if (*str==*sstr)
- {
- a=str;
- b=sstr;
- do
- {
- a++;
- b++;
- }
- while( (*b) && (*b==*a) );
- if (!*b) return(str); /* end of search string reached - its a match! */
- }
- }
- return(NULL);
- }
-
- /****/
-
- int __asm wcmatch(register __a0 char *name, register __a1 char *pattern)
- {
- register char *wc;
- register char *ss;
- register char *a;
- register char *b;
- register char *temp;
- register int result=-1;
-
-
- /* So you say goto's are a no-no eh? Well let's see you code the
- following more efficiently... */
-
- temp=malloc(strlen(name)+1);
- if (!temp) goto wcabort1;
-
- wc=strdup(pattern);
- if (!wc) goto wcabort2;
- strupr(wc);
-
- ss=strdup(name);
- if (!ss) goto wcabort3;
- strupr(ss);
-
-
- /*
- I know the following is cheating a little but for the sake of simplicity
- I'm gonna do it anyway! Any occurance of "#?" in the pattern will be
- changed to "*". The two patterns do the same thing, and now we'll
- only have to parse for one of them.
- */
- do
- {
- a=strsrch(wc,"#?");
- if (a)
- {
- *a='*';
- a++;
- b=(a+1);
- while(*b)
- {
- *a=*b;
- a++;
- b++;
- }
- *a='\0';
- }
- }
- while(a);
-
-
- /* now to get down to work... */
- a=wc; /* "a" tracks the wildcard pattern */
- b=ss; /* "b" tracks the source string (filename?) */
- for(; result==-1; )
- {
-
- /* check for premature end of source string */
- if ( (*b=='\0') && (*a!='\0') )
- { /* if end of source string but only one char left in
- pattern and its a '*' then it is a match */
- if ( (*a=='*') || (*(a+1)=='\0') )
- {
- result=1; /* a match */
- }
- else
- {
- result=0; /* no match */
- }
- continue;
- }
-
- /* parse next wildcard character */
- switch(*a)
- {
- case '\0': /* end of pattern string */
- {
- if (*b=='\0')
- {
- result=1; /* exact match */
- continue;
- }
- result=0; /* no match */
- continue;
- }
- case '?':
- /* matches any character */
- {
- a++;
- b++;
- break;
- }
- case '#':
- /* matches any number of occurances of the following character */
- {
- a++;
- while( (*b) && (*b==*a) ) b++;
- a++;
- continue;
- }
- case '*':
- /* matches any number of occurances of any character(s) */
- {
- register char *c;
- a++;
-
- /* is "*" the last character in pattern? If so then match */
- if (!*a)
- {
- result=1; /* match */
- continue;
- }
-
- /* extract the sub-string existing after the "*" */
- c=temp;
- while(!strchr("?#*",*a))
- {
- *c=*a;
- c++;
- a++;
- }
- *c='\0';
- if (!*temp) /* no sub-string exists - ignore this wc char */
- {
- continue;
- }
-
- /* locate the extracted sub-string in the source string */
- c=strsrch(b,temp);
- if (!c)
- {
- result=0; /* no match */
- continue;
- }
-
- /* at this point we have:
- a: points to first char beyond sub-string following "*" in pattern
- b: points to chars to be matched to "*" (to be tossed)
- c: points to temp sub-string in search string (beyond b)
- we must: advance b beyond the substring pointed to by c
- */
- b=(char *)(c+strlen(temp));
-
- continue; /* and that's it! */
- }
- default: /* must match exactly! (another easy one...) */
- {
- if (*a!=*b)
- {
- result=0; /* no match */
- continue;
- }
- a++;
- b++;
- break;
- }
- }
- }
- free(ss);
- wcabort3:
- free(wc);
- wcabort2:
- free(temp);
- wcabort1:
- return(result);
- }
-
- /****/
-
- void __asm conwrite(register __a0 char *str)
- {
- Write(Output(),str,strlen(str));
- }
-
- /****/
-
- void __asm conwrite_int(register __d0 int num)
- {
- char str[10];
- register int i;
- register char *p=str;
-
- /* Find beginning divisor */
- for(i=10000; ( (i>num) && (i>1) ); i/=10);
-
- do
- {
- *p=(char)((num/i)+'0');
- num%=i;
- i/=10;
- p++;
- }
- while(i>=1);
- *p='\0';
- conwrite(str);
- }
-
- /****/
-
- int chk4brk(void)
- {
- if ( SetSignal(0L,0L) &
- ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
- SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
- ) return(1);
- return(0);
- }
-
- /****/
-
- void __asm report_searching( register __a0 char *root,
- register __d0 int level,
- register __a1 char *mask )
- {
- if (bequiet) return;
- CLREOL;
- conwrite("Searching: ");
- conwrite(root);
- if (level>0) conwrite("/");
- conwrite(mask);
- conwrite("\x0d"); /* move cursor to column 1 */
- }
-
- /****/
-
- int __asm dtree( register __a0 char *root,
- register __a1 char *mask,
- register __d0 int level )
- {
- char temp_str[MAX_PATH_LEN];
- register int cnt=0;
- register BPTR lock;
- register struct FileInfoBlock *info;
- register int brk=0;
- if ( (lock=Lock(root,ACCESS_READ))==NULL ) return(0);
- info=(struct FileInfoBlock *)
- AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR);
- /* AllocMem() is used to guarantee long-word alignment */
- if (!info)
- {
- UnLock(lock);
- conwrite("33;42m Memory is low! 0m\n");
- return(0);
- }
- if (!bequiet) report_searching(root,level,mask);
- if (!Examine(lock,info))
- {
- UnLock(lock);
- FreeMem(info,sizeof(struct FileInfoBlock));
- return(0);
- }
- while( (brk==0) && (ExNext(lock,info)!=0) )
- {
- if (brk=chk4brk()) continue;
- strcpy(temp_str,root);
- if (level>0) strcat(temp_str,"/");
- strcat(temp_str,info->fib_FileName);
- if (info->fib_DirEntryType>0)
- { /* it's a directory - scan it */
- register int result;
- level++;
- result=dtree(temp_str,mask,level);
- level--;
- if (result==-1)
- {
- brk=1;
- continue;
- }
- cnt+=result;
- }
- else
- { /* it is a normal file - compare it */
- strupr(info->fib_FileName);
- if (wcmatch(info->fib_FileName,mask))
- {
- if (!bequiet) CLREOL;
- conwrite("33mFound: ");
- conwrite(temp_str);
- conwrite("\n0m");
- if (!bequiet) report_searching(root,level,mask);
- cnt++;
- }
- }
- }
- UnLock(lock);
- FreeMem(info,sizeof(struct FileInfoBlock));
- return( (int)((brk!=0)?(-1):(cnt)) );
- }
-
- /****/
-
- void usage(void)
- {
- conwrite("\nUsage: FF [-q] [-v] [DRIVE:][PATH/]FILENAME [...]\n\n");
- conwrite(" [-q] = Quiet mode - supresses \"searching...\" messages\n");
- conwrite(" [-v] = Verbose mode - opposite of \"Quiet\" (default)\n");
- conwrite(" [DRIVE:] = Optional drive to scan\n");
- conwrite(" [PATH/] = Optional path to begin scan at\n");
- conwrite(" FILENAME = File to search for (wildcards allowed)\n");
- conwrite(" [...] = Optional multiple additional arguments\n\n");
- exit(5);
- }
-
- /****/
-
- char * __regargs strdcpy(char *to, char *from, char delimiter)
- {
- while( (*from!=delimiter) && (*from!='\0') )
- {
- *to=*from;
- to++;
- from++;
- }
- *to='\0';
- if (*from==delimiter) from++;
- return(from);
- }
-
- /****/
-
- void _main(char *args)
- {
- register char *ptr;
- register int match_cnt;
- char
- drive[MAX_PATH_LEN],
- file_mask[MAX_PATH_LEN];
- conwrite("\n33;40mFileFind Amiga! Version ");
- conwrite(VERSION);
- conwrite("0mCopyright © 1988, 1989 by Ray Lambert\n");
-
- bequiet = 0; /* initialize to Verbose mode */
-
- /* Change terminating newline to a NULL */
- ptr=(char *)(args+strlen(args)-1);
- if (*ptr=='\n') *ptr='\0';
-
- /* Skip over command "FF " */
- SKIP_WHITE(args);
- SKIP_NON_WHITE(args);
-
- /* check for no args */
- SKIP_WHITE(args);
- if (!*args) usage();
-
- conwrite("(Ctrl-C to abort)\n\n");
-
- /* process all args */
- do
- {
-
- /* get next arg */
- if (*args=='-') /* a switch */
- {
- args++;
- switch(toupper(*args))
- {
- case 'Q': /* quiet switch */
- {
- bequiet = 1;
- conwrite("32;40m(Quiet mode enabled)0m\n");
- break;
- }
- case 'V': /* verbose switch */
- {
- bequiet = 0;
- conwrite("32;40m(Verbose mode enabled)0m\n");
- break;
- }
- }
- SKIP_NON_WHITE(args);
- SKIP_WHITE(args);
- continue;
- }
-
- if (*args=='\"') /* quoted argument */
- { /* copy till closing quote or null */
- args=strdcpy(drive,(++args),'\"');
- }
- else /* normal argument */
- { /* copy till space or null */
- args=strdcpy(drive,args,' ');
- }
-
- /* Skip over leading spaces for next pass */
- SKIP_WHITE(args);
-
- /* Check for user drive spec */
- ptr=strchr(drive,':');
- if (ptr) /* Drive was supplied by user */
- {
- /* Get pointer to last xter (actually to null) */
- while(*ptr!='\0') ptr++;
- /* Find beginning of file mask */
- while( (*ptr!='/') && (*ptr!=':') ) ptr--;
- /* copy file mask to "file_mask" variable */
- strcpy(file_mask,(ptr+1));
- /* truncate file mask from "drive" variable */
- *(ptr+1)='\0';
- /* don't forget to trunc the "/" */
- if (*ptr=='/') *ptr='\0';
- }
- else /* Get drive from system */
- {
- strcpy(file_mask,drive);
- if (getcd(0,drive)!=0) exit(50); /* die silently */
- /* Cut path off - we only want the volume name */
- ptr=strchr(drive,':');
- if (ptr) *(++ptr)='\0';
- }
-
- /* be a little user friendly */
- conwrite("\nSearching for file \"");
- conwrite(file_mask);
- conwrite("\" on drive \"");
- conwrite(drive);
- conwrite("\"\n\n");
-
- /* actually do the search */
- ptr=strchr(drive,':');
- match_cnt=dtree(drive,file_mask, ( (*(++ptr)!='\0') ? (1) : (0) ) );
-
- /* clear the last searching message */
- if (!bequiet) CLREOL;
-
- /* process the result */
- switch(match_cnt)
- {
- case -1: /* a ctrl-? break occured */
- {
- conwrite("**break\n\n");
- exit(0);
- }
- case 0:
- {
- conwrite("No matches found.\n\n");
- break;
- }
- default:
- {
- conwrite("\nFound ");
- conwrite_int(match_cnt);
- conwrite(" match");
- conwrite( ( (match_cnt==1) ? (".\n\n") : ("es.\n\n") ) );
- break;
- }
- }
- }
- while(*args!='\0');
- }
-
-