game/bin/
game/data/
/*
 * wild.c - wildcard routines
 * *
 * * Written by T. Alexander Popiel, 24 June 1993
 * * Last modified by T. Alexander Popiel, 19 August 1993
 * *
 * * Thanks go to Andrew Molitor for debugging
 * * Thanks also go to Rich $alz for code to benchmark against
 * *
 * * Copyright (c) 1993 by T. Alexander Popiel
 * * This code is hereby placed under GNU copyleft,
 * * see copyright.h for details.
 * *
 * * $Id: wild.c,v 1.3 1995/11/22 23:33:17 root Exp $
 */
#include "copyright.h"
#include "autoconf.h"

#include "config.h"
#include "db.h"
#include "mudconf.h"
#include "externs.h"
#include "alloc.h"

#define FIXCASE(a) (ToLower(a))
#define EQUAL(a,b) ((a == b) || (FIXCASE(a) == FIXCASE(b)))
#define NOTEQUAL(a,b) ((a != b) && (FIXCASE(a) != FIXCASE(b)))

static char **arglist;		/*

				 * argument return space 
				 */
static int numargs;		/*

				 * argument return size 
				 */

/*
 * ---------------------------------------------------------------------------
 * * quick_wild: do a wildcard match, without remembering the wild data.
 * *
 * * This routine will cause crashes if fed NULLs instead of strings.
 */
int quick_wild(tstr, dstr)
char *tstr, *dstr;
{
	while (*tstr != '*') {
		switch (*tstr) {
		case '?':
			/*
			 * Single character match.  Return false if at * end
			 * * * * of data. 
			 */
			if (!*dstr)
				return 0;
			break;
		case '\\':
			/*
			 * Escape character.  Move up, and force literal * *
			 * * * match of next character. 
			 */
			tstr++;
			/*
			 * FALL THROUGH 
			 */
		default:
			/*
			 * Literal character.  Check for a match. * If * * *
			 * matching end of data, return true. 
			 */
			if (NOTEQUAL(*dstr, *tstr))
				return 0;
			if (!*dstr)
				return 1;
		}
		tstr++;
		dstr++;
	}

	/*
	 * Skip over '*'. 
	 */

	tstr++;

	/*
	 * Return true on trailing '*'. 
	 */

	if (!*tstr)
		return 1;

	/*
	 * Skip over wildcards. 
	 */

	while ((*tstr == '?') || (*tstr == '*')) {
		if (*tstr == '?') {
			if (!*dstr)
				return 0;
			dstr++;
		}
		tstr++;
	}

	/*
	 * Skip over a backslash in the pattern string if it is there. 
	 */

	if (*tstr == '\\')
		tstr++;

	/*
	 * Return true on trailing '*'. 
	 */

	if (!*tstr)
		return 1;

	/*
	 * Scan for possible matches. 
	 */

	while (*dstr) {
		if (EQUAL(*dstr, *tstr) &&
		    quick_wild(tstr + 1, dstr + 1))
			return 1;
		dstr++;
	}
	return 0;
}

/*
 * ---------------------------------------------------------------------------
 * * wild1: INTERNAL: do a wildcard match, remembering the wild data.
 * *
 * * DO NOT CALL THIS FUNCTION DIRECTLY - DOING SO MAY RESULT IN
 * * SERVER CRASHES AND IMPROPER ARGUMENT RETURN.
 * *
 * * Side Effect: this routine modifies the 'arglist' static global
 * * variable.
 */
