tinymush-3.1p1/game/backups/
tinymush-3.1p1/game/bin/
tinymush-3.1p1/game/data/
tinymush-3.1p1/game/modules/
tinymush-3.1p1/game/modules/old/
tinymush-3.1p1/src/modules/comsys/
tinymush-3.1p1/src/modules/hello/
tinymush-3.1p1/src/modules/mail/
tinymush-3.1p1/src/tools/
/* match.c - Routines for parsing arguments */
/* $Id: match.c,v 1.20 2002/10/27 17:59:50 rmg Exp $ */

#include "copyright.h"
#include "autoconf.h"
#include "config.h"

#include "alloc.h"	/* required by mudconf */
#include "flags.h"	/* required by mudconf */
#include "htab.h"	/* required by mudconf */
#include "mudconf.h"	/* required by code */

#include "db.h"		/* required by externs */
#include "externs.h"	/* required by code */

#include "match.h"	/* required by code */
#include "attrs.h"	/* required by code */
#include "powers.h"	/* required by code */

#define	CON_LOCAL		0x01	/* Match is near me */
#define	CON_TYPE		0x02	/* Match is of requested type */
#define	CON_LOCK		0x04	/* I pass the lock on match */
#define	CON_COMPLETE		0x08	/* Name given is the full name */
#define	CON_TOKEN		0x10	/* Name is a special token */
#define	CON_DBREF		0x20	/* Name is a dbref */

static MSTATE md;

static void promote_match(what, confidence)
dbref what;
int confidence;
{
	/* Check for type and locks, if requested */

	if (md.pref_type != NOTYPE) {
		if (Good_obj(what) && (Typeof(what) == md.pref_type))
			confidence |= CON_TYPE;
	}
	if (md.check_keys) {
		MSTATE save_md;

		save_match_state(&save_md);
		if (Good_obj(what) && could_doit(md.player, what, A_LOCK))
		    confidence |= CON_LOCK;
		restore_match_state(&save_md);
	}
	/* If nothing matched, take it */

	if (md.count == 0) {
		md.match = what;
		md.confidence = confidence;
		md.count = 1;
		return;
	}
	/* If confidence is lower, ignore */

	if (confidence < md.confidence) {
		return;
	}
	/* If confidence is higher, replace */

	if (confidence > md.confidence) {
		md.match = what;
		md.confidence = confidence;
		md.count = 1;
		return;
	}
	/* Equal confidence, pick randomly */

	md.count++;
	if (Randomize(md.count) == 0) {
		md.match = what;
	}
	return;
}
/* ---------------------------------------------------------------------------
 * This function removes repeated spaces from the template to which object
 * names are being matched.  It also removes initial and terminal spaces.
 */

static char *munge_space_for_match(name)
char *name;
{
	static char buffer[LBUF_SIZE];
	char *p, *q;

	p = name;
	q = buffer;
	while (isspace(*p))
		p++;		/* remove inital spaces */
	while (*p) {
		while (*p && !isspace(*p))
			*q++ = *p++;
		while (*p && isspace(*++p)) ;
		if (*p)
			*q++ = ' ';
	}
	*q = '\0';		/* remove terminal spaces and terminate 
				 * string 
				 */
	return (buffer);
}

void NDECL(match_player)
{
	dbref match;

	if (md.confidence >= CON_DBREF) {
		return;
	}
	if (Good_obj(md.absolute_form) && isPlayer(md.absolute_form)) {
		promote_match(md.absolute_form, CON_DBREF);
		return;
	}
	if (*md.string == LOOKUP_TOKEN) {
		match = lookup_player(NOTHING, md.string, 1);
		if (Good_obj(match)) {
			promote_match(match, CON_TOKEN);
		}
	}
}


/* returns object dbref associated with named reference, else NOTHING */

static dbref absolute_nref(str)
char *str;
{
    char *p, *q, *buf, *bp;
    dbref *np, nref;

    /* Global or local reference? Global references are automatically
     * prepended with an additional underscore. i.e., #__foo_ is a global
     * reference, and #_foo_ is a local reference.
     * Our beginning and end underscores have already been stripped, so
     * we would see only _foo or foo.
     *
     * We are not allowed to nibble our buffer, because we've got a
     * pointer into the match string. Therefore we must copy it.
     * If we're matching locally we copy the dbref of the owner first,
     * which means that we then need to worry about buffer size.
     */

    buf = alloc_lbuf("absolute_nref");

    if (*str == '_') {
	for (p = buf, q = str; *q; p++, q++)
	    *p = tolower(*q);
	*p = '\0';
    } else {
	bp = buf;
	safe_ltos(buf, &bp, Owner(md.player));
	safe_chr('.', buf, &bp);
	for (q = str; *q; q++)
	    safe_chr(tolower(*q), buf, &bp);
	*bp = '\0';
    }

    np = (int *) hashfind(buf, &mudstate.nref_htab);
    if (np && Good_obj(*np))
	nref = *np;
    else
	nref = NOTHING;

    free_lbuf(buf);

    return nref;
}

