From ff68f496e9aa7e996f5e8fe25e60e22be0fb682e Mon Sep 17 00:00:00 2001 From: Ari Johnson Date: Wed, 14 Oct 2015 11:40:37 -0400 Subject: [PATCH] Add lattrp() --- game/txt/hlp/cobra_func.hlp | 4 ++ hdrs/attrib.h | 2 + src/attrib.c | 140 +++++++++++++++++++++++++++++++----- src/function.c | 1 + src/fundb.c | 18 +++-- 5 files changed, 143 insertions(+), 22 deletions(-) diff --git a/game/txt/hlp/cobra_func.hlp b/game/txt/hlp/cobra_func.hlp index 01415f3..be7e045 100644 --- a/game/txt/hlp/cobra_func.hlp +++ b/game/txt/hlp/cobra_func.hlp @@ -1870,7 +1870,9 @@ Continued in HELP ITER2 See also: first(), rest() & LATTR() +& LATTRP() lattr([/]) + lattrp([/]) 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() diff --git a/hdrs/attrib.h b/hdrs/attrib.h index 82168a2..9c4a98f 100644 --- a/hdrs/attrib.h +++ b/hdrs/attrib.h @@ -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); diff --git a/src/attrib.c b/src/attrib.c index 5de4d77..eb3b861 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -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, diff --git a/src/function.c b/src/function.c index 0b70bd3..92b9b96 100644 --- a/src/function.c +++ b/src/function.c @@ -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}, diff --git a/src/fundb.c b/src/fundb.c index 01ed051..d25821a 100644 --- a/src/fundb.c +++ b/src/fundb.c @@ -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 */ -- 2.30.2