Add lattrp()
authorAri Johnson <ari@theari.com>
Wed, 14 Oct 2015 15:40:37 +0000 (11:40 -0400)
committerAri Johnson <ari@theari.com>
Wed, 14 Oct 2015 15:40:37 +0000 (11:40 -0400)
game/txt/hlp/cobra_func.hlp
hdrs/attrib.h
src/attrib.c
src/function.c
src/fundb.c

index 01415f3fc574faf71849e66ff8c6d9beefd69073..be7e0457be0e1c0084d254062550b225aa23ad43 100644 (file)
@@ -1870,7 +1870,9 @@ Continued in HELP ITER2
 
   See also: first(), rest()
 & LATTR()
+& LATTRP()
   lattr(<object>[/<attribute pattern>])
+  lattrp(<object>[/<attribute pattern>])
  
   Returns a space-separated list of the attribute names on the object.
   You must either be a Wizard or Royalty, own the object, have the
@@ -1881,6 +1883,8 @@ Continued in HELP ITER2
   matching that pattern will be returned. lattr() uses the same
   wildcards as examine (?, *, **).
 
+  lattrp() also include attributes inherited from parents.
+
   See also: nattr(), examine
 & NATTR()
 & ATTRCNT()
index 82168a2238b0ae24dd8f5fc76ef77ec8c8cccfd7..9c4a98f4d41dba8158958ce386d76a3d8e3d1412 100644 (file)
@@ -57,6 +57,8 @@ extern ATTR *atr_get_noparent(dbref thing, char const *atr);
 typedef int (*aig_func) (dbref, dbref, dbref, const char *, ATTR *, void *);
 extern int atr_iter_get(dbref player, dbref thing, char const *name,
                        int mortal, aig_func func, void *args);
+extern int atr_iter_get_parent(dbref player, dbref thing, char const *name,
+                              int mortal, aig_func func, void *args);
 extern ATTR *atr_complete_match(dbref player, char const *atr, dbref privs);
 extern void atr_free(dbref thing);
 extern void atr_cpy(dbref dest, dbref source);
index 5de4d77072a821117692349310aaf5b99bfc371b..eb3b8619bfe591566485190589ef374036e51218 100644 (file)
@@ -84,6 +84,8 @@ typedef struct atrpage {
 static ATTR *atr_free_list;
 static ATTR *get_atr_free_list(void);
 static ATTR *find_atr_pos_in_list(ATTR *** pos, char const *name);
+static ATTR *atr_get_with_parent(dbref obj, char const *atrname, dbref *parent,
+                                int cmd);
 static int can_create_attr(dbref player, dbref obj, char const *atr_name,
                            int flags);
 static ATTR *find_atr_in_list(ATTR * atr, char const *name);
@@ -783,6 +785,20 @@ atr_clr(dbref thing, char const *atr, dbref player)
   return 1;
 }
 
+/** Wrapper for atr_get_with_parent()
+ * \verbatim
+ * Get an attribute from an object, checking its parents/ancestor if
+ * the object does not have the attribute itself. Return a pointer to
+ * the attribute structure (not its value), or NULL if the attr is
+ * not found.
+ * \endverbatim
+ */
+ATTR *
+atr_get(dbref obj, char const *atrname)
+{
+  return atr_get_with_parent(obj, atrname, NULL, 0);
+}
+
 /** Retrieve an attribute from an object or its ancestors.
  * This function retrieves an attribute from an object, or from its
  * parent chain, returning a pointer to the first attribute that
@@ -791,10 +807,13 @@ atr_clr(dbref thing, char const *atr, dbref player)
  * through atr_value() or safe_atr_value().
  * \param obj the object containing the attribute.
  * \param atrname the name of the attribute.
+ * \param parent if non-NULL, a dbref pointer to be set to the dbref of
+ *              the object the attr was found on
+ * \param cmd return NULL for no_command attributes?
  * \return pointer to the attribute structure retrieved, or NULL.
  */
