Author: talvo@talvo.com <talvo@talvo.com@ba372814-4f39-11de-9ad6-1127a62b9fcd>
authorRick L Bird <nveid@yahoo.com>
Sun, 15 May 2011 19:57:48 +0000 (15:57 -0400)
committerRick L Bird <nveid@yahoo.com>
Sun, 15 May 2011 19:57:48 +0000 (15:57 -0400)
Date:   Tue Jan 26 06:44:56 2010 +0000

    Issue 222, rewritten object matching routines in match.c
Fixes #172

hdrs/match.h
src/fundb.c
src/look.c
src/match.c
src/move.c
src/notify.c

index 26724ecbbb8bfaf3589032bec97e68ff878a96af..96a6905fe64f36fd1d94612ccc50784faacce4ee 100644 (file)
 #define MAT_NEIGHBOR     0x000100
 #define MAT_POSSESSION   0x000200
 #define MAT_EXIT         0x004000
+#define MAT_PMATCH       0x008000
   /* special things to match */
 #define MAT_CARRIED_EXIT     0x010000
 #define MAT_CONTAINER        0x020000
 #define MAT_REMOTE_CONTENTS  0x040000
 #define MAT_NEAR             0x080000
 #define MAT_ENGLISH          0x100000
-#define MAT_EXACT            0x200000 /* only match preferred type */
   /* types of match results - used internally */
 #define MAT_NOISY                0x1000000
 #define MAT_LAST                 0x2000000
+#define MAT_TYPE                 0x4000000 /* don't accept objects of other types */
   /* groups of things to match */
 #define MAT_EVERYTHING   (MAT_ME|MAT_HERE|MAT_ABSOLUTE|MAT_PLAYER| \
                           MAT_NEIGHBOR|MAT_POSSESSION|MAT_EXIT|MAT_ENGLISH)
  * last_match_result - returns a match or NOTHING
  * match_controlled - returns match if player controls, or NOTHING
  */
-extern dbref match_result
-  (const dbref who, const char *name, const int type, const long int flags);
+extern dbref
+match_result(dbref who, const char *xname, int type, long flags);
 extern dbref noisy_match_result
-  (const dbref who, const char *name, const int type, const long int flags);
+  (const dbref who, const char *name, const int type, const long flags);
 extern dbref last_match_result
-  (const dbref who, const char *name, const int type, const long int flags);
+  (const dbref who, const char *name, const int type, const long flags);
 extern dbref match_controlled(dbref player, const char *name);
 
 #define match_thing(player,name) \
index 4c34ea48b39322d63a4cdc8b2202465bd1ab4600..b6ce0a4a32fe4c2e367c548e5251d4c92e89808e 100644 (file)
@@ -1905,9 +1905,7 @@ FUNCTION(fun_locate)
   int pref_type;
   dbref item, loc;
   char *p;
-  int keys = 0;
   int ambig_ok = 0;
-  int force_type = 0;
   long match_flags = 0;
 
   /* find out what we're matching in relation to */
@@ -1916,7 +1914,7 @@ FUNCTION(fun_locate)
     safe_str("#-1", buff, bp);
     return;
   }
-  if (!CanSee(executor, looker) && !controls(executor, looker)) {
+  if (!See_All(executor) && !controls(executor, looker)) {
     safe_str("#-1", buff, bp);
     return;
   }
@@ -1940,14 +1938,11 @@ FUNCTION(fun_locate)
     case 'T':
       pref_type |= TYPE_THING;
       break;
-    case 'D':
-      pref_type |= TYPE_DIVISION;
-      break;
     case 'L':
-      keys = 1;
+      match_flags |= MAT_CHECK_KEYS;
       break;
     case 'F':
-      force_type = 1;
+      match_flags |= MAT_TYPE;
       break;
     case '*':
       match_flags |= MAT_EVERYTHING;
@@ -1976,6 +1971,9 @@ FUNCTION(fun_locate)
     case 'n':
       match_flags |= MAT_NEIGHBOR;
       break;
+    case 'y':
+      match_flags |= MAT_PMATCH;
+      break;
     case 'p':
       match_flags |= MAT_PLAYER;
       break;
@@ -1985,8 +1983,8 @@ FUNCTION(fun_locate)
     case 'X':
       ambig_ok = 1;             /* okay to pick last match */
       break;
-    case ' ':                  /* skip over spaces */
-      break;
+    case ' ':
+      break;                    /* skip over spaces */
     default:
       notify_format(executor, T("I don't understand switch '%c'."), *p);
       break;
@@ -1995,8 +1993,8 @@ FUNCTION(fun_locate)
   if (!pref_type)
     pref_type = NOTYPE;
 
-  if (keys)
-    match_flags = MAT_CHECK_KEYS;
+  if (!(match_flags & ~(MAT_CHECK_KEYS | MAT_TYPE)))
+    match_flags |= MAT_EVERYTHING;
 
   /* report the results */
   if (!ambig_ok)
@@ -2009,11 +2007,6 @@ FUNCTION(fun_locate)
     return;
   }
 
