home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Match the directory pattern given, and call user-supplied routine
- ** once for each match of a pattern with a pointer to the current
- ** FILE_MATCH packet as argument. The routine can interrupt the match
- ** process by returning a nonzero value.
- ** Argument type governs the attributes of the file searched for,
- ** the low bits (masked by ALLREALONES) being the normal DOS file
- ** attributes, while the rest are used to control the match algorithm.
- ** Specifically:
- ** READONLY,HIDDEN,SYSTEM,VOLABEL,DIRECTORY,ARCHIVE
- ** these are the normal DOS file attributes. If VOLABEL is specified,
- ** only the specified disk volume label will be found. If any of the
- ** bits READONLY, HIDDEN, SYSTEM, and DIRECTORY are specified, the
- ** match will find normal files and any files with these attributes
- ** set. The ARCHIVE bit cannot be used for searching.
- ** DOTHIDDEN
- ** if set, filenames starting with a dot '.' are considered hidden,
- ** and the HIDDEN bit must be on to retrieve any of these filenames,
- ** except if the name is given as a pattern
- ** MATCHNONWILD
- ** return non-wildcard match items as themselves, even if they do
- ** not exist
- ** RECURSIVE
- ** must have DIRECTORY set also; match recursively, returning the
- ** directory as the last member of itself; initial pattern must be
- ** nonwildcard
- ** DIRFIRST
- ** used with RECURSIVE; return the directory as the first member of
- ** itself as opposed to the default of last member
- ** When any of "x:", "x:/" and "/" are given as patterns, a "*.*" is
- ** appended to them automagically (this makes RECURSIVE matching behave
- ** more logically with all directories).
- **
- ** Returns codes as value:
- ** >0 OK, number of times user routine was called
- ** 0 no match
- ** -1 user routine returned nonzero
- **
- ** (c) 1988 by Otto Makela, Jyvaskyla, Finland
- */
- #include <model.h>
- #include <ctype.h>
- #include "formatch.h"
-
- #define SETDMA 0x1a
- #define SRCHFIR 0x4e
- #define SRCHNXT 0x4f
-
- #ifdef _LARGEDATA
- #define BDOS bdosx
- #define DOS dosx
- #else
- #define BDOS bdos
- #define DOS dos
- #endif
-
- char *getenv();
- char optsepar[2]="/",dirsepar='\\',othersepar='/';
-
- int formatch(path,type,routine)
- char *path;
- int type;
- int (*routine)(); {
- int i,code,count=0,wilds=0;
- register char *p,c;
- char *q,*restname;
- char *wildcard="*.*";
- FILE_MATCH file_match;
-
- #ifdef DEBUG
- printf("formatch(\"%s\",0x%x)\n",path,type);
- #endif
-
- BDOS(SETDMA, &file_match);
-
- /* Copy initial pattern up to last '/' to match.filename;
- set restname to last wildcard tail */
- for(p=file_match.filename, restname=p, q=path; c=*q; *q++=c) {
- if(c==':' || c==dirsepar || c==othersepar) {
- if(c!=':') c=dirsepar;
- restname=p+1;
- } else if(c=='*' || c=='?')
- wilds++;
- if(isupper(c))
- *p++=c=tolower(c);
- else
- *p++=c;
- }
-
- /* Non-wildcard matches: add "*.*" */
- if(!wilds) {
- p=path;
- if(isalpha(p[0]) && p[1]==':') p+=2;
- if(p[0]=='.') {
- if(!p[1] || (p[1]=='.' && !p[2])) {
- if(p[1]) {
- p+=2;
- *p++=dirsepar;
- }
- *p='\0';
- }
- } else if(p[0]==dirsepar && !p[1])
- p++;
-
- if(!*p) {
- strcpy(file_match.filename,path);
- restname=file_match.filename+(p-path);
- strcpy(p,wildcard);
- wilds=2;
- }
- }
-
- /* Then repeat until we run out of matches or user routine breaks */
- again:
- for(code=SRCHFIR; DOS(code,0,ALLREALONES&type,path)!=-1; code=SRCHNXT) {
- /* Proceed to next one, if starts with dot and DOTHIDDEN */
- if((type&(DOTHIDDEN|HIDDEN))==DOTHIDDEN &&
- *file_match.shortname=='.' && *restname!='.') continue;
- /* Copy shortname to full filename */
- for(p=file_match.shortname, q=restname; *q++=*p=tolower(*p); p++);
- /* Recurse if a directory name, but not "." or ".." */
- if(type&RECURSIVE && file_match.attribute&DIRECTORY &&
- (*file_match.shortname!='.' || !wilds)) {
- #ifdef DEBUG
- printf( "type&RECURSIVE=%02x, file_match.attribute&"
- "DIRECTORY=%02x, *file_match.shortname=%c, "
- "!wilds=%d\n",type&RECURSIVE,file_match.attribute&
- DIRECTORY,*file_match.shortname,!wilds);
- #endif
- /* Call user routine before anything else if DIRFIRST */
- if(type&DIRFIRST)
- if(routine(&file_match)) return(-1);
- else count++;
- /* Then add wildcard to filename and call us again */
- q[-1]=dirsepar;
- strcpy(q,wildcard);
- if((i=formatch(file_match.filename,type,routine))==-1) return(-1);
- /* Have to redo this because our other incarnation messed it */
- BDOS(SETDMA, &file_match);
- count+=i;
- q[-1]='\0';
- if(type&DIRFIRST) continue;
- }
-
- /* Call user routine only if not recursing and not at a '.';
- ** then return minus one if user routine breaks, else zero
- */
- if(!(type&RECURSIVE) || !(file_match.attribute&DIRECTORY) ||
- (*file_match.shortname!='.') || !wilds)
- if(routine(&file_match)) return(-1);
- else count++;
- }
-
- /* If no wildcards, just test the filename */
- if(!wilds && !count && type&MATCHNONWILD) {
- for(p=file_match.shortname, q=restname; *p++=*q++;);
- file_match.attribute=0;
- file_match.filetime=0L;
- file_match.filesize=0L;
- if(routine(&file_match)) return(-1);
- else count++;
- }
-
- /* Return number of times user routine called */
- return(count);
- }
-
- /*
- ** The first time 'round, get option and file separators
- */
- void initmatch() {
- register char *p;
-
- if( (*optsepar = (p=getenv("SWITCHAR"))?*p:switchar(0)) == '/')
- dirsepar='\\', othersepar='/';
- else
- dirsepar='/', othersepar='\\';
- }