int wild1(tstr, dstr, arg)
char *tstr, *dstr;
int arg;
{
	char *datapos;
	int argpos, numextra;

	while (*tstr != '*') {
		switch (*tstr) {
		case '?':
			/*
			 * Single character match.  Return false if at * end
			 * * * * of data. 
			 */
			if (!*dstr)
				return 0;
			arglist[arg][0] = *dstr;
			arglist[arg][1] = '\0';
			arg++;

			/*
			 * Jump to the fast routine if we can. 
			 */

			if (arg >= numargs)
				return quick_wild(tstr + 1, dstr + 1);
			break;
		case '\\':
			/*
			 * Escape character.  Move up, and force literal * *
			 * * * match of next character. 
			 */
			tstr++;
			/*
			 * FALL THROUGH 
			 */
		default:
			/*
			 * Literal character.  Check for a match. * If * * *
			 * matching end of data, return true. 
			 */
			if (NOTEQUAL(*dstr, *tstr))
				return 0;
			if (!*dstr)
				return 1;
		}
		tstr++;
		dstr++;
	}

	/*
	 * If at end of pattern, slurp the rest, and leave. 
	 */

	if (!tstr[1]) {
		StringCopyTrunc(arglist[arg], dstr, LBUF_SIZE - 1);
		arglist[arg][LBUF_SIZE - 1] = '\0';
		return 1;
	}
	/*
	 * Remember current position for filling in the '*' return. 
	 */

	datapos = dstr;
	argpos = arg;

	/*
	 * Scan forward until we find a non-wildcard. 
	 */

	do {
		if (argpos < arg) {
			/*
			 * Fill in arguments if someone put another '*' * * * 
			 * 
			 * * before a fixed string. 
			 */
			arglist[argpos][0] = '\0';
			argpos++;

			/*
			 * Jump to the fast routine if we can. 
			 */

			if (argpos >= numargs)
				return quick_wild(tstr, dstr);

			/*
			 * Fill in any intervening '?'s 
			 */

			while (argpos < arg) {
				arglist[argpos][0] = *datapos;
				arglist[argpos][1] = '\0';
				datapos++;
				argpos++;

				/*
				 * Jump to the fast routine if we can. 
				 */

				if (argpos >= numargs)
					return quick_wild(tstr, dstr);
			}
		}
		/*
		 * Skip over the '*' for now... 
		 */

		tstr++;
		arg++;

		/*
		 * Skip over '?'s for now... 
		 */

		numextra = 0;
		while (*tstr == '?') {
			if (!*dstr)
				return 0;
			tstr++;
			dstr++;
			arg++;
			numextra++;
		}
	} while (*tstr == '*');

	/*
	 * Skip over a backslash in the pattern string if it is there. 
	 */

	if (*tstr == '\\')
		tstr++;

	/*
	 * Check for possible matches.  This loop terminates either at * end
	 * * * * of data (resulting in failure), or at a successful match. 
	 */
	while (1) {

		/*
		 * Scan forward until first character matches. 
		 */

		if (*tstr)
			while (NOTEQUAL(*dstr, *tstr)) {
				if (!*dstr)
					return 0;
				dstr++;
		} else
			while (*dstr)
				dstr++;

		/*
		 * The first character matches, now.  Check if the rest * * * 
		 * 
		 * * does, using the fastest method, as usual. 
		 */
		if (!*dstr ||
		    ((arg < numargs) ? wild1(tstr + 1, dstr + 1, arg)
		     : quick_wild(tstr + 1, dstr + 1))) {

			/*
			 * Found a match!  Fill in all remaining arguments. * 
			 * 
			 * *  * *  * * First do the '*'... 
			 */
			StringCopyTrunc(arglist[argpos], datapos,
					(dstr - datapos) - numextra);
			arglist[argpos][(dstr - datapos) - numextra] = '\0';
			datapos = dstr - numextra;
			argpos++;

			/*
			 * Fill in any trailing '?'s that are left. 
			 */

			while (numextra) {
				if (argpos >= numargs)
					return 1;
				arglist[argpos][0] = *datapos;
				arglist[argpos][1] = '\0';
				datapos++;
				argpos++;
				numextra--;
			}

			/*
			 * It's done! 
			 */

			return 1;
		} else {
			dstr++;
		}
	}
}

/*
 * ---------------------------------------------------------------------------
 * * wild: do a wildcard match, remembering the wild data.
 * *
 * * This routine will cause crashes if fed NULLs instead of strings.
 * *
 * * This function may crash if alloc_lbuf() fails.
 * *
 * * Side Effect: this routine modifies the 'arglist' and 'numargs'
 * * static global variables.
 */
int wild(tstr, dstr, args, nargs)
char *tstr, *dstr, *args[];
int nargs;
{
	int i, value;
	char *scan;

	/*
	 * Initialize the return array. 
	 */

	for (i = 0; i < nargs; i++)
		args[i] = NULL;

	/*
	 * Do fast match. 
	 */

	while ((*tstr != '*') && (*tstr != '?')) {
		if (*tstr == '\\')
			tstr++;
		if (NOTEQUAL(*dstr, *tstr))
			return 0;
		if (!*dstr)
			return 1;
		tstr++;
		dstr++;
	}

	/*
	 * Allocate space for the return args. 
	 */

	i = 0;
	scan = tstr;
	while (*scan && (i < nargs)) {
		switch (*scan) {
		case '?':
			args[i] = alloc_lbuf("wild.?");
			i++;
			break;
		case '*':
			args[i] = alloc_lbuf("wild.*");
			i++;
		}
		scan++;
	}

	/*
	 * Put stuff in globals for quick recursion. 
	 */

	arglist = args;
	numargs = nargs;

	/*
	 * Do the match. 
	 */

	value = nargs ? wild1(tstr, dstr, 0) : quick_wild(tstr, dstr);

	/*
	 * Clean out any fake match data left by wild1. 
	 */

	for (i = 0; i < nargs; i++)
		if ((args[i] != NULL) && (!*args[i] || !value)) {
			free_lbuf(args[i]);
			args[i] = NULL;
		}
	return value;
}

/*
 * ---------------------------------------------------------------------------
 * * wild_match: do either an order comparison or a wildcard match,
 * * remembering the wild data, if wildcard match is done.
 * *
 * * This routine will cause crashes if fed NULLs instead of strings.
 */
int wild_match(tstr, dstr)
char *tstr, *dstr;
{
	int i;

	switch (*tstr) {
	case '>':
		tstr++;
		if (isdigit(*tstr) || (*tstr == '-'))
			return (atoi(tstr) < atoi(dstr));
		else
			return (strcmp(tstr, dstr) < 0);
	case '<':
		tstr++;
		if (isdigit(*tstr) || (*tstr == '-'))
			return (atoi(tstr) > atoi(dstr));
		else
			return (strcmp(tstr, dstr) > 0);
	}

	return quick_wild(tstr, dstr);
}