static int
match_upattern (string, pat, mtype, sp, ep)
     char *string, *pat;
     int mtype;
     char **sp, **ep;
{
  int c, mlen;
  size_t len;
  register char *p, *p1, *npat;
  char *end;
  int n1;

  /* If the pattern doesn't match anywhere in the string, go ahead and
     short-circuit right away.  A minor optimization, saves a bunch of
     unnecessary calls to strmatch (up to N calls for a string of N
     characters) if the match is unsuccessful.  To preserve the semantics
     of the substring matches below, we make sure that the pattern has
     `*' as first and last character, making a new pattern if necessary. */
  /* XXX - check this later if I ever implement `**' with special meaning,
     since this will potentially result in `**' at the beginning or end */
  len = STRLEN (pat);
  if (pat[0] != '*' || (pat[0] == '*' && pat[1] == LPAREN && extended_glob) || pat[len - 1] != '*')
    {
      int unescaped_backslash;
      char *pp;

      p = npat = (char *)xmalloc (len + 3);
      p1 = pat;
      if (*p1 != '*' || (*p1 == '*' && p1[1] == LPAREN && extended_glob))
	*p++ = '*';
      while (*p1)
	*p++ = *p1++;
#if 1
      /* Need to also handle a pattern that ends with an unescaped backslash.
	 For right now, we ignore it because the pattern matching code will
	 fail the match anyway */
      /* If the pattern ends with a `*' we leave it alone if it's preceded by
	 an even number of backslashes, but if it's escaped by a backslash
	 we need to add another `*'. */
      if (p1[-1] == '*' && (unescaped_backslash = p1[-2] == '\\'))
	{
	  pp = p1 - 3;
	  while (pp >= pat && *pp-- == '\\')
	    unescaped_backslash = 1 - unescaped_backslash;
	  if (unescaped_backslash)
	    *p++ = '*';
	}
      else if (p1[-1] != '*')
	*p++ = '*';
#else 
      if (p1[-1] != '*' || p1[-2] == '\\')
	*p++ = '*';
#endif
      *p = '\0';
    }
  else
    npat = pat;
  c = strmatch (npat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE);
  if (npat != pat)
    free (npat);
  if (c == FNM_NOMATCH)
    return (0);

  len = STRLEN (string);
  end = string + len;

  mlen = umatchlen (pat, len);

  switch (mtype)
    {
    case MATCH_ANY:
      for (p = string; p <= end; p++)
	{
	  if (match_pattern_char (pat, p, FNMATCH_IGNCASE))
	    {
	      p1 = (mlen == -1) ? end : p + mlen;
	      /* p1 - p = length of portion of string to be considered
	         p = current position in string
	         mlen = number of characters consumed by match (-1 for entire string)
	         end = end of string
	         we want to break immediately if the potential match len
	         is greater than the number of characters remaining in the
	         string
	      */
	      if (p1 > end)
		break;
	      for ( ; p1 >= p; p1--)
		{
		  c = *p1; *p1 = '\0';
		  if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
		    {
		      *p1 = c;
		      *sp = p;
		      *ep = p1;
		      return 1;
		    }
		  *p1 = c;
#if 1
		  /* If MLEN != -1, we have a fixed length pattern. */
		  if (mlen != -1)
		    break;
#endif
		}
	    }
	}

      return (0);

    case MATCH_BEG:
      if (match_pattern_char (pat, string, FNMATCH_IGNCASE) == 0)
	return (0);

      for (p = (mlen == -1) ? end : string + mlen; p >= string; p--)
	{
	  c = *p; *p = '\0';
	  if (strmatch (pat, string, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
	    {
	      *p = c;
	      *sp = string;
	      *ep = p;
	      return 1;
	    }
	  *p = c;
	  /* If MLEN != -1, we have a fixed length pattern. */
	  if (mlen != -1)
	    break;
	}

      return (0);

    case MATCH_END:
      for (p = end - ((mlen == -1) ? len : mlen); p <= end; p++)
	{
	  if (strmatch (pat, p, FNMATCH_EXTFLAG | FNMATCH_IGNCASE) == 0)
	    {
	      *sp = p;
	      *ep = end;
	      return 1;
	    }
	  /* If MLEN != -1, we have a fixed length pattern. */
	  if (mlen != -1)
	    break;
	}

      return (0);
    }

  return (0);