-  if (force_type && !(Typeof(item) & pref_type)) {
-    safe_dbref(NOTHING, buff, bp);
-    return;
-  }
-
   /* To locate it, you must either be able to examine its location
    * or be able to see the item.
    */
index 5bb9cce1d9a4ec90316fc13a90100884ff074e07..2b6d91a86c87523484ae33456cce410ee4d48e8d 100644 (file)
@@ -649,8 +649,7 @@ do_look_at(dbref player, const char *name, int key)
       return;
     }
     thing =
-      match_result(loc, name, NOTYPE,
-                   MAT_PLAYER | MAT_REMOTE_CONTENTS | MAT_EXIT | MAT_REMOTES);
+      match_result(loc, name,  NOTYPE, MAT_POSSESSION | MAT_CARRIED_EXIT);
     if (thing == NOTHING) {
       notify(player, T("I don't see that here."));
       return;
index ed4399c34b94175b4f711e3b3320a27c68874529..a41f52e739d13be52b67f8d7b1859fe7868db5c6 100644 (file)
@@ -32,6 +32,7 @@
  * MAT_CONTAINER        - match a container I'm in
  * MAT_REMOTE_CONTENTS  - match the contents of a remote location
  * MAT_ENGLISH          - match natural english 'my 2nd flower'
+ * MAT_TYPE             - match only objects of the given type(s)
  * MAT_EVERYTHING       - me,here,absolute,player,neighbor,possession,exit
  * MAT_NEARBY           - everything near
  * MAT_OBJECTS          - me,absolute,player,neigbor,possession
 #include "parse.h"
 #include "flags.h"
 #include "dbdefs.h"
+#include "confmagic.h"
+#include "attrib.h"
 
-static dbref match_result_internal
-  (dbref who, const char *name, int type, long flags);
-static dbref simple_matches(dbref who, const char *name, long flags);
 static int parse_english(char **name, long *flags);
-static dbref match_me(const dbref who, const char *name);
-static dbref match_here(const dbref who, const char *name);
-/** Convenience alias for parse_objid */
-#define match_absolute(name) parse_objid(name)
-static dbref match_player(const dbref matcher, const char *match_name);
-static dbref choose_thing(const dbref match_who, const int preferred_type,
-                          long int flags, dbref thing1, dbref thing2);
+static dbref match_player(dbref who, const char *name);
 extern int check_alias(const char *command, const char *list);  /* game.c */
+static int match_aliases(dbref who, const char *name);
+static dbref choose_thing(const dbref who, const int preferred_type, long flags, dbref thing1, dbref thing2);
 
-
-/** A wrapper for returning a match, AMBIGUOUS, or NOTHING.
- * This function attempts to match a name for who, and 
- * can return the matched dbref, AMBIGUOUS, or NOTHING.
- * \param who the looker.
- * \param name name to try to match.
- * \param type type of object to match.
- * \param flags match flags.
- * \return dbref of matched object, or AMBIGUOUS, or NOTHING.
- */
 dbref
-match_result(const dbref who, const char *name, const int type,
-             const long flags)
+noisy_match_result(const dbref who, const char *name, const int type, const long flags)
 {
-  return match_result_internal(who, name, type, flags);
-}
+  dbref match;
 
-/** A noisy wrapper for returning a match or NOTHING.
- * This function attempts to match a name for who, and 
- * can return the matched dbref or NOTHING (in ambiguous cases,
- * NOTHING is returned). If no match is made, the looker is notified
- * of the failure to match or ambiguity.
- * \param who the looker.
- * \param name name to try to match.
- * \param type type of object to match.
- * \param flags match flags.
- * \return dbref of matched object, or  NOTHING.
- */
-dbref
-noisy_match_result(const dbref who, const char *name, const int type,
-                   const long flags)
-{
-  return match_result_internal(who, name, type, flags | MAT_NOISY);
+  match = match_result(who, name, type, flags | MAT_NOISY);
+  if (!GoodObject(match))
+    return NOTHING;
+  else
+    return match;
 }
 
-/** A noisy wrapper for returning a match or NOTHING.
- * This function attempts to match a name for who, and 
- * can return the matched dbref or NOTHING. In ambiguous cases,
- * the last matched thing is returned.
- * \param who the looker.
- * \param name name to try to match.
- * \param type type of object to match.
- * \param flags match flags.
- * \return dbref of matched object, or  NOTHING.
- */
 dbref
-last_match_result(const dbref who, const char *name, const int type,
-                  const long flags)
+last_match_result(const dbref who, const char *name, const int type, const long flags)
 {
-  return match_result_internal(who, name, type, flags | MAT_LAST);
+  return match_result(who, name, type, flags | MAT_LAST);
 }
 
-/** Wrapper for a noisy match with control checks.
- * This function performs a noisy_match_result() and then checks that
- * the looker controls the matched object before returning it.
- * If the control check fails, the looker is notified and NOTHING
- * is returned.
- * \param player the looker.
- * \param name name to try to match.
- * \return dbref of matched controlled object, or NOTHING.
- */
 dbref
 match_controlled(dbref player, const char *name)
 {
-  dbref match;
-  match = noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING);
-  if (GoodObject(match) && !controls(player, match)) {
-    notify(player, T("Permission denied."));
-    return NOTHING;
-  } else {
-    return match;
-  }
+  return noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING | MAT_CONTROL);
 }
 
