/*

	Copyright (C) 1997-2001 Id Software, Inc.

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

	See the GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "../wolfiphone.h"

/* Like glob_match, but match PATTERN against any final segment of TEXT.  */
static int glob_match_after_star( char *pattern, char *text )
{
	register char *p = pattern, *t = text;
	register char c, 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 ) )
		{
			return 1;
		}

		if( *t++ == '\0' )
		{
			return 0;
		}
	}
}

/* Return nonzero if PATTERN has any special globbing chars in it.  */
static int glob_pattern_p( char *pattern )
{
	register char *p = pattern;
	register char c;
	int open = 0;

	while( (c = *p++) != '\0' )
	{
		switch( c ) 
		{
			case '?':
			case '*':
				return 1;

			case '[':		/* Only accept an open brace if there is a close */
				open++;		/* brace to match it.  Bracket expressions must be */
				continue;	/* complete, according to Posix.2 */
			case ']':
				if( open )
				{
					return 1;
				}
				continue;

			case '\\':
				if( *p++ == '\0' )
				{
					return 0;
				}
		}

	}

	return 0;
}

/* 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 `\'.
*/

int glob_match(char *pattern, char *text)
{
	register char *p = pattern, *t = text;
	register char c;

	while ((c = *p++) != '\0')
		switch (c) {
		case '?':
			if (*t == '\0')
				return 0;
			else
				++t;
			break;

		case '\\':
			if (*p++ != *t++)
				return 0;
			break;

		case '*':
			return glob_match_after_star(p, t);

		case '[':
			{
				register char c1 = *t++;
				int invert;

				if (!c1)
					return (0);

				invert = ((*p == '!') || (*p == '^'));
				if (invert)
					p++;

				c = *p++;
				while (1) {
					register char cstart = c, cend = c;

					if (c == '\\') {
						cstart = *p++;
						cend = cstart;
					}
					if (c == '\0')
						return 0;

					c = *p++;
					if (c == '-' && *p != ']') {
						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 (c != *t++)
				return 0;
		}

	return *t == '\0';
}

