home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / WILDMAT.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  6KB  |  188 lines

  1. /*
  2.  * @(#)wildmat.c 1.3 87/11/06   Public Domain.
  3.  *
  4. From: rs@mirror.TMC.COM (Rich Salz)
  5. Newsgroups: net.sources
  6. Subject: Small shell-style pattern matcher
  7. Message-ID: <596@mirror.TMC.COM>
  8. Date: 27 Nov 86 00:06:40 GMT
  9.   
  10. There have been several regular-expression subroutines and one or two
  11. filename-globbing routines in mod.sources.  They handle lots of
  12. complicated patterns.  This small piece of code handles the *?[]\
  13. wildcard characters the way the standard Unix(tm) shells do, with the
  14. addition that "[^.....]" is an inverse character class -- it matches
  15. any character not in the range ".....".  Read the comments for more
  16. info.
  17.   
  18. For my application, I had first ripped off a copy of the "glob" routine
  19. from within the find(1) source, but that code is bad news:  it recurses
  20. on every character in the pattern.  I'm putting this replacement in the
  21. public domain.  It's small, tight, and iterative.  Compile with -DTEST
  22. to get a test driver.  After you're convinced it works, install in
  23. whatever way is appropriate for you.
  24.   
  25. I would like to hear of bugs, but am not interested in additions; if I
  26. were, I'd use the code I mentioned above.
  27. */
  28. /*
  29. **  Do shell-style pattern matching for ?, \, [], and * characters.
  30. **  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  31. **  could cause a segmentation violation.
  32. **
  33. **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  34. */
  35.   
  36. /*
  37.  * Modified 6Nov87 by John Gilmore (hoptoad!gnu) to return a "match"
  38.  * if the pattern is immediately followed by a "/", as well as \0.
  39.  * This matches what "tar" does for matching whole subdirectories.
  40.  *
  41.  * The "*" code could be sped up by only recursing one level instead
  42.  * of two for each trial pattern, perhaps, and not recursing at all
  43.  * if a literal match of the next 2 chars would fail.
  44.  */
  45.   
  46. /* Modified by Anders Klemets to take an array of pointers as an optional
  47.    argument. Each part of the string that matches '*' is returned as a
  48.    null-terminated, malloced string in this array.
  49.  */
  50. #include <ctype.h>
  51. #include "global.h"
  52.   
  53.   
  54. static int Star __ARGS((char *s,char *p,char **argv,int single));
  55. static int haveDot __ARGS((register char *c,register int len));
  56.   
  57. static int
  58. haveDot(s,len)
  59. register char *s;
  60. register int len;
  61. {
  62.     while (len-- > 0)
  63.         if (*s++ == '.')
  64.             return TRUE;
  65.     return FALSE;
  66. }
  67.   
  68. static int
  69. Star(s,p,argv,single)
  70. register char *s;
  71. register char *p;
  72. register char **argv;
  73. int single;
  74. {
  75.     char *cp = s;
  76.     while (wildmat(cp, p, argv) == FALSE)
  77.         if(*++cp == '\0')
  78.             return -1;
  79.     if ((single == TRUE) && haveDot(s, (int)(cp - s)))
  80.         return -1;
  81.     return (int)(cp - s);
  82. }
  83.   
  84. int
  85. wildmat(s,p,argv)
  86. register char *s;
  87. register char *p;
  88. register char **argv;
  89. {
  90.     register int last;
  91.     register int matched;
  92.     register int reverse;
  93.     register int cnt;
  94.     int single;
  95.   
  96.     for(; *p; s++,p++){
  97.         switch(*p){
  98.             case '\\':
  99.             /* Literal match with following character; fall through. */
  100.                 p++;
  101.             default:
  102.              /*   if(*s != *p)   */
  103.                 if (tolower(*s) != tolower(*p))
  104.                     return FALSE;
  105.                 continue;
  106.             case '?':
  107.             /* Match anything. */
  108.                 if(*s == '\0')
  109.                     return FALSE;
  110.                 continue;
  111.             case '*':
  112.             case '+':
  113.                 single = (*p == '+');
  114.   
  115.             /* Trailing star matches everything. */
  116.                 if(argv == NULLCHARP)
  117.                     return *++p ? 1 + Star(s, p, NULLCHARP, single) : TRUE;
  118.                 if(*++p == '\0'){
  119.                     cnt = strlen(s);
  120.                     if ((single == TRUE) && haveDot(s, cnt))
  121.                         return FALSE;
  122.                 } else {
  123.                     if((cnt = Star(s, p, argv+1, single)) == -1)
  124.                         return FALSE;
  125.                 }
  126.                 *argv = mallocw(cnt+1);
  127.                 strncpy(*argv,s,cnt);
  128.                 *(*argv + cnt) = '\0';
  129.                 return TRUE;
  130.             case '[':
  131.             /* [^....] means inverse character class. */
  132.                 reverse = (p[1] == '^' || p[1] == '!') ? TRUE : FALSE;
  133.                 if(reverse)
  134.                     p++;
  135.                 for(last = 0400, matched = FALSE; *++p && *p != ']'; last = *p){
  136.                 /* This next line requires a good C compiler. */
  137.                     if(*p == '-' ? *s <= *++p && *s >= last : *s == *p)
  138.                         matched = TRUE;
  139.                 }
  140.                 if(matched == reverse)
  141.                     return FALSE;
  142.                 continue;
  143.         }
  144.     }
  145.     /* For "tar" use, matches that end at a slash also work. --hoptoad!gnu */
  146.     return *s == '\0' || *s == '/';
  147. }
  148.   
  149.   
  150. #ifdef  TEST
  151. #include <stdio.h>
  152.   
  153. extern char *gets();
  154.   
  155. main()
  156. {
  157.     char pattern[80];
  158.     char text[80];
  159.     char *argv[80], *cp;
  160.     int cnt;
  161.   
  162.     while (TRUE){
  163.         printf("Enter pattern:  ");
  164.         if(gets(pattern) == NULL)
  165.             break;
  166.         while (TRUE){
  167. #ifdef LINUX
  168.             memset(argv, 0, 80 * sizeof (char *));
  169. #else
  170.             bzero(argv,80*sizeof(char *));
  171. #endif
  172.             printf("Enter text:  ");
  173.             if(gets(text) == NULL)
  174.                 exit(0);
  175.             if(text[0] == '\0')
  176.                 /* Blank line; go back and get a new pattern. */
  177.                 break;
  178.             printf("      %d\n", wildmat(text, pattern, argv));
  179.             for(cnt = 0; argv[cnt] != NULLCHAR; ++cnt){
  180.                 printf("String %d is: '%s'\n",cnt,argv[cnt]);
  181.                 free(argv[cnt]);
  182.             }
  183.         }
  184.     }
  185.     exit(0);
  186. }
  187. #endif  /* TEST */
  188.