/*
** gmatch.c for  in 
** 
** Made by vianney rancurel
** Login   <vianney@epita.fr>
** 
** Started on  Wed Aug 25 12:10:23 1999 vianney rancurel
** Last update Thu Oct 28 20:16:42 1999 
*/
/*
** Match the pattern PATTERN against the string TEXT;
** return 1 if it matches, 0 otherwise.
**
** A match means the entire string TEXT is used up in matching.
**
** In the pattern string, `*' matches any sequence of characters,
** `?' matches any character, [SET] matches any character in the specified set,
** [!SET] matches any character not in the specified set .
** A set is composed of characters or ranges; a range looks like
** character hyphen character (as in 0-9 or A-Z).
** [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
** Any other character in the pattern must be matched exactly.
**
** To suppress the special syntactic significance of any of `[]*?!-\',
**  and match the character exactly, precede it with a `\'.
**
** If DOT_SPECIAL is nonzero,
** `*' and `?' do not match `.' at the beginning of TEXT.  
*/
#include <ctype.h>
#include <sys/types.h>

#define GMATCH_SENSITIVE	1
#define GMATCH_INSENSITIVE	0

static int glob_match_after_star();

int	gmatch(text,pattern)
char	*pattern;
char	*text;
{
   return (glob_match(pattern,text,0,GMATCH_SENSITIVE));
}

int	gmatchcase(text,pattern,caseflag)
char	*pattern;
char	*text;
int	caseflag;
{
   return (glob_match(pattern,text,0,caseflag));
}

/* Return nonzero if PATTERN has any special globbing chars in it.  */

int	glob_pattern_p(pattern)
char	*pattern;
{
   char	*p;
   char	c;
   
   p = pattern;
   while ((c = *p++) != '\0')
      switch (c)
      {
      case '?':
      case '[':
      case '*':
	 return (1);
      case '\\':
	 if (*p++ == '\0')
	    return (0);
      }
   return (0);
}

int	glob_match(pattern,text,dot_special,caseflag)
char	*pattern;
char	*text;
int	dot_special;
int	caseflag;
{
   char *p = pattern;
   char	*t = text;
   char	c;
   
   while ((c = *p++) != '\0')
      switch (c)
      {
      case '?':
	 if (*t == '\0' || (dot_special && t == text && *t == '.'))
	    return (0);
	 else
	    ++t;
	 break;
      case '\\':
	 if (*p++ != *t++)
	    return (0);
	 break;
      case '*':
	 if (dot_special && t == text && *t == '.')
	    return (0);
	 return (glob_match_after_star(p,t,caseflag));
      case '[':
      {
	 char	c1 = *t++;
	 int	invert;
	 
	 invert = ((*p == '!') || (*p == '^'));
	 if (invert)
	    p++;
	 c = *p++;
	 while (1)
	 {
	    char	cstart = c, cend = c;
	    
	    if (c == '\\')
	    {
	       cstart = *p++;
	       cend = cstart;
	    }
	    if (c == '\0')
	       return (0);
	    c = *p++;
	    if (c == '-')
	    {
	       cend = *p++;
	       if (cend == '\\')
		  cend = *p++;
	       if (cend == '\0')
		  return 0;
	       c = *p++;
	    }
	    if (c1 >= cstart && c1 <= cend)
	       goto match;
	    if (c == ']')
	       break;
	 }
	 if (!invert)
	    return (0);
	 break;
      match:
	 /* Skip the rest of the [...] construct that already matched.  */
	 while (c != ']')
	 { 
	    if (c == '\0')
	       return (0);
	    c = *p++;
	    if (c == '\0')
	       return (0);
	    else if (c == '\\')
	       ++p;
	 }
	 if (invert)
	    return (0);
	 break;
      }
      default:
	 if (caseflag == GMATCH_SENSITIVE || islower(*t))
	 {
	    if (c != *t++)
	       return (0);
	 }
	 else
	    if (c != tolower(*t++))
	       return (0);
      }
   return *t == '\0';
}

/* Like glob_match, but match PATTERN against any final segment of TEXT.  */

static int	glob_match_after_star(pattern,text,caseflag)
char		*pattern;
char		*text;
int		caseflag;
{
   char		*p = pattern;
   char		*t = text;
   char		c;
   char		c1;
   
   while ((c = *p++) == '?' || c == '*')
      if (c == '?' && *t++ == '\0')
	 return (0);
   if (c == '\0')
      return (1);
   if (c == '\\')
      c1 = *p;
   else
      c1 = c;
   while (1)
   {
      if ((c == '[' || *t == c1) && glob_match (p - 1, t, 0,caseflag))
	 return (1);
      if (*t++ == '\0')
	 return (0);
   }
}
