mux2.0/game/
mux2.0/game/data/
mux2.0/src/tools/
// 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.cpp,v 1.1 2000/04/11 07:14:48 sdennis Exp $
//
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"

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

#define EQUAL(a,b) ((a == b) || (Tiny_ToLower[(unsigned char)a] == Tiny_ToLower[(unsigned char)b]))
#define NOTEQUAL(a,b) ((a != b) && (Tiny_ToLower[(unsigned char)a] != Tiny_ToLower[(unsigned char)b]))

// Argument return space and size.
//
static char **arglist;
static int numargs;

//
// ---------------------------------------------------------------------------
// 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(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.?");
            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(char *tstr, char *dstr)
{
    switch (*tstr)
    {
    case '>':

        tstr++;
        if (Tiny_IsDigit[(unsigned char)*tstr] || (*tstr == '-'))
        {
            return (Tiny_atol(tstr) < Tiny_atol(dstr));
        }
        else
        {
            return (strcmp(tstr, dstr) < 0);
        }

    case '<':

        tstr++;
        if (Tiny_IsDigit[(unsigned char)*tstr] || (*tstr == '-'))
        {
            return (Tiny_atol(tstr) > Tiny_atol(dstr));
        }
        else
        {
            return (strcmp(tstr, dstr) > 0);
        }
    }

    return quick_wild(tstr, dstr);
}