/* match.c */
#include "copyright.h"
/* Routines for parsing arguments */
#include <ctype.h>
#ifdef WANT_ANSI
#ifdef __STDC__
#include <stddef.h>
#endif /* __STDC__ */
#endif /* WANT_ANSI */
#include "config.h"
#include "db.h"
#include "mudconf.h"
#include "externs.h"
#include "match.h"
extern long random();
static dbref exact_match = NOTHING; /* holds result of exact match */
static int check_keys = 0; /* if non-zero, check for keys */
static dbref last_match = NOTHING; /* holds result of last match */
static int match_count; /* holds total number of inexact matches */
static dbref match_who; /* player who is being matched around */
static const char *match_name; /* name to match */
static int preferred_type = NOTYPE; /* preferred type */
/*
* This function removes repeated spaces from the template to which object
* names are being matched. It also removes inital and terminal spaces.
*/
static char *munge_space_for_match(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);
}
/*
* check a list for objects that are prefix's for string, && are controlled
* || link_ok
*/
dbref pref_match(dbref player, dbref list, const char *string)
{
dbref lmatch = NOTHING;
int mlen = 0;
while (list != NOTHING) {
if (string_prefix(string, Name(list)) &&
(Flags(list) & PUPPET) &&
controls(player, list)) {
if (strlen(Name(list)) > mlen) {
lmatch = list;
mlen = strlen(Name(list));
}
}
list = Next(list);
}
return (lmatch);
}
void init_match(dbref player, const char *name, int type)
{
exact_match = last_match = NOTHING;
match_count = 0;
match_who = player;
match_name = munge_space_for_match((char *)name);
check_keys = 0;
preferred_type = type;
}
void init_match_check_keys(dbref player, const char *name, int type)
{
init_match(player, name, type);
check_keys = 1;
}
static dbref choose_thing(dbref thing1, dbref thing2)
{
int has1;
int has2;
if (thing1 == NOTHING) {
return thing2;
} else if (thing2 == NOTHING) {
return thing1;
}
if (preferred_type != NOTYPE) {
if (Typeof(thing1) == preferred_type) {
if (Typeof(thing2) != preferred_type) {
return thing1;
}
} else if (Typeof(thing2) == preferred_type) {
return thing2;
}
}
if (check_keys) {
has1 = could_doit(match_who, thing1, A_LOCK);
has2 = could_doit(match_who, thing2, A_LOCK);
if (has1 && !has2) {
return thing1;
} else if (has2 && !has1) {
return thing2;
}
/* else fall through */
}
return (random() % 2 ? thing1 : thing2);
}
void match_player()
{
dbref match;
char *p;
if (*match_name == LOOKUP_TOKEN) {
for (p = (char *)match_name + 1; isspace(*p); p++) ;
if ((match = lookup_player(NOTHING, p, 1)) != NOTHING) {
exact_match = match;
}
}
}
/* returns nnn if name = #nnn, else NOTHING */
static dbref absolute_name()
{
dbref match;
if (*match_name == NUMBER_TOKEN) {
match = parse_dbref(match_name + 1);
if (!Good_obj(match)) {
return NOTHING;
} else {
return match;
}
} else {
return NOTHING;
}
}
void match_absolute()
{
dbref match;
match = absolute_name();
if (Good_obj(match)) {
exact_match = match;
}
}
void match_me()
{
if (!string_compare(match_name, "me")) {
exact_match = match_who;
}
}
void match_here()
{
if (Good_obj(match_who) && Has_location(match_who)) {
if (!string_compare(match_name, "here") &&
Good_obj(Location(match_who))) {
exact_match = Location(match_who);
}
}
}
static void match_list(dbref first)
{
dbref absolute;
absolute = absolute_name();
if (!Good_obj(absolute) || !controls(match_who, absolute))
absolute = NOTHING;
DOLIST(first, first) {
if (first == absolute) {
exact_match = first;
return;
} else if (!string_compare(Name(first), match_name)) {
/* if multiple exact matches, randomly choose one */
exact_match = choose_thing(exact_match, first);
} else if (string_match(Name(first), match_name)) {
last_match = first;
match_count++;
}
}
}
void match_possession()
{
if (Good_obj(match_who) && Has_contents(match_who))
match_list(Contents(match_who));
}
void match_neighbor()
{
dbref loc;
if (Good_obj(match_who) && Has_location(match_who)) {
loc = Location(match_who);
if (Good_obj(loc)) {
match_list(Contents(loc));
}
}
}
static void match_exit_internal (dbref loc)
{
dbref exit, absolute;
if (!Good_obj(loc) || !Has_exits(loc))
return;
absolute = absolute_name();
if (!Good_obj(absolute) || !controls(match_who, absolute))
absolute = NOTHING;
DOLIST(exit, Exits(loc)) {
if (exit == absolute) {
exact_match = exit;
return;
}
if (matches_exit_from_list((char *)match_name, Name(exit)))
exact_match = choose_thing(exact_match, exit);
}
}
void match_exit()
{
if (Good_obj(match_who) && Has_location(match_who))
match_exit_internal(Location(match_who));
}
void match_exit_with_parents()
{
dbref loc, parent;
int lev;
if (Good_obj(match_who) && Has_location(match_who)) {
loc = Location(match_who);
match_exit_internal(loc);
if (exact_match == NOTHING) {
for (lev=0, parent=Parent(loc);
(Good_obj(parent) &&
(lev < mudconf.parent_nest_lim) &&
(exact_match == NOTHING));
parent=Parent(parent), lev++) {
match_exit_internal(parent);
}
}
}
}
void match_carried_exit()
{
if (Good_obj(match_who) && Has_exits(match_who))
match_exit_internal(match_who);
}
void match_carried_exit_with_parents()
{
dbref parent;
int lev;
if (Good_obj(match_who) && Has_exits(match_who)) {
match_exit_internal(match_who);
if (exact_match == NOTHING) {
for (lev=0, parent=Parent(match_who);
(Good_obj(parent) &&
(lev < mudconf.parent_nest_lim) &&
(exact_match == NOTHING));
parent=Parent(parent), lev++) {
match_exit_internal(parent);
}
}
}
}
void match_master_exit()
{
if (Good_obj(mudconf.master_room))
match_exit_internal(mudconf.master_room);
}
void match_everything()
{
match_carried_exit();
match_exit();
match_neighbor();
match_possession();
match_me();
match_here();
match_absolute();
match_player();
}
dbref match_result()
{
if (exact_match != NOTHING) {
return exact_match;
} else {
switch (match_count) {
case 0:
return NOTHING;
case 1:
return last_match;
default:
return AMBIGUOUS;
}
}
}
/* use this if you don't care about ambiguity */
dbref last_match_result()
{
if (exact_match != NOTHING) {
return exact_match;
} else {
return last_match;
}
}
dbref noisy_match_result()
{
dbref match;
switch (match = match_result()) {
case NOTHING:
notify(match_who, NOMATCH_MESSAGE);
return NOTHING;
case AMBIGUOUS:
notify(match_who, AMBIGUOUS_MESSAGE);
return NOTHING;
default:
return match;
}
}