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);
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
* 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;
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)
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;
}
strcpy(name, AL_NAME(atr));
}
- global_parent_depth[0] = parent_depth;
return NULL;
}
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,