/*
**
**  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.
**  Special thanks to Lars Mathiesen 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-p-70-iso8859-1
**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
**  the ABORT, then it takes 22310 calls to fail.  Ugh.
**
**  bernie    613-01 91/01/04 19:34
**  Fixed problem with terminating * not matching with (null)
**
**  bernie    597-00 91/01/08 11:24
**  Fixed shell glob negate from '^' to '!'
**
**  bernie    597-02 91/01/21 13:43
**	Fixed . matching * or ? on first char.
**
**  jseymour  91/02/05 22:56
**	Fixed problems with ill-formed sets in pattern yielding false
**	matches.  Should now be robust in such cases (not all possibilities
**	tested - standard disclaimer).  Added stand-alone debug code.
**
**  jseymour  91/03/28 20:50
**	Re-fixed problems with ill-formed sets in pattern yielding false
**	matches - one hopes correctly this time.
**
**  jseymour  1998/04/04 17:45 EST
**	Before adding this to minicom (as part of my "getsdir()" addition),
**	I emailed a request to Rich $alz, asking if I could "GPL" it.  Here
**	is his reply:
**
**	    Date: Mon, 30 Mar 1998 10:50:06 -0500 (EST)
**	    Message-Id: <199803301550.KAA14018@<anonymized>.com>
**	    From: Rich Salz <salzr@<anonymized>.com>
**	    To: jseymour@jimsun.LinxNet.com
**	    Subject: Re: A Little Thing Named "Wildmat"
**
**	    Wildmat is in the public domain -- enjoy it.
**
**	    I would rather it not get encumbered with various licenses,
**	    but since it is in the public domain you can do what you want...
**
**	So there you go.  (I anonymized his email address as I don't know
**	that he was particularly interested in having it "advertised".)
*/
#include <config.h>

#include "minicom.h"

#ifndef TRUE
#define TRUE	 1
#endif
#ifndef FALSE
#define FALSE	 0
#endif
#define ABORT	-1

static int Star(const char *, const char *);
static int DoMatch(const char *, const char *);

static int Star(const char *s, const char *p)
{
  int retval;

  while ((retval = DoMatch(s, p)) == FALSE)	/* gobble up * match */
    if (*++s == '\0')
      return ABORT;
  return retval;
}

/* match string "s" to pattern "p" */
static int DoMatch(const char *s, const char *p)
{
  register int last;
  register int matched;
  register int reverse;
  const char *ss;
  int escaped;

  for (; *p; s++, p++) {                        /* parse the string to end */

    if (*s == '\0')
      return *p == '*' && *++p == '\0' ? TRUE : ABORT;

    switch (*p) {			        /* parse pattern */

      case '\\':
        /* Literal match with following character. */
        p++;

        /* FALLTHRU */
      default:		/*literal match*/
        if (*s != *p)
          return FALSE;
        continue;

      case '?':
        /* Match anything. */
        continue;

      case '*':
        /* Trailing star matches everything. */
        return *++p ? Star(s, p) : TRUE;

      case '[':
        /* [!....] means inverse character class. */
        if ((reverse = (p[1] == '!')))
          p++;
        ss = p + 1;	/* set start point */

        for (last = 0400, escaped = matched = FALSE; *++p; last = *p) {
          if (*p == ']' && !(escaped || p == ss))
            break;
          if (escaped)
            escaped = FALSE;
          else if (*p == '\\') {
            escaped = TRUE;
            continue;
          }

          /* This next line requires a good C compiler.	    */
          /*     range?	(in bounds)                 (equal) */
          if ((*p == '-') ? (*s <= *++p && *s >= last) : (*s == *p))
            matched = TRUE;
        }

        if (matched == reverse)
          return FALSE;
        continue;
    }
  }

  return *s == '\0';
}


/*
 * usage: wildmat(string, pattern)
 *
 * returns: non-0 on match
 */
int wildmat(const char *s, const char *p)
{
  if ((*p == '?' || *p == '*') && *s == '.') {
    return FALSE;
  } else {
    return DoMatch(s, p) == TRUE;
  }
}

#ifdef STAND_ALONE_TEST
#include <stdio.h>

/*
 * usage: wildmat <pattern> <test arg(s)>
 */

int main(int argc, char **argv)
{
  int index;
  int status = FALSE;

  for (index = 2; index < argc; ++index) {
    if (wildmat(argv[index], argv[1])) {
      if (status)
        fputs(" ", stdout);
      printf("%s", argv[index]);
      status = TRUE;
    }
  }

  printf("%s\n", status ? "" : argv[1]);
  return 0;
}

#endif
