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