/
2.0.5/doc/
2.0.5/gnu/
2.0.5/sha/
/* wild.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		Portions Copyright(C) 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II 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.
 *
 * TeenyMUD II 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 (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

/* wild.c - wildcard routines
 *
 * Stolen from MUSH and hacked up, April 1994.
 * (Well, not really stolen. Supposedly, it was under the 'GNU copyleft'.)
 *
 * 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.
 */

/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca	__builtin_alloca
#else	/* not __GNUC__ */
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#else	/* not HAVE_ALLOCA_H */
#ifdef _AIX
 #pragma alloca
#endif	/* not _AIX */
#endif	/* not HAVE_ALLOCA_H */
#endif 	/* not __GNUC__ */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#include <ctype.h>

#include "conf.h"
#include "teeny.h"
#include "externs.h"

#define FIXCASE(a) (to_lower(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 maximum size */
static int totargs;	/* total number of parsed arguments */

static int wild1 _ANSI_ARGS_((char *, char *, int));

int quick_wild_prefix(tstr, dstr)
    char *tstr, *dstr;
{
  return((strncasecmp(tstr, dstr, strlen(tstr)) == 0)
         || quick_wild(tstr, dstr));
}

/* ---------------------------------------------------------------------------
 * 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.
 */
static 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;

			/* allocate the argument */
			arglist[arg] = (char *)ty_malloc((size_t)2,
							 "wild1.arglist");
			arglist[arg][0] = *dstr;
			arglist[arg][1] = '\0';
			arg++;
			totargs++;

			/* 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]) {
		/* allocate the argument */
		arglist[arg] = ty_strdup(dstr, "wild1.arglist");
		totargs++;
		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] = (char *)ty_strdup("",
							    "wild1.arglist");
			argpos++;
			totargs++;

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

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

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

			while (argpos < arg) {
				/* allocate the argument */
				arglist[argpos] = (char *)ty_malloc((size_t)2,
							"wild1.arglist");
				arglist[argpos][0] = *datapos;
				arglist[argpos][1] = '\0';
				datapos++;
				argpos++;
				totargs++;

				/* 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 '*'...
			 */
			/* allocate the argument */
			arglist[argpos] = (char *)ty_malloc(
					((dstr - datapos) - numextra) + 1,
					"wild1.arglist");
			ty_strncpy(arglist[argpos], datapos,
				   (dstr - datapos) - numextra);
			datapos = dstr - numextra;
			argpos++;
			totargs++;

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

			while (numextra) {
				if (argpos >= numargs) return 1;

				/* allocate the argument */
				arglist[argpos] = (char *)ty_malloc((size_t)2,
							"wild1.arglist");
				arglist[argpos][0] = *datapos;
				arglist[argpos][1] = '\0';
				datapos++;
				argpos++;
				totargs++;
				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.
 *
 * Side Effect: this routine modifies the 'arglist' and 'numargs'
 * static global variables.
 */
int wild(tstr, dstr, limit, argc, args)
char	*tstr, *dstr;
int	limit, *argc;
char	*args[];
{
int	i, value;

	/* Initialize the return array. */

	*argc = 0;
	for (i=0; i<limit; i++) args[i] = (char *)NULL;

	/* Do fast match. */

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

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

	arglist = args;
	numargs = limit;
	totargs = 0;

	/* Do the match. */

	value = wild1(tstr, dstr, 0);

	/* If we matched nothing, make sure the array is empty. */
	if(!value) {
		for(i = 0; i < limit; i++) {
			if(args[i] != (char *)NULL) {
				ty_free((VOID *)args[i]);
				args[i] = (char *)NULL;
			}
		}
	} else
		*argc = totargs;

	return value;
}

int filter_match(str, filter)
    register char *str, *filter;
{
  register char *buf, *p;

  buf = (char *) alloca(strlen(filter) + 1);
  if(buf == (char *)NULL)
    panic("filter_match(): stack allocation failed\n");
  strcpy(buf, filter);

  while (buf[0]) {
    for (p = buf; *p && (*p != '|'); p++);
    if (*p == '|')
      *p++ = '\0';
    if (quick_wild(buf, str))
      return (1);
    buf = p;
  }
  return (0);
}