text: /* $LastChangedRevision$
   **
   ** Do shell-style pattern matching for ?, \, [], and * characters.
   ** Might not be robust in face of malformed patterns; e.g., "foo[a-"
   ** could cause a segmentation violation. It is 8bit clean.
   **
   ** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
   ** Rich $alz is now <rsalz@osf.org>.
   ** April, 1991: Replaced mutually-recursive calls with in-line code
   ** for the star character.
   **
   ** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
   ** This can greatly speed up failing wildcard patterns. For example:
   ** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
   ** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
   ** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
   ** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without
   ** the ABORT code, it takes 22310 calls to fail. Ugh. The following
   ** explanation is from Lars:
   ** The precondition that must be fulfilled is that DoMatch will consume
   ** at least one character in text. This is true if *p is neither '*' nor
   ** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic
   ** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx".  With
   ** FALSE, each star-loop has to run to the end of the text; with ABORT
   ** only the last one does.
   **
   ** Once the control of one instance of DoMatch enters the star-loop, that
   ** instance will return either TRUE or ABORT, and any calling instance
   ** will therefore return immediately after (without calling recursively
   ** again). In effect, only one star-loop is ever active. It would be
   ** possible to modify the code to maintain this context explicitly,
   ** eliminating all recursive calls at the cost of some complication and
   ** loss of clarity (and the ABORT stuff seems to be unclear enough by
   ** itself). I think it would be unwise to try to get this into a
   ** released version unless you have a good test data base to try it
   ** out on.
   */
  
  #include "cs_config.h"
  
  #include <ctype.h>
  #include "neo_misc.h"
  
  #define ABORT -1
  
  
   /* What character marks an inverted character class? */
  #define NEGATE_CLASS '^'
   /* Is "*" a common pattern? */
  #define OPTIMIZE_JUST_STAR
   /* Do tar(1) matching rules, which ignore a trailing slash? */
  #undef MATCH_TAR_PATTERN
  
  
  /*
   ** Match text and p, return TRUE, FALSE, or ABORT.
   */
    static int 
  DoMatch(register const char *text, register const char *p)
  {
    register int last;
    register int matched;
    register int reverse;
  
    for ( ; *p; text++, p++) {
      if (*text == '\0' && *p != '*')
        return ABORT;
      switch (*p) {
        case '\\':
  	/* Literal match with following character. */
  	p++;
  	/* FALLTHROUGH */
        default:
  	if (*text != *p)
  	  return FALSE;
  	continue;
        case '?':
  	/* Match anything. */
  	continue;
        case '*':
  	while (*++p == '*')
  	  /* Consecutive stars act just like one. */
  	  continue;
  	if (*p == '\0')
  	  /* Trailing star matches everything. */
  	  return TRUE;
  	while (*text)
  	  if ((matched = DoMatch(text++, p)) != FALSE)
  	    return matched;
  	return ABORT;
        case '[':
  	reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
  	if (reverse)
  	  /* Inverted character class. */
  	  p++;
  	matched = FALSE;
  	if (p[1] == ']' || p[1] == '-')
  	  if (*++p == *text)
  	    matched = TRUE;
  	for (last = *p; *++p && *p != ']'; last = *p)
  	  /* This next line requires a good C compiler. */
  	  if (*p == '-' && p[1] != ']'
  	      ? *text <= *++p && *text >= last : *text == *p)
  	    matched = TRUE;
  	if (matched == reverse)
  	  return FALSE;
  	continue;
      }
    }
  
  #ifdef MATCH_TAR_PATTERN
    if (*text == '/')
      return TRUE;
  #endif /* MATCH_TAR_ATTERN */
    return *text == '\0';
  }
  
  
  /*
   ** Match text and p, return TRUE, FALSE, or ABORT.
   */
  static int
  DoMatchCaseInsensitive(register const char *text, register const char *p)
  {
    register int last;
    register int matched;
    register int reverse;
  
    for ( ; *p; text++, p++) {
      if (*text == '\0' && *p != '*')
        return ABORT;
      switch (*p) {
        case '\\':
  	/* Literal match with following character. */
  	p++;
  	/* FALLTHROUGH */
        default:
  	if (toupper(*text) != toupper(*p))
  	  return FALSE;
  	continue;
        case '?':
  	/* Match anything. */
  	continue;
        case '*':
  	while (*++p == '*')
  	  /* Consecutive stars act just like one. */
  	  continue;
  	if (*p == '\0')
  	  /* Trailing star matches everything. */
  	  return TRUE;
  	while (*text)
  	  if ((matched = DoMatchCaseInsensitive(text++, p)) != FALSE)
  	    return matched;
  	return ABORT;
        case '[':
  	reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
  	if (reverse)
  	  /* Inverted character class. */
  	  p++;
  	matched = FALSE;
  	if (p[1] == ']' || p[1] == '-')
  	  if (toupper(*++p) == toupper(*text))
  	    matched = TRUE;
  	for (last = toupper(*p); *++p && *p != ']'; last = toupper(*p))
  	  /* This next line requires a good C compiler. */
  	  if (*p == '-' && p[1] != ']'
  	      ? toupper(*text) <= toupper(*++p) && toupper(*text) >= last : toupper(*text) == toupper(*p))
  	    matched = TRUE;
  	if (matched == reverse)
  	  return FALSE;
  	continue;
      }
    }
  
  #ifdef MATCH_TAR_PATTERN
    if (*text == '/')
      return TRUE;
  #endif /* MATCH_TAR_ATTERN */
    return *text == '\0';
  }
  
  
  /*
   ** User-level routine. Returns TRUE or FALSE.
   */
  int
  wildmat(const char *text, const char *p)
  {
  #ifdef OPTIMIZE_JUST_STAR
    if (p[0] == '*' && p[1] == '\0')
      return TRUE;
  #endif /* OPTIMIZE_JUST_STAR */
    return DoMatch(text, p) == TRUE;
  }
  
  /*
   ** User-level routine. Returns TRUE or FALSE.
   */
  int
  wildmatcase(const char *text, const char *p)
  {
  #ifdef OPTIMIZE_JUST_STAR
    if (p[0] == '*' && p[1] == '\0')
      return TRUE;
  #endif /* OPTIMIZE_JUST_STAR */
    return DoMatchCaseInsensitive(text, p) == TRUE;
  }
  