home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / WILDMAT.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  5KB  |  166 lines

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