btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * 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.
 * *
 */

#include "copyright.h"
#include "config.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  */

/**
 * Do a wildcard match, without remembering the wild data.
 * This routine will cause crashes if fed NULLs instead of strings.
 */
int quick_wild(char *tstr, char *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(char *tstr, char *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(char *tstr, char *dstr, char *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.?");
            memset(args[i], 0, LBUF_SIZE);
			i++;
			break;
		case '*':
			args[i] = alloc_lbuf("wild.*");
            memset(args[i], 0, LBUF_SIZE);
			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(char *tstr, char *dstr)
{
	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);
}