/***************************************************************************
 fnmatch_openvms.c - OpenVMS fnmatch implementation

 Simple fnmatch implementation for OpenVMS.
 Supports basic wildcards: * and ?
***************************************************************************/

#ifdef OPENVMS

#include <string.h>
#include <ctype.h>

/* fnmatch flags */
#define FNM_NOMATCH     1       /* Match failed. */
#define FNM_NOESCAPE    0x01    /* Disable backslash escaping. */
#define FNM_PATHNAME    0x02    /* Slash must be matched by slash. */
#define FNM_PERIOD      0x04    /* Period must be matched by period. */
#define FNM_LEADING_DIR 0x08    /* Ignore /<tail> after Imatch. */
#define FNM_CASEFOLD    0x10    /* Case insensitive search. */

static int
fnmatch_internal(const char *pattern, const char *string, int flags)
{
	char c;
	char test;

	for (;;) {
		c = *pattern++;

		switch (c) {
		case 0:
			return (*string == 0 ? 0 : FNM_NOMATCH);

		case '?':
			if (*string == 0)
				return (FNM_NOMATCH);
			if ((flags & FNM_PATHNAME) && *string == '/')
				return (FNM_NOMATCH);
			if ((flags & FNM_PERIOD) && *string == '.' &&
			    (string == string ||
			     ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
				return (FNM_NOMATCH);
			++string;
			break;

		case '*':
			c = *pattern;
			/* Collapse multiple stars. */
			while (c == '*')
				c = *++pattern;

			if ((flags & FNM_PERIOD) && *string == '.' &&
			    (string == string ||
			     ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
				return (FNM_NOMATCH);

			/* Optimize for pattern with * at end or before /. */
			if (c == 0) {
				if (flags & FNM_PATHNAME)
					return ((flags & FNM_LEADING_DIR) ||
					    strchr(string, '/') == NULL ?
					    0 : FNM_NOMATCH);
				else
					return (0);
			} else if ((flags & FNM_PATHNAME) && c == '/')
				if ((string = strchr(string, '/')) == NULL)
					return (FNM_NOMATCH);

			/* General case, use recursion. */
			while ((test = *string) != '\0') {
				if (!fnmatch_internal(pattern, string, flags))
					return (0);
				if ((flags & FNM_PATHNAME) && test == '/')
					break;
				++string;
			}
			return (FNM_NOMATCH);

		case '\\':
			if (!(flags & FNM_NOESCAPE)) {
				c = *pattern++;
				if (c == 0) {
					c = '\\';
					--pattern;
				}
			}
			/* FALLTHROUGH */

		default:
			if (flags & FNM_CASEFOLD)
				test = tolower((unsigned char)*string);
			else
				test = *string;

			if (test == 0)
				return (FNM_NOMATCH);

			if ((flags & FNM_CASEFOLD ? tolower((unsigned char)c) : c) != test)
				return (FNM_NOMATCH);

			string++;
			break;
		}
	}
	/* NOTREACHED */
}

int
fnmatch(const char *pattern, const char *string, int flags)
{
	return fnmatch_internal(pattern, string, flags);
}

#endif /* OPENVMS */
