/*
 * 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.
 *
 * =======================================================================
 *
 * Global string matching
 *
 * =======================================================================
 */

#include <stdio.h>
#include "header/glob.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;
		}
	}
}

/* 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';
}