/* returns nnn if name = #nnn, else NOTHING */

static dbref absolute_name(need_pound)
int need_pound;
{
	dbref match;
	char *mname;

	mname = md.string;
	if (need_pound) {
		if (*md.string != NUMBER_TOKEN) {
			return NOTHING;
		} else {
			mname++;
		}
		if ((*mname == '_') && *(mname + 1)) {
			return absolute_nref(mname + 1);
		}
	}
	if (*mname) {
		match = parse_dbref(mname);
		if (Good_obj(match)) {
			return match;
		}
	}
	return NOTHING;
}

void NDECL(match_absolute)
{
	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.absolute_form))
		promote_match(md.absolute_form, CON_DBREF);
}

void NDECL(match_numeric)
{
	dbref match;

	if (md.confidence >= CON_DBREF)
		return;
	match = absolute_name(0);
	if (Good_obj(match))
		promote_match(match, CON_DBREF);
}

void NDECL(match_me)
{
	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.absolute_form) && (md.absolute_form == md.player)) {
		promote_match(md.player, CON_DBREF | CON_LOCAL);
		return;
	}
	if (!string_compare(md.string, "me"))
		promote_match(md.player, CON_TOKEN | CON_LOCAL);
	return;
}

void NDECL(match_home)
{
	if (md.confidence >= CON_DBREF)
		return;
	if (!string_compare(md.string, "home"))
		promote_match(HOME, CON_TOKEN);
	return;
}

void NDECL(match_here)
{
	dbref loc;

	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.player) && Has_location(md.player)) {
		loc = Location(md.player);
		if (Good_obj(loc)) {
			if (loc == md.absolute_form) {
				promote_match(loc, CON_DBREF | CON_LOCAL);
			} else if (!string_compare(md.string, "here")) {
				promote_match(loc, CON_TOKEN | CON_LOCAL);
			} else if (!string_compare(md.string,
					   (char *)PureName(loc))) {
				promote_match(loc, CON_COMPLETE | CON_LOCAL);
			}
		}
	}
}

static void match_list(first, local)
dbref first;
int local;
{
	char *namebuf;

	if (md.confidence >= CON_DBREF)
		return;
	DOLIST(first, first) {
		if (first == md.absolute_form) {
			promote_match(first, CON_DBREF | local);
			return;
		}
		/*
		 * Warning: make sure there are no other calls to Name() in 
		 * promote_match or its called subroutines; they
		 * would overwrite Name()'s static buffer which is
		 * needed by string_match(). 
		 */
		namebuf = (char *)PureName(first);

		if (!string_compare(namebuf, md.string)) {
			promote_match(first, CON_COMPLETE | local);
		} else if (string_match(namebuf, md.string)) {
			promote_match(first, local);
		}
	}
}

void NDECL(match_possession)
{
	if (md.confidence >= CON_DBREF)
		return;
	if (Good_loc(md.player))
		match_list(Contents(md.player), CON_LOCAL);
}

void NDECL(match_neighbor)
{
	dbref loc;

	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.player) && Has_location(md.player)) {
		loc = Location(md.player);
		if (Good_obj(loc)) {
			match_list(Contents(loc), CON_LOCAL);
		}
	}
}

static int match_exit_internal(loc, baseloc, local)
dbref loc, baseloc;
int local;
{
	dbref exit;
	int result, key;

	if (!Good_obj(loc) || !Has_exits(loc))
		return 1;

	result = 0;
	DOLIST(exit, Exits(loc)) {
		if (exit == md.absolute_form) {
			key = 0;
			if (Examinable(md.player, loc))
				key |= VE_LOC_XAM;
			if (Dark(loc))
				key |= VE_LOC_DARK;
			if (Dark(baseloc))
				key |= VE_BASE_DARK;
			if (Exit_Visible(exit, md.player, key)) {
				promote_match(exit, CON_DBREF | local);
				return 1;
			}
		}
		if (matches_exit_from_list(md.string,
					   (char *)PureName(exit))) {
			promote_match(exit, CON_COMPLETE | local);
			result = 1;
		}
	}
	return result;
}

