/* match.c -- Routines for parsing arguments */ #include "autoconf.h" #include "copyright.h" #ifndef lint static char *RCSid = "$Id: match.c,v 1.7 1995/03/21 00:00:39 ambar Exp $"; USE(RCSid); #endif #include "externs.h" #include "match.h" #include "attrs.h" static dbref exact_match = NOTHING; /* holds result of exact match */ static int have_exact = 0; /* Have a precise match (dbref, 'me', etc) */ 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 = 0; /* holds total number of inexact matches */ static dbref match_who = NOTHING; /* player performing match */ static const char *match_name = ""; /* name to match */ static int preferred_type = NOTYPE; /* preferred type */ static int local_match = 0; /* Matched something locally, not by number */ /* * 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(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); } /* * check a list for objects that are prefix's for string, && are controlled * || link_ok */ dbref pref_match(player, list, string) dbref player, list; const char *string; { dbref lmatch; int mlen; lmatch = NOTHING; mlen = 0; while (list != NOTHING) { if (string_prefix(string, Name(list)) && Puppet(list) && controls(player, list)) { if (strlen(Name(list)) > mlen) { lmatch = list; mlen = strlen(Name(list)); } } list = Next(list); } return (lmatch); } void init_match(player, name, type) dbref player; const char *name; int type; { exact_match = last_match = NOTHING; have_exact = 0; match_count = 0; match_who = player; match_name = munge_space_for_match((char *) name); check_keys = 0; preferred_type = type; local_match = 0; } void init_match_check_keys(player, name, type) dbref player; const char *name; int type; { init_match(player, name, type); check_keys = 1; } static dbref choose_thing(thing1, thing2) dbref thing1, 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 NDECL(match_player) { dbref match; char *p; if (have_exact) return; 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; have_exact = 1; local_match = 0; } } } /* returns nnn if name = #nnn, else NOTHING */ static dbref absolute_name(need_pound) int need_pound; { dbref match; char *mname; mname = (char *) match_name; if (need_pound) { if (*match_name != NUMBER_TOKEN) { return NOTHING; } else { mname++; } } if (*mname) { match = parse_dbref(mname); if (Good_obj(match)) { return match; } } return NOTHING; } void NDECL(match_absolute) { dbref match; if (have_exact) return; match = absolute_name(1); if (Good_obj(match)) { exact_match = match; have_exact = 1; local_match = 0; } } void NDECL(match_numeric) { dbref match; if (have_exact) return; match = absolute_name(0); if (Good_obj(match)) { exact_match = match; have_exact = 1; local_match = 0; } } void NDECL(match_controlled_absolute) { dbref match; if (have_exact) return; match = absolute_name(1); if (Good_obj(match) && (Controls(match_who, match) || nearby(match_who, match))) { exact_match = match; have_exact = 1; local_match = 0; } } void NDECL(match_me) { if (have_exact) return; if (!string_compare(match_name, "me")) { exact_match = match_who; have_exact = 1; local_match = 1; } } void NDECL(match_home) { if (have_exact) return; if (!string_compare(match_name, "home")) { exact_match = HOME; have_exact = 1; local_match = 0; } } void NDECL(match_here) { if (have_exact) return; 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); have_exact = 1; local_match = 1; } } } static void match_list(first) dbref first; { dbref absolute; char *namebuf; if (have_exact) return; absolute = absolute_name(1); if (!Good_obj(absolute)) absolute = NOTHING; DOLIST(first, first) { if (first == absolute) { exact_match = first; have_exact = 1; local_match = 1; return; } /* Warning: make sure there are no other calls to Name() * in choose_thing or its called subroutines; they would * overwrite Name()'s static buffer which is needed by * string_match(). */ namebuf = Name(first); if (!string_compare(namebuf, match_name)) { /* if multiple exact matches, randomly choose one */ exact_match = choose_thing(exact_match, first); local_match = 1; } else if (string_match(namebuf, match_name)) { last_match = first; match_count++; local_match = 1; } } } void NDECL(match_possession) { if (have_exact) return; if (Good_obj(match_who) && Has_contents(match_who)) match_list(Contents(match_who)); } void NDECL(match_neighbor) { dbref loc; if (have_exact) return; 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(loc) dbref loc; { dbref exit, absolute; if (!Good_obj(loc) || !Has_exits(loc)) return; absolute = absolute_name(1); if (!Good_obj(absolute) || !controls(match_who, absolute)) absolute = NOTHING; DOLIST(exit, Exits(loc)) { if (exit == absolute) { exact_match = exit; local_match = 1; return; } if (matches_exit_from_list((char *) match_name, Name(exit))) { exact_match = choose_thing(exact_match, exit); local_match = 1; } } } void NDECL(match_exit) { if (have_exact) return; if (Good_obj(match_who) && Has_location(match_who)) match_exit_internal(Location(match_who)); } void NDECL(match_exit_with_parents) { dbref parent; int lev; if (have_exact) return; if (Good_obj(match_who) && Has_location(match_who)) { ITER_PARENTS(Location(match_who), parent, lev) { match_exit_internal(parent); if (exact_match != NOTHING) break; } } } void NDECL(match_carried_exit) { if (have_exact) return; if (Good_obj(match_who) && Has_exits(match_who)) match_exit_internal(match_who); } void NDECL(match_carried_exit_with_parents) { dbref parent; int lev; if (have_exact) return; if (Good_obj(match_who) && Has_exits(match_who)) { ITER_PARENTS(match_who, parent, lev) { match_exit_internal(parent); if (exact_match != NOTHING) break; } } } void NDECL(match_master_exit) { if (exact_match != NOTHING) return; if (Good_obj(mudconf.master_room)) match_exit_internal(mudconf.master_room); } 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 (have_exact) 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) { if (exact_match != NOTHING) return exact_match; 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 NDECL(last_match_result) { if (exact_match != NOTHING) return exact_match; return last_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(match_who, match_result()); } dbref dispatched_match_result(player) dbref player; { dbref match, save_player; save_player = match_who; match_who = player; match = noisy_match_result(); match_who = save_player; return match; } int NDECL(matched_locally) { return local_match; } void save_match_state(mstate) MSTATE *mstate; { mstate->exact_match = exact_match; mstate->have_exact = have_exact; mstate->check_keys = check_keys; mstate->last_match = last_match; mstate->match_count = match_count; mstate->match_who = match_who; mstate->match_name = alloc_lbuf("save_match_state"); strcpy(mstate->match_name, match_name); mstate->preferred_type = preferred_type; mstate->local_match = local_match; } void restore_match_state(mstate) MSTATE *mstate; { exact_match = mstate->exact_match; have_exact = mstate->have_exact; check_keys = mstate->check_keys; last_match = mstate->last_match; match_count = mstate->match_count; match_who = mstate->match_who; strcpy((char *) match_name, mstate->match_name); free_lbuf(mstate->match_name); preferred_type = mstate->preferred_type; local_match = mstate->local_match; } dbref match_controlled_quiet(player, name) dbref player; const char *name; { dbref mat; init_match(player, name, NOTYPE); match_everything(MAT_EXIT_PARENTS); mat = match_result(); if (Good_obj(mat) && !Controls(player, mat)) { return NOTHING; } else { return (mat); } }