+
 /* The real work. Here's the spec:
  * str  --> "me"
  *      --> "here"
@@ -169,7 +116,7 @@ match_controlled(dbref player, const char *name)
  *  c. *player
  * 2. Parse for adj-phrases and restrict further matching and/or
  *    remember the object count
- * 3. Look for matches (remote contents, neighbor, inventory, exits, 
+ * 3. Look for matches (remote contents, neighbor, inventory, exits,
  *    containers, carried exits)
  *  a. If we don't have an object count, collect the number of exact
  *     and partial matches and the best partial match.
@@ -184,185 +131,331 @@ match_controlled(dbref player, const char *name)
  *  e. If we got no matches, complain
  */
 
-#define MATCH_NONE      0x0     /**< No matches were found */
-#define MATCH_EXACT     0x1     /**< At least one exact match found */
-#define MATCH_PARTIAL   0x2     /**< At least one partial match found, no exact */
-/** Prototype for matching functions */
-#define MATCH_FUNC_PROTO(fun_name) \
-  /* ARGSUSED */ /* try to keep lint happy */ \
-  static int fun_name(const dbref who, const char *name, const int type, \
-      const long flags, dbref first, \
-      dbref *match, int *exact_matches_to_go, int *matches_to_go)
-/** Common declaration for matching functions */
-#define MATCH_FUNC(fun_name) \
-  static int fun_name(const dbref who, const char *name, const int type, \
-      const long flags, dbref first __attribute__ ((__unused__)), \
-      dbref *match, int *exact_matches_to_go, int *matches_to_go)
-/** Macro to execute matching and store some results */
-#define RUN_MATCH_FUNC(fun,first) \
-   { \
-    result = fun(who, name, type, flags, first, &match, \
-          &exact_matches_to_go, &matches_to_go); \
-    if (result == MATCH_EXACT) { \
-      exact_match = match; \
-      /* If it's the nth exact match, we're done */ \
-      if (matchnum && !exact_matches_to_go) \
-        goto finished; \
-      /* If it's the n'th match, remember it */ \
-      if (matchnum && !matches_to_go) \
-        last_match = match; \
-    } else if (result == MATCH_PARTIAL) { \
-      if (!matchnum || !matches_to_go) \
-        last_match = match; \
+/*
+#define DEBUG_OBJECT_MATCHING
+/**/
+#ifdef DEBUG_OBJECT_MATCHING
+static dbref debugMatchTo = 1;
+#endif
+
+#define MATCHED(full) \
+  { \
+    if (!MATCH_CONTROLS) { \
+      /* Found a matching object, but we lack necessary control */ \
+      nocontrol = 1; \
+      continue; \
+    } \
+    if (!final) { \
+      bestmatch = BEST_MATCH; \
+      if (bestmatch != match) { \
+        /* Previously matched item won over due to type, @lock, etc, checks */ \
+        continue; \
+      } \
+      if (full) { \
+        if (exact) { \
+          /* Another exact match */ \
+          curr++; \
+        } else { \
+          /* Ignore any previous partial matches now we have an exact match */ \
+          exact = 1; \
+          curr = 1; \
+        } \
+      } else { \
+        /* Another partial match */ \
+        curr++; \
+      } \
+    } else { \
+      curr++; \
+      if (curr == final) { \
+        /* we've successfully found the Nth item */ \
+        bestmatch = match; \
+        done = 1; \
+        break; \
+      } \
+    } \
+  }
+
+
+#define MATCH_LIST(start) \
+  { \
+    if (done) \
+      break; /* already found the Nth object we needed */ \
+    match = start; \
+    DOLIST(match, match) { \
+      if (!MATCH_TYPE) { \
+        /* Exact-type match required, but failed */ \
+        continue; \
+      } else if (match == abs) { \
+        /* absolute dbref match in list */ \
+        MATCHED(1); \
+      } else if (!can_interact(match, who, INTERACT_MATCH)) { \
+        /* Not allowed to match this object */ \
+        continue; \
+      } else if (match_aliases(match, name) || (!IsExit(match) && !strcasecmp(Name(match), name))) { \
+        /* exact name match */ \
+        MATCHED(1); \
+      } else if ((!exact || !GoodObject(bestmatch)) && !IsExit(match) && string_match(Name(match), name)) { \
+        /* partial name match */ \
+        MATCHED(0); \
+      } \
     } \
-   }
+  }
+
+#define MATCH_CONTROLS (!(flags & MAT_CONTROL) || controls(who, match))
+
+#define MATCH_TYPE ((type & Typeof(match)) ? 1 : ((flags & MAT_TYPE) ? 0 : -1))
 
-MATCH_FUNC_PROTO(match_possession);
-MATCH_FUNC_PROTO(match_neighbor);
-MATCH_FUNC_PROTO(match_exit);
-MATCH_FUNC_PROTO(match_exit_internal);
-MATCH_FUNC_PROTO(match_container);
-MATCH_FUNC_PROTO(match_list);
+#define BEST_MATCH choose_thing(who, type, flags, bestmatch, match)
 
 static dbref
-match_result_internal(dbref who, const char *xname, int type, long flags)
+choose_thing(const dbref who, const int preferred_type, long flags, dbref thing1, dbref thing2)
 {
-  dbref match = NOTHING, last_match = NOTHING, exact_match = NOTHING;
-  int exact_matches_to_go, matches_to_go;
-  int matchnum = 0;
-  int result;
-  char *name, *sname;
+  int key;
+  /* If there's only one valid thing, return it */
+  /* Check == NOTHING, not GoodObject, to make sure we favour AMBIGUOUS over NOTHING */
+  /* (Apologies to Theodor Geisel) */
+  if (thing1 == NOTHING) {
+#ifdef DEBUG_OBJECT_MATCHING
+    notify_format(debugMatchTo,"Picking #%d over #%d (a nothing)", thing2, thing1);
+#endif
+    return thing2;
+  } else if (thing2 == NOTHING) {
+#ifdef DEBUG_OBJECT_MATCHING
+    notify_format(debugMatchTo,"Picking #%d over #%d (a nothing)", thing1, thing2);
+#endif
+    return thing1;
+  }
 
-  /* The quick ones that can never be ambiguous */
-  match = simple_matches(who, xname, flags);
-  if (GoodObject(match))
-    return match;
+  /* If a type is given, and only one thing is of that type, return it */
+  if (preferred_type != NOTYPE) {
+    if (Typeof(thing1) & preferred_type) {
+      if (!(Typeof(thing2) & preferred_type)) {
+#ifdef DEBUG_OBJECT_MATCHING
+      notify_format(debugMatchTo,"Picking #%d over #%d (type)", thing1, thing2);
+#endif
+        return thing1;
+      }
+    } else if (Typeof(thing2) & preferred_type) {
+#ifdef DEBUG_OBJECT_MATCHING
+    notify_format(debugMatchTo,"Picking #%d over #%d (type)", thing2, thing1);
+#endif
+      return thing2;
+    }
+  }
 
-  sname = name = mush_strdup(xname, "mri.string");
+  if (flags & MAT_CHECK_KEYS) {
+    key = could_doit(who, thing1);
+    if (!key && could_doit(who, thing2)) {
+#ifdef DEBUG_OBJECT_MATCHING
+      notify_format(debugMatchTo,"Picking #%d over #%d (unlocked)", thing2, thing1);
+#endif
+      return thing2;
+    } else if (key && !could_doit(who, thing2)) {
+#ifdef DEBUG_OBJECT_MATCHING
+      notify_format(debugMatchTo,"Picking #%d over #%d (unlocked)", thing1, thing2);
+#endif
+      return thing1;
+    }
+  }
+#ifdef DEBUG_OBJECT_MATCHING
+  notify_format(debugMatchTo,"Picking #%d over #%d (last matched)", thing2, thing1);
+#endif
+  /* No luck. Return last match */
+  return thing2;
+}
 
-  if (flags & MAT_ENGLISH) {
-    /* Check for adjective phrases */
-    matchnum = parse_english(&name, &flags);
+static dbref
+match_player(dbref who, const char *name) {
+  dbref match;
+
+  if (*name == LOOKUP_TOKEN) {
+    name++;
   }
 
-  /* Perform matching. We've already had flags restricted by any
-   * adjective phrases. If matchnum is set, collect the matchnum'th
-   * exact match (and stop) and the matchnum'th match (exact or partial, 
-   * and store this in case we don't get enough exact matches).
-   * If not, collect the number of exact and partial matches and the 
-   * last exact and partial matches.
-   */
-  exact_matches_to_go = matches_to_go = matchnum;
-  if (flags & MAT_POSSESSION)
-    RUN_MATCH_FUNC(match_possession, NOTHING);
-  if (flags & MAT_NEIGHBOR)
-    RUN_MATCH_FUNC(match_neighbor, NOTHING);
-  if (flags & MAT_REMOTE_CONTENTS)
-    RUN_MATCH_FUNC(match_possession, NOTHING);
-  if (flags & MAT_EXIT)
-    RUN_MATCH_FUNC(match_exit, NOTHING);
-  if (flags & MAT_CONTAINER)
-    RUN_MATCH_FUNC(match_container, NOTHING);
-  if (flags & MAT_CARRIED_EXIT)
-    RUN_MATCH_FUNC(match_exit_internal, who);
-
-finished:
-  /* Set up the default match_result behavior */
-  if (matchnum) {
-    /* nth exact match? */
-    if (!exact_matches_to_go)
-      match = exact_match;
-    else if (GoodObject(last_match))
-      match = last_match;       /* nth exact-or-partial match, or nothing? */
-    /* This shouldn't happen, but just in case we have a valid match,
-     * and an invalid last_match in the matchnum case, fall through and
-     * use the match.
-     */
-  } else if (GoodObject(exact_match)) {
-    /* How many exact matches? */
-    if (exact_matches_to_go == -1)
-      match = exact_match;      /* Good */
-    else if (flags & MAT_LAST)
-      match = exact_match;      /* Good enough */
-    else
-      match = AMBIGUOUS;
-  } else {
-    if (!matches_to_go)
-      match = NOTHING;          /* No matches */
-    else if (matches_to_go == -1)
-      match = last_match;       /* Good */
-    else if (flags & MAT_LAST)
-      match = last_match;       /* Good enough */
-    else
-      match = AMBIGUOUS;
+  while(isspace((unsigned char) *name)) {
+    name++;
   }
 
-  /* Handle noisy_match_result */
-  if (flags & MAT_NOISY) {
-    mush_free(sname, "mri.string");
-    switch (match) {
-    case NOTHING:
-      notify(who, T("I can't see that here."));
-      return NOTHING;
-    case AMBIGUOUS:
-      notify(who, T("I don't know which one you mean!"));
-      return NOTHING;
-    default:
-      return match;
+  match = lookup_player(name);
+  if (match != NOTHING) {
+    return match;
+  }
+  return visible_short_page(who, name);
+}
+
+static int
+match_aliases(dbref who, const char *name) {
+
+  if (!IsPlayer(who) && !IsExit(who)) {
+    return 0;
+  }
+
+  if (IsExit(who)) {
+    return check_alias(name, Name(who));
+  } else {
+    char tbuf1[BUFFER_LEN];
+    ATTR *a = atr_get_noparent(who, "ALIAS");
+    if (!a) {
+      return 0;
     }
+    mush_strncpy(tbuf1, atr_value(a), BUFFER_LEN);
+    return check_alias(name, tbuf1);
   }
-  mush_free(sname, "mri.string");
-  return match;
+
 }
 
-static dbref
-simple_matches(dbref who, const char *name, long flags)
+dbref
+match_result(dbref who, const char *xname, int type, long flags)
 {
-  dbref match = NOTHING;
-  if (flags & MAT_ME) {
-    match = match_me(who, name);
-    if (GoodObject(match))
-      return match;
+  dbref match, loc;
+  dbref bestmatch = NOTHING;
+  dbref abs = parse_objid(xname);
+  int curr = 0, final = 0, nocontrol = 0, exact = 0, done = 0;
+  int goodwho = GoodObject(who);
+  char *name, *sname;
+#ifdef DEBUG_OBJECT_MATCHING
+  debugMatchTo = (IsPlayer(who) ? who : 1);
+  notify(debugMatchTo, "ENTERING MATCH_RESULT");
+  notify_format(debugMatchTo, "FLAGS: %ld, TYPE: %d", flags, (type == NOTYPE));
+#endif
+  /* match "me" */
+  match = who;
+  if (MATCH_TYPE && (flags & MAT_ME) && !strcasecmp(xname, "me")) {
+    return match;
   }
-  if (flags & MAT_HERE) {
-    match = match_here(who, name);
-    if (GoodObject(match))
+
+  /* match "here" */
+  match = Location(who);
+  if ((flags & MAT_HERE) && !strcasecmp(xname, "here") && GoodObject(match) && MATCH_TYPE) {
+    if(MATCH_CONTROLS) {
       return match;
+    } else {
+      nocontrol = 1;
+    }
   }
-  if (!(flags & MAT_NEAR) || Long_Fingers(who)) {
-    if (flags & MAT_ABSOLUTE) {
-      match = match_absolute(name);
-      if (GoodObject(match) && (flags & MAT_NEAR) && !CanRemote(who, match))
-        goto mat_near;
-      if (GoodObject(match)) {
-       if (flags & MAT_CONTROL) {
-         /* Check for control */
-         if (controls(who, match) || nearby(who, match))
-           return match;
-       } else {
-         return match;
-       }
+
+  /* match *<player>, or <player> */
+  match = match_player(who, xname);
+  if (((flags & MAT_PMATCH) || ((flags & MAT_PLAYER) && *xname == LOOKUP_TOKEN)) && MATCH_TYPE) {
+    if (GoodObject(match)) {
+      if (MATCH_CONTROLS) {
+        return match;
+      } else {
+        nocontrol = 1;
       }
+    } else {
+      bestmatch = BEST_MATCH;
     }
-    if (flags & MAT_PLAYER) {
-      match = match_player(who, name);
-      if (GoodObject(match))
-       return match;
+  }
+
+  /* dbref match */
+  match = abs;
+  if (GoodObject(match) && MATCH_TYPE) {
+    if (!(flags & MAT_NEAR) || Long_Fingers(who) || (nearby(who, match) || controls(who, match))) {
+      /* valid dbref match */
+      if (MATCH_CONTROLS) {
+        return match;
+      } else {
+        nocontrol = 1;
+      }
     }
-  } else {
-    /* We're doing a nearby match and the player doesn't have
-     * long_fingers, so it's a controlled absolute
-     */
-mat_near:
-    match = match_absolute(name);
-    if (GoodObject(match) && (controls(who, match) || nearby(who, match)))
-      return match;
   }
-  return NOTHING;
+
+  sname = name = mush_strdup(xname, "mri.string");
+  if (flags & MAT_ENGLISH) {
+    /* English-style matching */
+    final = parse_english(&name, &flags);
+  }
+#ifdef DEBUG_OBJECT_MATCHING
+  notify_format(debugMatchTo, "AFTER ENGLISH, we have: name = %s, curr = %d, flags = %ld", name, curr, flags);
+#endif
+
+  while (1) {
+    loc = (goodwho ? (IsRoom(who) ? who : Location(who)) : NOTHING);
+#ifdef DEBUG_OBJECT_MATCHING
+    notify_format(debugMatchTo, "Running for #%d in #%d", who, loc);
+#endif
+    if (goodwho && ((flags & MAT_POSSESSION) || (flags & MAT_REMOTE_CONTENTS))) {
+#ifdef DEBUG_OBJECT_MATCHING
+      notify(debugMatchTo, "STARTING POSSESSION");
+#endif
+      MATCH_LIST(Contents(who));
+    }
+    if (GoodObject(loc) && (flags & MAT_NEIGHBOR)) {
+#ifdef DEBUG_OBJECT_MATCHING
+      notify(debugMatchTo, "STARTING NEIGHBOURS");
+#endif
+      MATCH_LIST(Contents(loc));
+    }
+    if ((type & TYPE_EXIT) || !(flags & MAT_TYPE)) {
+      if (GoodObject(loc) && IsRoom(loc) && (flags & MAT_EXIT)) {
+#ifdef DEBUG_OBJECT_MATCHING
+        notify_format(debugMatchTo, "STARTING EXIT");
+#endif
+        if (flags & MAT_REMOTES && GoodObject(Zone(loc)) && IsRoom(Zone(loc))) {
+#ifdef DEBUG_OBJECT_MATCHING
+          notify(debugMatchTo, "STARTING EXIT-REMOTE");
+#endif
+          MATCH_LIST(Exits(Zone(loc)));
+        }
+        if (flags & MAT_GLOBAL) {
+#ifdef DEBUG_OBJECT_MATCHING
+          notify(debugMatchTo, "STARTING EXIT-GLOBAL");
+#endif
+          MATCH_LIST(Exits(MASTER_ROOM));
+        }
+        if (GoodObject(loc) && IsRoom(loc)) {
+#ifdef DEBUG_OBJECT_MATCHING
+          notify(debugMatchTo, "STARTING EXITS");
+#endif
+          MATCH_LIST(Exits(loc));
+        }
+      }
+    }
+    if ((flags & MAT_CONTAINER) && goodwho) {
+#ifdef DEBUG_OBJECT_MATCHING
+      notify(debugMatchTo, "STARTING CONTAINER");
+#endif
+      MATCH_LIST(loc);
+    }
+    if ((type & TYPE_EXIT) || !(flags & MAT_TYPE)) {
+      if ((flags & MAT_CARRIED_EXIT) && goodwho && IsRoom(who)) {
+#ifdef DEBUG_OBJECT_MATCHING
+        notify_format(debugMatchTo, "STARTING CEXIT");
+#endif
+        MATCH_LIST(Exits(who));
+      }
+    }
+    break;
+  }
+#ifdef DEBUG_OBJECT_MATCHING
+  notify_format(debugMatchTo, "AT END, we have: final = %d, curr = %d, bestmatch = %d", final, curr, bestmatch);
+#endif
+  if (!GoodObject(bestmatch) && final) {
+    /* we never found the Nth item */
+    bestmatch = NOTHING;
+  } else if (!final && curr > 1) {
+    if (!(flags & MAT_LAST)) {
+      bestmatch = AMBIGUOUS;
+    }
+  }
+
+  if (!GoodObject(bestmatch) && (flags & MAT_NOISY)) {
+    /* give error message */
+    if (bestmatch == AMBIGUOUS) {
+      notify(who, T("I don't know which one you mean!"));
+    } else if (nocontrol) {
+      notify(who, T("Permission denied."));
+    } else {
+      notify(who, T("I can't see that here."));
+    }
+  }
+
+  return bestmatch;
 }
 
 
-/* 
+/*
  * adj-phrase --> adj
  *            --> adj count
  *            --> count
@@ -413,7 +506,7 @@ parse_english(char **name, long *flags)
   while (**name == ' ')
     (*name)++;
 
-  /* If the name was just 'toward' (with no object name), reset 
+  /* If the name was just 'toward' (with no object name), reset
    * everything and press on.
    */
   if (!**name) {
@@ -470,228 +563,3 @@ parse_english(char **name, long *flags)
   return count;
 }
 
-
-static dbref
-match_me(const dbref who, const char *name)
-{
-  return (!strcasecmp(name, "me")) ? who : NOTHING;
-}
-
-static dbref
-match_here(const dbref who, const char *name)
-{
-  return (!strcasecmp(name, "here") && GoodObject(Location(who))) ?
-    Location(who) : NOTHING;
-}
-
-
-static dbref
-match_player(const dbref matcher, const char *match_name)
-{
-  dbref match;
-  const char *p;
-
-  if (*match_name != LOOKUP_TOKEN)
-    return NOTHING;
-  for (p = match_name + 1; isspace((unsigned char) *p); p++) ;
-  /* If lookup_player fails, try a partial match on connected
-   * players, 2.0 style. That can return match, NOTHING, AMBIGUOUS
-   */
-  match = lookup_player(p);
-  return (match != NOTHING) ? match : visible_short_page(matcher, p);
-}
-
-/* Run down a contents list and try to match */
-MATCH_FUNC(match_list)
-{
-  dbref absolute;
-  dbref alias_match;
-  int match_type = MATCH_NONE;
-  int nth_match = (*exact_matches_to_go != 0);
-
-  /* If we were given an absolute dbref, remember it */
-  absolute = match_absolute(name);
-  /* If we were given a player name, remember it */
-  alias_match = lookup_player(name);
-
-  DOLIST(first, first) {
-    if (first == absolute) {
-      /* Got an absolute match, return it */
-      *match = first;
-      (*exact_matches_to_go)--;
-      (*matches_to_go)--;
-      return MATCH_EXACT;
-    } else if( can_interact(first, who, INTERACT_MATCH) && (!strcasecmp(Name(first), name) ||
-                           (GoodObject(alias_match) && (alias_match == first)))) {
-      /* An exact match, but there may be others */
-      (*exact_matches_to_go)--;
-      (*matches_to_go)--;
-      if (nth_match) {
-       if (!(*exact_matches_to_go)) {
-         /* We're done */
-         *match = first;
-         return MATCH_EXACT;
-       }
-      } else {
-       if (match_type == MATCH_EXACT)
-         *match = choose_thing(who, type, flags, *match, first);
-       else
-         *match = first;
-       match_type = MATCH_EXACT;
-      }
-    } else if ((match_type != MATCH_EXACT) 
-                   && string_match(Name(first), name)
-                   && can_interact(first, who, INTERACT_MATCH)) {
-      /* A partial match, and we haven't done an exact match yet */
-      (*matches_to_go)--;
-      if (nth_match) {
-       if (!(*matches_to_go))
-         *match = first;
-      } else if (match_type == MATCH_PARTIAL)
-       *match = choose_thing(who, type, flags, *match, first);
-      else
-       *match = first;
-      match_type = MATCH_PARTIAL;
-    }
-  }
-  /* If we've made the nth partial match in this round, there's none to go */
-  if (nth_match && *matches_to_go < 0)
-    *matches_to_go = 0;
-  return match_type;
-}
-
-/* We recursively search upwards trying to match exits */
-MATCH_FUNC(match_exit)
-{
-  dbref loc;
-  int mret = MATCH_NONE; /* FIXME: temporary workaround, see #250 */
-
-  loc = (IsRoom(who)) ? who : Location(who);
-  if (flags & MAT_REMOTES) {
-    if (GoodObject(loc))
-      return match_exit_internal(who, name, type, flags, Zone(loc),
-                                match, exact_matches_to_go, matches_to_go);
-    else
-      return NOTHING;
-  } else if (flags & MAT_GLOBAL)
-    return match_exit_internal(who, name, type, flags, MASTER_ROOM,
-                              match, exact_matches_to_go, matches_to_go);
-  /* Recursively search upwards in locations parent tree */
-  while(GoodObject(loc) && !IsGarbage(loc) && mret != MATCH_EXACT ) {
-    mret = match_exit_internal(who, name, type, flags, loc,
-                            match, exact_matches_to_go, matches_to_go);
-    loc = Parent(loc);
-  }
-  return mret;
-}
-
-MATCH_FUNC(match_exit_internal)
-{
-  dbref exit_tmp;
-  dbref absolute;
-  int match_type = MATCH_NONE;
-  int nth_match = (*exact_matches_to_go != 0);
-
-  if (!GoodObject(first) || !IsRoom(first) || !name || !*name)
-    return NOTHING;
-  /* Store an absolute dbref match if given */
-  absolute = match_absolute(name);
-  DOLIST(exit_tmp, Exits(first)) {
-
-    if ((exit_tmp == absolute) && (can_interact(exit_tmp, who, INTERACT_MATCH))) {
-      /* Absolute match. Return immediately */
-      *match = exit_tmp;
-      (*exact_matches_to_go)--;
-      (*matches_to_go)--;
-      return MATCH_EXACT;
-    } else if (check_alias(name, Name(exit_tmp))
-               && (can_interact(exit_tmp, who, INTERACT_MATCH))) {
-      /* Matched an exit alias, but there may be more */
-      (*exact_matches_to_go)--;
-      (*matches_to_go)--;
-      if (nth_match) {
-        if (!(*exact_matches_to_go)) {
-          /* We're done */
-          *match = exit_tmp;
-          return MATCH_EXACT;
-        }
-      } else {
-        if (match_type == MATCH_EXACT)
-          *match = choose_thing(who, type, flags, *match, exit_tmp);
-        else
-          *match = exit_tmp;
-        match_type = MATCH_EXACT;
-      }
-    }
-  }
-  /* If we've made the nth partial match in this round, there's none to go */
-  if (nth_match && *matches_to_go < 0)
-    *matches_to_go = 0;
-  return match_type;
-}
-
-
-MATCH_FUNC(match_possession)
-{
-  if (!GoodObject(who))
-    return NOTHING;
-  return match_list(who, name, type, flags, Contents(who), match,
-                    exact_matches_to_go, matches_to_go);
-}
-
-MATCH_FUNC(match_container)
-{
-  if (!GoodObject(who))
-    return NOTHING;
-  return match_list(who, name, type, flags, Location(who), match,
-                    exact_matches_to_go, matches_to_go);
-}
-
-MATCH_FUNC(match_neighbor)
-{
-  dbref loc;
-  if (!GoodObject(who))
-    return NOTHING;
-  loc = Location(who);
-  if (!GoodObject(loc))
-    return NOTHING;
-  return match_list(who, name, type, flags, Contents(loc), match,
-                    exact_matches_to_go, matches_to_go);
-}
-
-
-static dbref
-choose_thing(const dbref match_who, const int preferred_type, long flags,
-             dbref thing1, dbref thing2)
-{
-  int has1;
-  int has2;
-  /* If there's only one valid thing, return it */
-  /* (Apologies to Theodor Geisel) */
-  if (thing1 == NOTHING)
-    return thing2;
-  else if (thing2 == NOTHING)
-    return thing1;
-
-  /* If a type is given, and only one thing is of that type, return it */
-  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 we've asked for a basic lock check, and only one passes, use that */
-  if (flags & MAT_CHECK_KEYS) {
-    has1 = could_doit(match_who, thing1);
-    has2 = could_doit(match_who, thing2);
-    if (has1 && !has2)
-      return thing1;
-    else if (has2 && !has1)
-      return thing2;
-  }
-
-  /* No luck. Return the higher dbref */
-  return (thing1 > thing2 ? thing1 : thing2);
-}
index bd43cbc3e7c0c40af218cab633f698a103609376..8f2f1dff7cf565a94e2c570ba6e9095f2c172163 100644 (file)
@@ -534,14 +534,14 @@ do_get(dbref player, const char *what)
   dbref thing;
   char tbuf1[BUFFER_LEN], tbuf2[BUFFER_LEN], *tp;
   long match_flags =
-    MAT_NEIGHBOR | MAT_ABSOLUTE | MAT_CHECK_KEYS | MAT_NEAR | MAT_ENGLISH;
+    MAT_NEIGHBOR | MAT_CHECK_KEYS | MAT_NEAR | MAT_ENGLISH;
 
   if (!IsRoom(loc) && !EnterOk(loc) && !controls(player, loc)) {
     notify(player, T("Permission denied."));
     return;
   }
-  if (!Long_Fingers(player))
-    match_flags |= MAT_CONTROL;
+  if (Long_Fingers(player))
+    match_flags |= MAT_ABSOLUTE;
   if (match_result(player, what, TYPE_THING, match_flags) == NOTHING) {
     if (POSSESSIVE_GET) {
       dbref box;
@@ -671,7 +671,7 @@ do_drop(dbref player, const char *name)
     return;
   switch (thing =
           match_result(player, name, TYPE_THING,
-                       MAT_POSSESSION | MAT_ABSOLUTE | MAT_CONTROL |
+                       MAT_POSSESSION | MAT_ABSOLUTE |
                        MAT_ENGLISH)) {
   case NOTHING:
       notify(player, T("You don't have that!"));
index b873520c7d00cb7422ebd8afb2032661474973b9..273c10aeff385196015c5c41ab4c8097e01d88ca 100644 (file)
@@ -1190,7 +1190,6 @@ level_broadcast(dbref minlevel, const char *fmt, ...) {
   va_list args;
   char tbuf1[BUFFER_LEN];
   DESC *d;
-  int ok;
 
   va_start(args, fmt);
 #ifdef HAS_VSNPRINTF