void NDECL(match_exit)
{
	dbref loc;

	if (md.confidence >= CON_DBREF)
		return;
	loc = Location(md.player);
	if (Good_obj(md.player) && Has_location(md.player))
		(void)match_exit_internal(loc, loc, CON_LOCAL);
}

void NDECL(match_exit_with_parents)
{
	dbref loc, parent;
	int lev;

	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.player) && Has_location(md.player)) {
		loc = Location(md.player);
		ITER_PARENTS(loc, parent, lev) {
			if (match_exit_internal(parent, loc, CON_LOCAL))
				break;
		}
	}
}

void NDECL(match_carried_exit)
{
	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.player) && Has_exits(md.player))
		(void)match_exit_internal(md.player, md.player, CON_LOCAL);
}

void NDECL(match_carried_exit_with_parents)
{
	dbref parent;
	int lev;

	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.player) && (Has_exits(md.player) ||
				    isRoom(md.player))) {
		ITER_PARENTS(md.player, parent, lev) {
			if (match_exit_internal(parent, md.player, CON_LOCAL))
				break;
		}
	}
}

void NDECL(match_master_exit)
{
	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.player) && Has_exits(md.player))
		(void)match_exit_internal(mudconf.master_room,
					  mudconf.master_room, 0);
}

void NDECL(match_zone_exit)
{
	if (md.confidence >= CON_DBREF)
		return;
	if (Good_obj(md.player) && Has_exits(md.player))
		(void)match_exit_internal(Zone(md.player),
					  Zone(md.player), 0);
}

void match_everything(key)
int key;
{
	/*
	 * Try matching me, then here, then absolute, then player FIRST, since
	 * this will hit most cases. STOP if we get something, since those are
	 * exact matches.
	 */

	match_me();
	match_here();
	match_absolute();
	if (key & MAT_NUMERIC)
		match_numeric();
	if (key & MAT_HOME)
		match_home();
	match_player();
	if (md.confidence >= CON_TOKEN)
		return;

	if (!(key & MAT_NO_EXITS)) {
		if (key & MAT_EXIT_PARENTS) {
			match_carried_exit_with_parents();
			match_exit_with_parents();
		} else {
			match_carried_exit();
			match_exit();
		}
	}
	match_neighbor();
	match_possession();
}

dbref NDECL(match_result)
{
	switch (md.count) {
	    case 0:
		return NOTHING;
	    case 1:
		return md.match;
	    default:
		return ((mudconf.no_ambiguous_match) ? (md.match) : AMBIGUOUS);
	}
}

/* use this if you don't care about ambiguity */

dbref NDECL(last_match_result)
{
	return md.match;
}

dbref match_status(player, match)
dbref player, match;
{
	switch (match) {
	case NOTHING:
		notify(player, NOMATCH_MESSAGE);
		return NOTHING;
	case AMBIGUOUS:
		notify(player, AMBIGUOUS_MESSAGE);
		return NOTHING;
	case NOPERM:
		notify(player, NOPERM_MESSAGE);
		return NOTHING;
	}
	return match;
}

dbref NDECL(noisy_match_result)
{
	return match_status(md.player, match_result());
}

void save_match_state(m_state)
MSTATE *m_state;
{
	m_state->confidence = md.confidence;
	m_state->count = md.count;
	m_state->pref_type = md.pref_type;
	m_state->check_keys = md.check_keys;
	m_state->absolute_form = md.absolute_form;
	m_state->match = md.match;
	m_state->player = md.player;
	m_state->string = alloc_lbuf("save_match_state");
	StringCopy(m_state->string, md.string);
}

void restore_match_state(m_state)
MSTATE *m_state;
{
	md.confidence = m_state->confidence;
	md.count = m_state->count;
	md.pref_type = m_state->pref_type;
	md.check_keys = m_state->check_keys;
	md.absolute_form = m_state->absolute_form;
	md.match = m_state->match;
	md.player = m_state->player;
	StringCopy(md.string, m_state->string);
	free_lbuf(m_state->string);
}

void init_match(player, name, type)
dbref player;
const char *name;
int type;
{
	md.confidence = -1;
	md.count = md.check_keys = 0;
	md.pref_type = type;
	md.match = NOTHING;
	md.player = player;
	md.string = munge_space_for_match((char *)name);
	md.absolute_form = absolute_name(1);
}

void init_match_check_keys(player, name, type)
dbref player;
const char *name;
int type;
{
	init_match(player, name, type);
	md.check_keys = 1;
}