home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast2.iso
/
waffle
/
allfil62.zip
/
FORMATCH.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-25
|
8KB
|
268 lines
/*
** formatch(), MS-DOS wildcard matching routine
**
** Otto Makela, Jyvaskyla, Finland, 1992
** Distributed under the GNU General Public Licence:
** see file COPYING for details
**
** Match the filename 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.
** MATCHNONWILD
** return non-wildcard match items as themselves, even if they do
** not exist
** DOTHIDDEN
** if set, filenames starting with a dot '.' (under MS-DOS only the
** directory pointer names) are considered hidden, and the HIDDEN
** bit must be on to retrieve any of these filenames, unless the
** name is explicitly given as a pattern
**
** (these following three are as of yet not implemented... I'll get to that...)
**
** 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
**
** The trailing pattern "." is replaced with "*.*"; the patterns "x:"
** and anything with a trailing "/" get "*.*" appended to them
** automagically (this makes RECURSIVE matching behave more logically
** with all directories and makes for a nice shorthand notation).
**
** Returns codes as value:
** >0 OK, number of times user routine was called
** 0 no match
** -1 user routine returned nonzero
*/
#include <time.h>
#include <ctype.h>
#include "formatch.h"
char switchar=0,dirsepar='/',othersepar='\\';
int formatch(char *pattern, unsigned int attribute,
int (*routine)(struct file_match *match)) {
register char *p,c;
char *q;
int count=0,wilds=0;
struct file_match match;
struct find_t dos_match;
#ifdef DEBUG
printf("formatch(\"%s\",0x%04x)\n",pattern,attribute);
#endif
init_match();
/*
** Copy initial pattern to match.filename; set match.shortname
** to point to just beyond last "/" or ":"
*/
for(p=match.shortname=match.filename, q=pattern; c=*q++; *p++=c)
if(c==':' || c==dirsepar || c==othersepar) {
if(c==othersepar) c=dirsepar;
match.shortname=p+1;
} else if(c=='*' || c=='?')
wilds++;
else if(isupper(c))
c=tolower(c);
#ifdef DEBUG
printf("match.filename=0x%04x, match.shortname=0x%04x, p=0x%04x\n",
match.filename,match.shortname,p);
#endif
/* Handle cases like "." and "/" */
if(p>match.filename && p==match.shortname+1 && p[-1]=='.')
p--;
if(match.shortname==p) {
*p++='*'; *p++='.'; *p++='*';
wilds+=2;
}
*p='\0';
/* If a dot is explicitly given, disable DOTHIDDEN */
if(*match.shortname=='.') attribute &= ~DOTHIDDEN;
/*
** Even if first match fails, we will force an exact match
** if MATCHNONWILD is set (and there are no wildcards)
*/
#ifdef DEBUG
printf("Initial \"%s\"\n",match.filename);
#endif
if(_dos_findfirst(match.filename,attribute&ALLREALONES,&dos_match))
if(!wilds && attribute&MATCHNONWILD) {
match.filetime=0L;
match.file_tm.tm_year=0;
match.file_tm.tm_mon=0;
match.file_tm.tm_mday=0;
match.file_tm.tm_hour=0;
match.file_tm.tm_min=0;
match.file_tm.tm_sec=0;
match.file_tm.tm_isdst=-1;
match.attribute=0;
match.filesize=0L;
if(routine(&match)) return(-1);
return 1;
} else
return 0;
/*
** Then repeat matching until we run out of matches or
** user routine requests break
*/
do {
match.file_tm.tm_year=dos_match.wr_date/512u+80;
match.file_tm.tm_mon=(dos_match.wr_date%512u)/32-1;
match.file_tm.tm_mday=dos_match.wr_date%32u;
match.file_tm.tm_hour=dos_match.wr_time/2048u;
match.file_tm.tm_min=(dos_match.wr_time%2048u)/32;
match.file_tm.tm_sec=(dos_match.wr_time%32u)*2;
match.file_tm.tm_isdst=-1;
match.filetime=mktime(&match.file_tm);
match.attribute=dos_match.attrib;
match.filesize=dos_match.size;
match.extension=NULL;
for(p=match.shortname, q=dos_match.name; *p=*q; p++,q++)
if(isupper(*q))
*p=tolower(*q);
else if(*p=='.')
match.extension=p+1;
if(!match.extension) match.extension=p;
if((attribute&(DOTHIDDEN|HIDDEN))==DOTHIDDEN &&
*match.shortname=='.') continue;
if(routine(&match)) return(-1);
count++;
} while(!_dos_findnext(&dos_match));
#if 0
/* This horrible mess was used to implement DOTHIDDEN, RECURSIVE and DIRFIRST */
again:
for(code=SRCHFIR; DOS(code,0,ALLREALONES&type,path)!=-1; code=SRCHNXT) {
/* Copy shortname to full filename */
for(p=match.shortname, q=restname; *q++=*p=tolower(*p); p++);
/* Recurse if a directory name, but not "." or ".." */
if(type&RECURSIVE && match.attribute&DIRECTORY &&
(*match.shortname!='.' || !wilds)) {
#ifdef DEBUG
printf( "type&RECURSIVE=%02x, match.attribute&"
"DIRECTORY=%02x, *match.shortname=%c, "
"!wilds=%d\n",type&RECURSIVE,match.attribute&
DIRECTORY,*match.shortname,!wilds);
#endif
/* Call user routine before anything else if DIRFIRST */
if(type&DIRFIRST)
if(routine(&match)) return(-1);
else count++;
/* Then add wildcard to filename and call us again */
q[-1]=dirsepar;
strcpy(q,wildcard);
if((i=formatch(match.filename,type,routine))==-1) return(-1);
/* Have to redo this because our other incarnation messed it */
BDOS(SETDMA, &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) || !(match.attribute&DIRECTORY) ||
(*match.shortname!='.') || !wilds)
if(routine(&match)) return(-1);
else count++;
}
#endif
/* Return number of times user routine called */
return(count);
}
#ifdef MAIN
/*
** A test main program
*/
matched(struct file_match *match) {
printf("%02x %6lu %2d/%02d/%02d %2d:%02d:%02d %-13s%-3s %s\n",
match->attribute,match->filesize,
match->file_tm.tm_mday,match->file_tm.tm_mon+1,
match->file_tm.tm_year,
match->file_tm.tm_hour,match->file_tm.tm_min,
match->file_tm.tm_sec,
match->shortname,match->extension,match->filename);
return 0;
}
main(int argc,char *argv[]) {
char c;
int loop;
unsigned int attribute=READONLY|DIRECTORY;
for(loop=1; loop<argc; loop++)
if(*argv[loop]=='-')
while(c=*++argv[loop])
switch(c) {
case 'a':
attribute^=ARCHIVE;
continue;
case 'D':
attribute^=DOTHIDDEN;
continue;
case 'd':
attribute^=DIRECTORY;
continue;
case 'F':
attribute^=DIRFIRST;
continue;
case 'h':
attribute^=HIDDEN;
continue;
case 'm':
attribute^=MATCHNONWILD;
continue;
case 'R':
attribute^=RECURSIVE;
continue;
case 'r':
attribute^=READONLY;
continue;
case 's':
attribute^=SYSTEM;
continue;
case 'v':
attribute^=VOLABEL;
continue;
default:
printf("warning: unrecognized '%c'\n",
c);
continue;
}
else
printf("%s: %d\n",argv[loop],
formatch(argv[loop],attribute,matched));
}
#endif