home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / waffle / allfil62.zip / FORMATCH.C < prev    next >
C/C++ Source or Header  |  1992-12-25  |  8KB  |  268 lines

  1. /*
  2. **    formatch(), MS-DOS wildcard matching routine
  3. **
  4. **    Otto Makela, Jyvaskyla, Finland, 1992
  5. **    Distributed under the GNU General Public Licence:
  6. **    see file COPYING for details
  7. **
  8. **      Match the filename pattern given, and call user-supplied routine
  9. **    once for each match of a pattern with a pointer to the current 
  10. **    file_match packet as argument.  The routine can interrupt the match
  11. **    process by returning a nonzero value.
  12. **      Argument type governs the attributes of the file searched for,
  13. **    the low bits (masked by ALLREALONES) being the normal DOS file
  14. **    attributes, while the rest are used to control the match algorithm.
  15. **
  16. **    Specifically:
  17. **    READONLY,HIDDEN,SYSTEM,VOLABEL,DIRECTORY,ARCHIVE
  18. **        these are the normal DOS file attributes.  If VOLABEL is specified,
  19. **        only the specified disk volume label will be found.  If any of the
  20. **        bits READONLY, HIDDEN, SYSTEM, and DIRECTORY are specified, the
  21. **        match will find normal files and any files with these attributes
  22. **        set.  The ARCHIVE bit cannot be used for searching.
  23. **    MATCHNONWILD
  24. **        return non-wildcard match items as themselves, even if they do
  25. **        not exist
  26. **    DOTHIDDEN
  27. **        if set, filenames starting with a dot '.' (under MS-DOS only the
  28. **        directory pointer names) are considered hidden, and the HIDDEN
  29. **        bit must be on to retrieve any of these filenames, unless the
  30. **        name is explicitly given as a pattern
  31. **
  32. ** (these following three are as of yet not implemented... I'll get to that...)
  33. **
  34. **    RECURSIVE
  35. **        must have DIRECTORY set also; match recursively, returning the
  36. **        directory as the last member of itself; initial pattern must be
  37. **        nonwildcard
  38. **    DIRFIRST
  39. **        used with RECURSIVE; return the directory as the first member of
  40. **        itself as opposed to the default of last member
  41. **
  42. **    The trailing pattern "." is replaced with "*.*"; the patterns "x:"
  43. **    and anything with a trailing "/" get "*.*" appended to them
  44. **    automagically (this makes RECURSIVE matching behave more logically
  45. **    with all directories and makes for a nice shorthand notation).
  46. **
  47. **    Returns codes as value:
  48. **    >0  OK, number of times user routine was called
  49. **     0  no match
  50. **    -1  user routine returned nonzero
  51. */
  52.  
  53. #include    <time.h>
  54. #include    <ctype.h>
  55. #include    "formatch.h"
  56.  
  57. char switchar=0,dirsepar='/',othersepar='\\';
  58.  
  59. int formatch(char *pattern, unsigned int attribute,
  60.     int (*routine)(struct file_match *match))    {
  61.     register char *p,c;
  62.     char *q;
  63.     int count=0,wilds=0;
  64.     struct file_match match;
  65.     struct find_t dos_match;
  66.  
  67. #ifdef    DEBUG
  68.     printf("formatch(\"%s\",0x%04x)\n",pattern,attribute);
  69. #endif
  70.  
  71.     init_match();
  72.  
  73.     /*
  74.     **    Copy initial pattern to match.filename; set match.shortname
  75.     **    to point to just beyond last "/" or ":"
  76.     */
  77.     for(p=match.shortname=match.filename, q=pattern; c=*q++; *p++=c)
  78.         if(c==':' || c==dirsepar || c==othersepar)  {
  79.             if(c==othersepar) c=dirsepar;
  80.             match.shortname=p+1;
  81.         } else if(c=='*' || c=='?')
  82.             wilds++;
  83.         else if(isupper(c))
  84.             c=tolower(c);
  85.  
  86. #ifdef    DEBUG
  87.     printf("match.filename=0x%04x, match.shortname=0x%04x, p=0x%04x\n",
  88.         match.filename,match.shortname,p);
  89. #endif
  90.         /* Handle cases like "." and "/" */
  91.     if(p>match.filename && p==match.shortname+1 && p[-1]=='.')
  92.         p--;
  93.     if(match.shortname==p)    {
  94.         *p++='*';    *p++='.';    *p++='*';
  95.         wilds+=2;
  96.     }
  97.     *p='\0';
  98.  
  99.         /* If a dot is explicitly given, disable DOTHIDDEN */
  100.     if(*match.shortname=='.') attribute &= ~DOTHIDDEN;
  101.  
  102.     /*
  103.     **    Even if first match fails, we will force an exact match
  104.     **    if MATCHNONWILD is set (and there are no wildcards)
  105.     */
  106. #ifdef    DEBUG
  107.     printf("Initial \"%s\"\n",match.filename);
  108. #endif
  109.     if(_dos_findfirst(match.filename,attribute&ALLREALONES,&dos_match))
  110.         if(!wilds && attribute&MATCHNONWILD)    {
  111.             match.filetime=0L;
  112.             match.file_tm.tm_year=0;
  113.             match.file_tm.tm_mon=0;
  114.             match.file_tm.tm_mday=0;
  115.             match.file_tm.tm_hour=0;
  116.             match.file_tm.tm_min=0;
  117.             match.file_tm.tm_sec=0;
  118.             match.file_tm.tm_isdst=-1;
  119.             match.attribute=0;
  120.             match.filesize=0L;
  121.             if(routine(&match)) return(-1);
  122.             return 1;
  123.         } else
  124.             return 0;
  125.  
  126.     /*
  127.     **    Then repeat matching until we run out of matches or
  128.     **    user routine requests break 
  129.     */
  130.     do    {
  131.         match.file_tm.tm_year=dos_match.wr_date/512u+80;
  132.         match.file_tm.tm_mon=(dos_match.wr_date%512u)/32-1;
  133.         match.file_tm.tm_mday=dos_match.wr_date%32u;
  134.         match.file_tm.tm_hour=dos_match.wr_time/2048u;
  135.         match.file_tm.tm_min=(dos_match.wr_time%2048u)/32;
  136.         match.file_tm.tm_sec=(dos_match.wr_time%32u)*2;
  137.         match.file_tm.tm_isdst=-1;
  138.         match.filetime=mktime(&match.file_tm);
  139.  
  140.         match.attribute=dos_match.attrib;
  141.         match.filesize=dos_match.size;
  142.         match.extension=NULL;
  143.         for(p=match.shortname, q=dos_match.name; *p=*q; p++,q++)
  144.             if(isupper(*q))
  145.                 *p=tolower(*q);
  146.             else if(*p=='.')
  147.                 match.extension=p+1;
  148.         if(!match.extension) match.extension=p;
  149.         if((attribute&(DOTHIDDEN|HIDDEN))==DOTHIDDEN &&
  150.             *match.shortname=='.') continue;
  151.  
  152.         if(routine(&match)) return(-1);
  153.         count++;
  154.     } while(!_dos_findnext(&dos_match));
  155.  
  156. #if 0
  157. /* This horrible mess was used to implement DOTHIDDEN, RECURSIVE and DIRFIRST */
  158.  
  159. again:
  160.     for(code=SRCHFIR; DOS(code,0,ALLREALONES&type,path)!=-1; code=SRCHNXT)  {
  161.             /* Copy shortname to full filename */
  162.         for(p=match.shortname, q=restname; *q++=*p=tolower(*p); p++);
  163.             /* Recurse if a directory name, but not "." or ".." */
  164.         if(type&RECURSIVE && match.attribute&DIRECTORY &&
  165.             (*match.shortname!='.' || !wilds)) {
  166. #ifdef    DEBUG
  167.                 printf(    "type&RECURSIVE=%02x, match.attribute&"
  168.                     "DIRECTORY=%02x, *match.shortname=%c, "
  169.                     "!wilds=%d\n",type&RECURSIVE,match.attribute&
  170.                     DIRECTORY,*match.shortname,!wilds);
  171. #endif
  172.                 /* Call user routine before anything else if DIRFIRST */
  173.             if(type&DIRFIRST)
  174.                 if(routine(&match)) return(-1);
  175.                 else count++;
  176.                 /* Then add wildcard to filename and call us again */
  177.             q[-1]=dirsepar;
  178.             strcpy(q,wildcard);
  179.             if((i=formatch(match.filename,type,routine))==-1) return(-1);
  180.                 /* Have to redo this because our other incarnation messed it */
  181.             BDOS(SETDMA, &match);
  182.             count+=i;
  183.             q[-1]='\0';
  184.             if(type&DIRFIRST) continue;
  185.         }
  186.  
  187.     /*    Call user routine only if not recursing and not at a '.';
  188.     **    then return minus one if user routine breaks, else zero
  189.     */
  190.     if(!(type&RECURSIVE) || !(match.attribute&DIRECTORY) ||
  191.         (*match.shortname!='.') || !wilds)
  192.         if(routine(&match)) return(-1);
  193.         else count++;
  194.     }
  195. #endif
  196.  
  197.     /* Return number of times user routine called */
  198.     return(count);
  199. }
  200.  
  201.  
  202. #ifdef    MAIN
  203.  
  204. /*
  205. **    A test main program
  206. */
  207.  
  208. matched(struct file_match *match)    {
  209.     printf("%02x %6lu %2d/%02d/%02d %2d:%02d:%02d %-13s%-3s %s\n",
  210.         match->attribute,match->filesize,
  211.         match->file_tm.tm_mday,match->file_tm.tm_mon+1,
  212.         match->file_tm.tm_year,
  213.         match->file_tm.tm_hour,match->file_tm.tm_min,
  214.         match->file_tm.tm_sec,
  215.         match->shortname,match->extension,match->filename);
  216.     return 0;
  217. }
  218.  
  219. main(int argc,char *argv[])    {
  220.     char c;
  221.     int loop;
  222.     unsigned int attribute=READONLY|DIRECTORY;
  223.  
  224.     for(loop=1; loop<argc; loop++)
  225.         if(*argv[loop]=='-')
  226.             while(c=*++argv[loop])
  227.                 switch(c)    {
  228.                 case 'a':
  229.                     attribute^=ARCHIVE;
  230.                     continue;
  231.                 case 'D':
  232.                     attribute^=DOTHIDDEN;
  233.                     continue;
  234.                 case 'd':
  235.                     attribute^=DIRECTORY;
  236.                     continue;
  237.                 case 'F':
  238.                     attribute^=DIRFIRST;
  239.                     continue;
  240.                 case 'h':
  241.                     attribute^=HIDDEN;
  242.                     continue;
  243.                 case 'm':
  244.                     attribute^=MATCHNONWILD;
  245.                     continue;
  246.                 case 'R':
  247.                     attribute^=RECURSIVE;
  248.                     continue;
  249.                 case 'r':
  250.                     attribute^=READONLY;
  251.                     continue;
  252.                 case 's':
  253.                     attribute^=SYSTEM;
  254.                     continue;
  255.                 case 'v':
  256.                     attribute^=VOLABEL;
  257.                     continue;
  258.                 default:
  259.                     printf("warning: unrecognized '%c'\n",
  260.                         c);
  261.                     continue;
  262.                 }
  263.         else
  264.             printf("%s: %d\n",argv[loop],
  265.                 formatch(argv[loop],attribute,matched));
  266. }
  267. #endif
  268.