-ATTR *
-atr_get(dbref obj, char const *atrname)
+static ATTR *
+atr_get_with_parent(dbref obj, char const *atrname, dbref *parent, int cmd)
 {
   static char name[ATTRIBUTE_NAME_LIMIT + 1];
   char *p;
@@ -803,20 +822,18 @@ atr_get(dbref obj, char const *atrname)
   dbref target;
   dbref ancestor;
 
-  global_parent_depth[0] = 0;
-  global_parent_depth[1] = NOTHING;
   if (obj == NOTHING || !good_atr_name(atrname))
     return NULL;
 
   /* First try given name, then try alias match. */
   strcpy(name, atrname);
   for (;;) {
-    /* Hunt through the parents/ancestor chain... */
+    /* Hunt through the parents/ancestors chain... */
     ancestor = Ancestor_Parent(obj);
     target = obj;
     parent_depth = 0;
     while (parent_depth < MAX_PARENTS && GoodObject(target)) {
-      /* If the ancestor of the object is in its explict parent chain,
+      /* If the ancestor of the object is in its explicit parent chain,
        * we use it there, and don't check the ancestor later.
        */
       if (target == ancestor)
@@ -824,24 +841,34 @@ atr_get(dbref obj, char const *atrname)
       atr = List(target);
 
       /* If we're looking at a parent/ancestor, then we
-       * need to check the branch path for privacy... */
-      if (target != obj) {
+       * need to check the branch path for privacy. We also
+       * need to check the branch path if we're looking for no_command */
+      if (target != obj || cmd) {
         for (p = strchr(name, '`'); p; p = strchr(p + 1, '`')) {
           *p = '\0';
           atr = find_atr_in_list(atr, name);
-          if (!atr || AF_Private(atr)) {
-            *p = '`';
+          *p = '`';
+          if (!atr)
             goto continue_target;
+          else if (target != obj && AF_Private(atr)) {
+            /* Can't inherit the attr or branches */
+            return NULL;
+          } else if (cmd && AF_Noprog(atr)) {
+            /* Can't run commands in attr or branches */
+            return NULL;
           }
-          *p = '`';
         }
       }
 
-      /* Now actually find the attribute. */
+      /* Now actually find the attribute */
       atr = find_atr_in_list(atr, name);
-      global_parent_depth[1] = atr_on_obj = target;
-      if (atr && (target == obj || !AF_Private(atr))) {
-        global_parent_depth[0] = parent_depth;
+      if (atr) {
+        if (target != obj && AF_Private(atr))
+          return NULL;
+        if (cmd && AF_Noprog(atr))
+          return NULL;
+        if (parent)
+          *parent = target;
         return atr;
       }
 
@@ -862,7 +889,6 @@ atr_get(dbref obj, char const *atrname)
     strcpy(name, AL_NAME(atr));
   }
 
-  global_parent_depth[0] = parent_depth;
   return NULL;
 }
 
@@ -950,6 +976,88 @@ atr_iter_get(dbref player, dbref thing, const char *name, int mortal,
   return result;
 }
 
+/** Apply a function to a set of attributes, including inherited ones.
+ * This function applies another function to a set of attributes on an
+ * object specified by a (wildcarded) pattern to match against the
+ * attribute name on an object or its parents.
+ * \param player the enactor.
+ * \param thing the object containing the attribute.
+ * \param name the pattern to match against the attribute name.
+ * \param mortal only fetch mortal-visible attributes?
+ * \param func the function to call for each matching attribute.
+ * \param args additional arguments to pass to the function.
+ * \return the sum of the return values of the functions called.
+ */
+int
+atr_iter_get_parent(dbref player, dbref thing, const char *name, int mortal,
+                   aig_func func, void *args)
+{
+  ATTR *ptr, *lastbranch, **indirect;
+  int result;
+  int len;
+  dbref parent = NOTHING;
+
+  result = 0;
+  if (!name || !*name)
+    name = "*";
+  len = strlen(name);
+
+  if (!wildcard(name) && name[len - 1] != '`') {
+    ptr = atr_get_with_parent(thing, strupper(name), &parent, 0);
+    if (ptr && (mortal ? Is_Visible_Attr(parent, ptr)
+                : Can_Read_Attr(player, parent, ptr)))
+      result = func(player, thing, parent, name, ptr, args);
+  } else {
+    StrTree seen;
+    int parent_depth;
+    st_init(&seen);
+    for (parent_depth = MAX_PARENTS + 1, parent = thing;
+        parent_depth-- && parent != NOTHING; parent = Parent(parent)) {
+      ptr = NULL;
+      lastbranch = List(parent);
+      for (indirect = &List(parent); *indirect; indirect = &AL_NEXT(ptr)) {
+        ptr = *indirect;
+        if (!strchr(AL_NAME(ptr), '`'))
+          lastbranch = ptr;
+        if (!st_find(AL_NAME(ptr), &seen)) {
+          st_insert(AL_NAME(ptr), &seen);
+          if (parent != thing) {
+            if (AF_Private(ptr))
+              continue;
+            if (strchr(AL_NAME(ptr), '`')) {
+              /* We need to check all the branchs of the tree for no_inherit */
+              char bname[BUFFER_LEN];
+              char *p;
+              ATTR *branch;
+              int skip = 0;
+
+              strcpy(bname, AL_NAME(ptr));
+              for (p = strchr(bname, '`'); p; p = strchr(p + 1, '`')) {
+                *p = '\0';
+                branch = find_atr_in_list(lastbranch, bname);
+                *p = '`';
+                if (branch && AF_Private(branch)) {
+                  skip = 1;
+                  break;
+                }
+              }
+              if (skip)
+                continue;
+            }
+          }
+          if ((mortal ? Is_Visible_Attr(parent, ptr)
+              : Can_Read_Attr(player, parent, ptr))
+             && atr_wild(name, AL_NAME(ptr)))
+            result += func(player, thing, parent, name, ptr, args);
+        }
+      }
+    }
+    st_flush(&seen);
+  }
+
+  return result;
+}
+
 /** Free the memory associated with all attributes of an object.
  * This function frees all of an object's attribute memory.
  * This includes the memory allocated to hold the attribute's value,
index 0b70bd3c0526c510760d1452f6dca752de4c5941..92b9b96cf928a8d0bb7f51aa801d6aca8fb63e71 100644 (file)
@@ -439,6 +439,7 @@ FUNTAB flist[] = {
   {"ITEXT", fun_itext, 1, 1, FN_REG},
   {"LAST", fun_last, 1, 2, FN_REG},
   {"LATTR", fun_lattr, 1, 1, FN_REG},
+  {"LATTRP", fun_lattr, 1, 1, FN_REG},
   {"LCON", fun_dbwalker, 1, 1, FN_REG},
   {"LCSTR", fun_lcstr, 1, -1, FN_REG},
   {"LDELETE", fun_ldelete, 2, 3, FN_REG},
index 01ed05109809a47619600d52ccb7afd7f5e5e068..d25821a87eb1b3a9cda5a3f60a9cc2e068705a07 100644 (file)
@@ -102,6 +102,7 @@ lattr_helper(dbref player __attribute__ ((__unused__)),
 FUNCTION(fun_ooref) {
        safe_dbref(ooref, buff, bp);
 }
+
 /* ARGSUSED */
 FUNCTION(fun_lattr)
 {
@@ -113,21 +114,26 @@ FUNCTION(fun_lattr)
   if (pattern)
     *pattern++ = '\0';
   else
-    pattern = (char *) "*";    /* match anything */
+    pattern = (char *) "*";
 
   thing = match_thing(executor, args[0]);
   if (!GoodObject(thing)) {
     safe_str(T(e_notvis), buff, bp);
     return;
   }
-  if (!Can_Examine(executor, thing)) {
-    safe_str(T(e_perm), buff, bp);
-    return;
-  }
   lh.first = 1;
   lh.buff = buff;
   lh.bp = bp;
-  (void) atr_iter_get(executor, thing, pattern, 0, lattr_helper, &lh);
+
+  if (strchr(called_as, 'P')) {
+    (void) atr_iter_get_parent(executor, thing, pattern,
+                              !Can_Examine(executor, thing),
+                              lattr_helper, &lh);
+  } else {
+    (void) atr_iter_get(executor, thing, pattern,
+                       !Can_Examine(executor, thing), lattr_helper,
+                       &lh);
+  }
 }
 
 /* ARGSUSED */