+/**
+ * \file attrib.h
+ *
+ * \brief Attribute-related prototypes and constants.
+ */
+
#ifndef _ATTRIB_H
#define _ATTRIB_H
struct attr {
char const *name; /**< Name of attribute */
- int flags; /**< Attribute flags */
+ unsigned int flags; /**< Attribute flags */
chunk_reference_t data; /**< The attribute's value, compressed */
dbref creator; /**< The attribute's creator's dbref */
boolexp write_lock; /**< Attribute lock set */
extern void do_attribute_lock(dbref player, char *name, char *lock, switch_mask swi);
/* From attrib.c */
+
+/** atr_add(), atr_clr() error codes */
+typedef enum {
+ AE_OKAY = 0, /**< Success */
+ AE_ERROR = -1, /**< general failure */
+ AE_SAFE = -2, /**< attempt to overwrite a safe attribute */
+ AE_BADNAME = -3, /**< invalid name */
+ AE_TOOMANY = -4, /**< too many attribs */
+ AE_TREE = -5, /**< unable to delete/create entire tree */
+ AE_NOTFOUND = -6 /** No such attribute */
+} atr_err;
+
extern int good_atr_name(char const *s);
extern ATTR *atr_match(char const *string);
extern ATTR *atr_sub_branch(ATTR *branch);
extern void atr_new_add(dbref thing, char const *RESTRICT atr,
- char const *RESTRICT s, dbref player, int flags,
+ char const *RESTRICT s, dbref player, unsigned int flags,
unsigned char derefs, boolexp wlock, boolexp rlock,
time_t modtime);
-extern int atr_add(dbref thing, char const *RESTRICT atr,
- char const *RESTRICT s, dbref player, int flags);
-extern int atr_clr(dbref thing, char const *atr, dbref player);
+extern atr_err atr_add(dbref thing, char const *RESTRICT atr,
+ char const *RESTRICT s, dbref player, unsigned int flags);
+extern atr_err atr_clr(dbref thing, char const *atr, dbref player);
+extern atr_err wipe_atr(dbref thing, char const *atr, dbref player);
extern ATTR *atr_get(dbref thing, char const *atr);
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 ATTR *atr_complete_match(dbref player, char const *atr, dbref privs);
-extern void atr_free(dbref thing);
+extern void atr_free_all(dbref thing);
extern void atr_cpy(dbref dest, dbref source);
extern char const *convert_atr(int oldatr);
extern int atr_comm_match(dbref thing, dbref player, int type, int end,
extern int one_comm_match(dbref thing, dbref player, const char *atr,
const char *str);
extern int do_set_atr(dbref thing, char const *RESTRICT atr,
- char const *RESTRICT s, dbref player, int flags);
+ char const *RESTRICT s, dbref player, unsigned int flags);
extern void do_atrlock(dbref player, char const *arg1, char const *arg2, char write_lock);
extern void do_atrchown(dbref player, char const *arg1, char const *arg2);
extern int string_to_atrflag(dbref player, const char *p);
/* possible attribute flags */
+#define AF_EMPTY_FLAGS 0x0 /**< No flag at all */
#define AF_ODARK 0x1 /* OBSOLETE! Leave here but don't use */
#define AF_INTERNAL 0x2 /* no one can see it or set it */
#define AF_PRIVILEGE 0x4 /* Only privileged players can change it */
#define AF_REGEXP 0x400 /* Match $/^ patterns using regexps */
#define AF_CASE 0x800 /* Match $/^ patterns case-sensitive */
#define AF_SAFE 0x1000 /* This attribute may not be modified */
-#define AF_STATIC 0x10000 /* OBSOLETE! Leave here but don't use */
+#define AF_ROOT 0x10000 /* Root of an attribute tree */
#define AF_COMMAND 0x20000 /* INTERNAL: value starts with $ */
#define AF_LISTEN 0x40000 /* INTERNAL: value starts with ^ */
#define AF_NODUMP 0x80000 /* INTERNAL: attribute is not saved */
#define AF_PUBLIC 0x2000000 /* Override SAFER_UFUN */
#define AF_ANON 0x4000000 /* INTERNAL: Attribute doesn't exist in the database */
#define AF_POWINHERIT 0x8000000 /* Execute with powers of object it's on */
+#define AF_NONAME 0x10000000 /**< No name in did_it */
#define AF_MHEAR 0x20000000 /* ^-listens can be triggered by %! */
#define AF_AHEAR 0x40000000 /* ^-listens can be triggered by anyone */
+#define AF_NOSPACE 0x80000000 /**< No space in did_it */
+
+#define AF_MAXVAL 0x100000000 /**< Largest attribute flag value. */
+
+/*** external predefined attributes. */
+ extern ATTR attr[];
+
/* external predefined attributes. */
extern ATTR attr[];
#define AL_RLock(alist) ((alist)->read_lock)
#define AL_MODTIME(alist) ((alist)->last_modified)
-/* Errors from ok_player_alias */
-#define OPAE_SUCCESS 1
-#define OPAE_INVALID -1
-#define OPAE_TOOMANY -2
-#define OPAE_NULL -3
+/** Errors from ok_player_alias */
+/** Success */
+#define OPAE_SUCCESS 1
+/** Invalid alias */
+#define OPAE_INVALID -1
+/** Too many aliases already set */
+#define OPAE_TOOMANY -2
+/** Null alias */
+#define OPAE_NULL -3
#endif /* __ATTRIB_H */
-/* This must be first, otherwise dbref will be undefined */
-#include "mushtype.h"
+/* Must be included after mushtype.h to get dbref typedef */
#ifndef _CHUNK_H_
#define _CHUNK_H_
{"nearby", 'n', AF_NEARBY, AF_NEARBY},
{"amhear", 'M', AF_MHEAR, AF_MHEAR},
{"aahear", 'A', AF_AHEAR, AF_AHEAR},
+ {"root", '`', AF_ROOT, AF_ROOT},
{NULL, '\0', 0, 0}
};
#pragma warning( disable : 4761) /* disable warning re conversion */
#endif
-/** Attribute error - too many attribs */
-#define AE_TOOMANY -4
-/** Attribute error - invalid name */
-#define AE_BADNAME -3
-/** Attribute error - attempt to overwrite a safe attribute */
-#define AE_SAFE -2
-/** Attribute error - general failure */
-#define AE_ERROR -1
-
/* Catchall Attribute any non-standard attributes will conform to this */
ATTR *catchall;
extern PRIV attr_privs_view[];
dbref atr_on_obj = NOTHING;
-/** A flag to show if we're in the middle of a @wipe (this changes
- * behaviour for atr_clr()). Yes, this is gross and ugly, but it
- * seemed like a better idea than propogating signature changes
- * for atr_clr() and do_set_atr() through the entire codebase. If
- * you come up with a better way, PLEASE fix this...
- */
-int we_are_wiping;
+static int real_atr_clr(dbref thinking, char const *atr, dbref player,
+ int we_are_wiping);
+
dbref global_parent_depth[] = { 0, 0 };
ATTR atrs[ATTRS_PER_PAGE]; /**< Array of attribute structures */
} ATTRPAGE;
-static ATTR *atr_free_list;
-static ATTR *get_atr_free_list(void);
+static int atr_clear_children(dbref player, dbref thing, ATTR *root);
+static ATTR *atr_free_list = NULL;
+static ATTR *alloc_atr(void);
+static ATTR *pop_free_list(void);
+static void push_free_list(ATTR *);
+static void atr_free_one(ATTR *);
static ATTR *find_atr_pos_in_list(ATTR *** pos, char const *name);
+static atr_err can_create_attr(dbref player, dbref obj, char const *atr_name,
+ unsigned int flags);
static int can_create_attr(dbref player, dbref obj, char const *atr_name,
- int flags);
+ unsigned int flags);
static ATTR *find_atr_in_list(ATTR * atr, char const *name);
/** Utility define for can_write_attr_internal and can_create_attr.
return NULL;
}
-/** Find the place to insert/delete an attribute with the specified name.
+/** Find the place to insert an attribute with the specified name.
* \param pos a pointer to the ATTR ** holding the list position
* \param name the attribute name to look for
* \return the matching attribute, or NULL if no matching attribute
lock_owner = AL_CREATOR(std); \
ns_chk = 0; \
} else { \
- if (flags != NOTHING) \
- AL_FLAGS(atr) |= flags; \
+ AL_FLAGS(atr) = flags; \
AL_WLock(atr) = AL_RLock(atr) = TRUE_BOOLEXP; \
lock_owner = NOTHING; \
ns_chk = 1; \
* \param player the player trying to do the write.
* \param obj the object targetted for the write.
* \param atr the attribute being interrogated.
- * \param flags the default flags to add to the attribute.
+ * \param flags the default flags to add to the attribute.
+ * 0 for default flags if it's a builtin attribute.
* \retval 0 if the player cannot write the attribute.
* \retval 1 if the player can write the attribute.
*/
static int
-can_create_attr(dbref player, dbref obj, char const *atr_name, int flags)
+can_create_attr(dbref player, dbref obj, char const *atr_name,
+ unsigned int flags)
{
char *p;
ATTR tmpatr, *atr;
return AE_TOOMANY;
}
- return 1;
+ return AE_OKAY;
}
/*======================================================================*/
return NULL;
/* allocate a new page, if needed */
- ptr = get_atr_free_list();
- atr_free_list = AL_NEXT(ptr);
+ ptr = pop_free_list();
+ if (ptr == NULL) {
+ st_delete(name, &atr_names);
+ return NULL;
+ }
/* initialize atr */
AL_WLock(ptr) = TRUE_BOOLEXP;
*/
void
atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
- dbref player, int flags, unsigned char derefs, boolexp wlock,
+ dbref player, unsigned int flags, unsigned char derefs, boolexp wlock,
boolexp rlock, time_t modtime)
{
ATTR *ptr;
boolexp lock;
+ dbref lock_owner;
+ int ns_chk;
+ char *p, root_name[ATTRIBUTE_NAME_LIMIT + 1];
if (!EMPTY_ATTRS && !*s)
return;
if((lock = dup_bool(rlock)))
AL_RLock(ptr) = lock;
- AL_FLAGS(ptr) = (flags != NOTHING) ? flags : 0;
+ strcpy(root_name, atr);
+ if ((p = strrchr(root_name, '`'))) {
+ ATTR *root = NULL;
+ *p = '\0';
+ root = find_atr_in_list(List(thing), root_name);
+ if (!root) {
+ do_rawlog(LT_ERR, T("Missing root attribute '%s' on object #%d!\n"),
+ root_name, thing);
+ root = create_atr(thing, root_name);
+ set_default_flags(root, 0, lock_owner, ns_chk);
+ if(lock_owner == NOTHING)
+ lock_owner = player;
+ AL_FLAGS(root) |= AF_ROOT;
+ AL_CREATOR(root) = player;
+ if (!EMPTY_ATTRS) {
+ unsigned char *t = compress(" ");
+ if (!t) {
+ mush_panic(T("Unable to allocate memory in atr_new_add()!"));
+ }
+ root->data = chunk_create(t, u_strlen(t), 0);
+ free(t);
+ }
+ } else {
+ if (!AL_FLAGS(root) & AF_ROOT) /* Upgrading old database */
+ AL_FLAGS(root) |= AF_ROOT;
+ }
+ }
+
+ AL_FLAGS(ptr) = flags;
AL_FLAGS(ptr) &= ~AF_COMMAND & ~AF_LISTEN;
AL_CREATOR(ptr) = ooref != NOTHING ? ooref : player;
unsigned char *t = compress(s);
if (!t)
return;
+
ptr->data = chunk_create(t, u_strlen(t), derefs);
free(t);
* \param atr name of the attribute to set.
* \param s value of the attribute to set.
* \param player the attribute creator.
- * \param flags bitmask of attribute flags for this attribute.
- * \retval AE_BADNAME invalid attribute name.
- * \retval AE_SAFE attempt to overwrite a SAFE attribute.
- * \retval AE_ERROR general failure.
- * \retval 1 success.
+ * \param flags bitmask of attribute flags for this attribute. 0 will use
+ * default.
+ * \return AE_OKAY or an AE_* error code.
*/
-int
+
+atr_err
atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
- dbref player, int flags)
+ dbref player, unsigned int flags)
{
- ATTR *ptr;
+ ATTR *ptr, *root = NULL;
dbref lock_owner; /* Not used.. but set in set_default_flags */
int ns_chk;
char *p;
/* make a new atr, if needed */
if (!ptr) {
- int res = can_create_attr(player, thing, atr, flags);
- if (res < 0) {
+ atr_err res = can_create_attr(player, thing, atr, flags);
+ if (res != AE_OKAY) {
ooref = tooref;
return res;
}
for (p = strchr(missing_name, '`'); p; p = strchr(p + 1, '`')) {
*p = '\0';
- ptr = find_atr_in_list(ptr, missing_name);
+ root = find_atr_in_list(ptr, missing_name);
- if (!ptr) {
- ptr = create_atr(thing, missing_name);
- if (!ptr) {
+ if (!root) {
+ root = create_atr(thing, missing_name);
+ if (!root) {
ooref = tooref;
- return AE_ERROR;
+ return AE_TREE;
}
/* update modification time here, because from now on,
set_lmod(thing, lmbuf);
}
- set_default_flags(ptr, flags, lock_owner, ns_chk);
- AL_FLAGS(ptr) &= ~AF_COMMAND & ~AF_LISTEN;
- AL_CREATOR(ptr) = ooref != NOTHING ? Owner(ooref) : Owner(player);
- AL_MODTIME(ptr) = mudtime;
+ set_default_flags(root, flags, lock_owner, ns_chk);
+ AL_FLAGS(root) &= ~AF_COMMAND & ~AF_LISTEN;
+ AL_FLAGS(root) |= AF_ROOT;
+ AL_CREATOR(root) = ooref != NOTHING ? Owner(ooref) : Owner(player);
+ AL_MODTIME(root) = mudtime;
if (!EMPTY_ATTRS) {
unsigned char *t = compress(" ");
if (!t) {
+ mush_panic(T("Unable to allocate memory in atr_add()!"));
ooref = tooref;
- return AE_ERROR;
}
- ptr->data = chunk_create(t, u_strlen(t), 0);
+ root->data = chunk_create(t, u_strlen(t), 0);
free(t);
}
- }
+ } else AL_FLAGS(root) |= AF_ROOT;
*p = '`';
}
* \param thing object to clear attribute from.
* \param atr name of attribute to remove.
* \param player enactor attempting to remove attribute.
- * \retval 0 no attribute found to reset
- * \retval AE_SAFE attribute is safe
- * \retval AE_ERROR other failure
+ * \param we_are_wiping true if called by \@wipe.
+ * \return AE_OKAY or AE_* error code.
*/
-int
-atr_clr(dbref thing, char const *atr, dbref player)
+static atr_err
+real_atr_clr(dbref thing, char const *atr, dbref player, int we_are_wiping)
{
- ATTR *ptr, **prev, *sub;
- size_t len;
+ ATTR *ptr, **prev;
+ int can_clear = 1;
tooref = ooref;
if (player == GOD)
if (!ptr) {
ooref = tooref;
- return 0;
+ return AE_NOTFOUND;
}
if (ptr && AF_Safe(ptr)) {
return AE_ERROR;
}
- sub = atr_sub_branch(ptr);
- if (!we_are_wiping && sub) {
+ if ((AL_FLAGS(ptr) & AF_ROOT) && !we_are_wiping) {
ooref = tooref;
- return AE_ERROR;
- }
-
- if (!IsPlayer(thing) && !AF_Nodump(ptr)) {
- char lmbuf[1024];
- ModTime(thing) = mudtime;
- snprintf(lmbuf, 1023, "%s[#%d]", ptr->name, player);
- lmbuf[strlen(lmbuf) + 1] = '\0';
- set_lmod(thing, lmbuf);
+ return AE_TREE;
}
- *prev = AL_NEXT(ptr);
+ /* We only hit this if wiping. */
+ if (AL_FLAGS(ptr) & AF_ROOT)
+ can_clear = atr_clear_children(player, thing, ptr);
- if (ptr->data)
- chunk_delete(ptr->data);
+ if (can_clear) {
+ char *p;
+ char root_name[ATTRIBUTE_NAME_LIMIT + 1];
- len = strlen(AL_NAME(ptr));
- st_delete(AL_NAME(ptr), &atr_names);
+ strcpy(root_name, AL_NAME(ptr));
- free_atr_locks(ptr);
-
- AL_NEXT(ptr) = atr_free_list;
- AL_FLAGS(ptr) = 0;
- atr_free_list = ptr;
- AttrCount(thing)--;
-
- if (we_are_wiping && sub) {
- while (*prev != sub)
- prev = &AL_NEXT(*prev);
- ptr = *prev;
- while (ptr && strlen(AL_NAME(ptr)) > len && AL_NAME(ptr)[len] == '`') {
- *prev = AL_NEXT(ptr);
-
- if (ptr->data)
- chunk_delete(ptr->data);
- st_delete(AL_NAME(ptr), &atr_names);
-
- AL_NEXT(ptr) = atr_free_list;
- AL_FLAGS(ptr) = 0;
- atr_free_list = ptr;
- AttrCount(thing)--;
-
- ptr = *prev;
- }
- }
- ooref = tooref;
- return 1;
+ if (!IsPlayer(thing) && !AF_Nodump(ptr))
+ ModTime(thing) = mudtime;
+ *prev = AL_NEXT(ptr);
+ atr_free_one(ptr);
+ AttrCount(thing)--;
+
+ /* If this was the only leaf of a tree, clear the AF_ROOT flag from
+ * the parent. */
+ if ((p = strrchr(root_name, '`'))) {
+ ATTR *root;
+ *p = '\0';
+
+ root = find_atr_in_list(List(thing), root_name);
+ *p = '`';
+
+ if (!root) {
+ do_rawlog(LT_ERR, T("Attribute %s on object #%d lacks a parent!"),
+ root_name, thing);
+ } else {
+ if (!atr_sub_branch(root))
+ AL_FLAGS(root) &= ~AF_ROOT;
+ }
+ }
+
+ return AE_OKAY;
+ } else
+ return AE_TREE;
}
-/** Retrieve an attribute from an object or its ancestors.
+/* Remove an attribute from an object.
+ * This function clears an attribute from an object.
+ * Permission is denied if the attribute is a branch, not a leaf.
+ * \param thing object to clear attribute from.
+ * \param atr name of attribute to remove.
+ * \param player enactor attempting to remove attribute.
+ * \return AE_OKAY or an AE_* error code
+ */
+atr_err
+atr_clr(dbref thing, char const *atr, dbref player)
+{
+ return real_atr_clr(thing, atr, player, 0);
+}
+
+
+/* \@wipe an attribute (And any leaves) from an object.
+ * This function clears an attribute from an object.
+ * \param thing object to clear attribute from.
+ * \param atr name of attribute to remove.
+ * \param player enactor attempting to remove attribute.
+ * \return AE_OKAY or an AE_* error code.
+ */
+atr_err
+wipe_atr(dbref thing, char const *atr, dbref player)
+{
+ return real_atr_clr(thing, atr, player, 1);
+}
+
+ /** 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
* matches or NULL. This is a pointer to an attribute structure, not
* \param thing dbref of object
*/
void
-atr_free(dbref thing)
+atr_free_all(dbref thing)
{
ATTR *ptr;
while ((ptr = List(thing))) {
List(thing) = AL_NEXT(ptr);
- if (AL_WLock(ptr) != TRUE_BOOLEXP)
- free_boolexp(AL_WLock(ptr));
- if (AL_RLock(ptr) != TRUE_BOOLEXP)
- free_boolexp(AL_RLock(ptr));
-
- if (ptr->data)
- chunk_delete(ptr->data);
- st_delete(AL_NAME(ptr), &atr_names);
-
- AL_NEXT(ptr) = atr_free_list;
- atr_free_list = ptr;
+ atr_free_one(ptr);
}
}
*/
int
do_set_atr(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
- dbref player, int flags)
+ dbref player, unsigned int flags)
{
ATTR *old;
char name[BUFFER_LEN];
char tbuf1[BUFFER_LEN];
- int res;
+ atr_err res;
int was_hearer;
int was_listener;
dbref contents;
s ? atr_add(thing, name, s, player,
(flags & 0x02) ? AF_NOPROG : NOTHING)
: atr_clr(thing, name, player);
- if (res == AE_SAFE) {
+ switch (res) {
+ case AE_SAFE:
notify_format(player, T("Attribute %s is SAFE. Set it !SAFE to modify it."),
name);
return 0;
- } else if (res == AE_BADNAME) {
- notify(player, T("That's not a very good name for an attribute."));
+ case AE_TREE:
+ if (!s) {
+ notify_format(player,
+ T("Unable to remove '%s' because of a protected tree attribute."),
+ name);
+ return 0;
+ } else {
+ notify_format(player,
+ T("Unable to set '%s' because of a failure to create a needed parent attribute."), name);
+ return 0;
+ }
+ case AE_BADNAME:
+ notify_format(player, T("That's not a very good name for an attribute."));
return 0;
- } else if (res == AE_ERROR) {
+ case AE_ERROR:
if (*missing_name) {
if (s && (EMPTY_ATTRS || *s))
notify_format(player, T("You must set %s first."), missing_name);
} else
notify(player, T("That attribute cannot be changed by you."));
return 0;
- } else if (res == AE_TOOMANY) {
+ case AE_TOOMANY:
notify(player, T("Too many attributes on that object to add another."));
return 0;
- } else if (!res) {
+ case AE_NOTFOUND:
notify(player, T("No such attribute to reset."));
return 0;
+ case AE_OKAY:
+ /* Success */
+ break;
}
if (!strcmp(name, "ALIAS") && IsPlayer(thing)) {
reset_player_list(thing, NULL, tbuf1, NULL, s);
* \return the pointer to the head of the attribute free list.
*/
static ATTR *
-get_atr_free_list(void)
+alloc_atr(void)
{
if (!atr_free_list) {
ATTRPAGE *page;
int j;
page = (ATTRPAGE *) mush_malloc(sizeof(ATTRPAGE), "ATTRPAGE");
if (!page)
- mush_panic("Couldn't allocate memory in get_atr_free_list");
+ mush_panic("Couldn't allocate memory in alloc_attr");
for (j = 0; j < ATTRS_PER_PAGE - 1; j++)
AL_NEXT(page->atrs + j) = page->atrs + j + 1;
AL_NEXT(page->atrs + ATTRS_PER_PAGE - 1) = NULL;
*p = '`';
}
- return 1;
+ return AE_OKAY;
+}
+
+
+/** Remove all child attributes from root attribute that can be.
+ * \param player object doing a @wipe.
+ * \param thing object being @wiped.
+ * \param root root of attribute tree.
+ * \return 1 if all children were deleted, 0 if some were left.
+ */
+static int
+atr_clear_children(dbref player, dbref thing, ATTR *root)
+{
+ ATTR *sub, *next = NULL, *prev;
+ int skipped = 0;
+
+ prev = root;
+
+ for (sub = atr_sub_branch(root);
+ sub && string_prefix(AL_NAME(sub), AL_NAME(root)); sub = next) {
+ if (AL_FLAGS(sub) & AF_ROOT) {
+ if (!atr_clear_children(player, thing, sub)) {
+ skipped++;
+ next = AL_NEXT(sub);
+ prev = sub;
+ continue;
+ }
+ }
+
+ next = AL_NEXT(sub);
+
+ if (!Can_Write_Attr(player, thing, sub)) {
+ skipped++;
+ prev = sub;
+ continue;
+ }
+
+ /* Can safely delete attribute. */
+ AL_NEXT(prev) = next;
+ atr_free_one(sub);
+ AttrCount(thing)--;
+
+ }
+
+ return !skipped;
+
+}
+
+/** Pop an empty attribute off of the free list for use on
+ * an object.
+ * \return the pointer to an attribute, or NULL on error.
+ */
+static ATTR *
+pop_free_list(void)
+{
+ ATTR *ptr;
+ ptr = alloc_atr();
+ if (!ptr)
+ return NULL;
+ atr_free_list = AL_NEXT(ptr);
+ AL_NEXT(ptr) = NULL;
+ return ptr;
+}
+
+/** Push a now-unused attribute onto the free list
+ * \param An attribute that's been deleted from an object and
+ * had its chunk reference deleted.
+ */
+static void
+push_free_list(ATTR *a)
+{
+ memset(a, 0, sizeof(*a));
+ AL_NEXT(a) = atr_free_list;
+ atr_free_list = a;
+}
+
+/** Delete one attribute, deallocating its name and data.
+ * <strong>Does not update the owning object's attribute list or
+ * attribute count. That is the caller's responsibility.</strong>
+ *
+ * \param a the attribute to free
+ */
+static void
+atr_free_one(ATTR *a)
+{
+ if (!a)
+ return;
+
+ if (AL_WLock(a) != TRUE_BOOLEXP)
+ free_boolexp(AL_WLock(a));
+ if (AL_RLock(a) != TRUE_BOOLEXP)
+ free_boolexp(AL_RLock(a));
+
+ st_delete(AL_NAME(a), &atr_names);
+
+ if (a->data)
+ chunk_delete(a->data);
+
+ push_free_list(a);
}
/** Return the compressed data for an attribute.
snprintf(tbuf1, BUFFER_LEN-1, "%ld %ld %d %d", (mudtime - d->connected_at),
d->idle_total, d->unidle_times, d->cmds);
tbuf1[strlen(tbuf1)+1] = '\0';
- (void) atr_add(d->player, "LASTACTIVITY", tbuf1, GOD, NOTHING);
+ (void) atr_add(d->player, "LASTACTIVITY", tbuf1, GOD, 0);
announce_disconnect(d->player);
#ifdef USE_MAILER
do_mail_purge(d->player);
snprintf(tbuf1, BUFFER_LEN-1, "%ld %ld %d %d", (mudtime - d->connected_at),
d->idle_total , d->unidle_times, d->cmds);
tbuf1[strlen(tbuf1)+1] = '\0';
- (void) atr_add(d->player, "LASTACTIVITY", tbuf1, GOD, NOTHING);
+ (void) atr_add(d->player, "LASTACTIVITY", tbuf1, GOD, 0);
announce_disconnect(d->player);
#ifdef USE_MAILER
do_mail_purge(d->player);
(void) queue_attribute(obj, "ADISCONNECT", player);
}
clear_flag_internal(player, "CONNECTED");
- (void) atr_add(player, "LASTLOGOUT", show_time(mudtime, 0), GOD, NOTHING);
+ (void) atr_add(player, "LASTLOGOUT", show_time(mudtime, 0), GOD, 0);
} else {
/* note: when you partially disconnect, ADISCONNECTS are not executed */
sprintf(tbuf1, T("%s has partially disconnected."), Name(player));
snprintf(tbuf1, BUFFER_LEN-1, "%ld %ld %d %d", (mudtime - closed->connected_at),
closed->idle_total , closed->unidle_times, closed->cmds);
tbuf1[strlen(tbuf1)+1] = '\0';
- (void) atr_add(closed->player, "LASTACTIVITY", tbuf1, GOD, NOTHING);
+ (void) atr_add(closed->player, "LASTACTIVITY", tbuf1, GOD, 0);
announce_disconnect(closed->player);
mush_free(closed, "descriptor");
closed = nextclosed;
sep[1] = '\0';
arr2list(p_buf, cnt-1, tbuf, &tbp, sep);
/* Add the attribute back */
- (void) atr_add(player, "XYXX_DIVRCD", tbuf, GOD, NOTHING);
+ (void) atr_add(player, "XYXX_DIVRCD", tbuf, GOD, 0);
}
} else {
notify(player, "Must specify what player you wish to @su into.");
static int
add_to(dbref player, int am)
{
- return (add_to_generic(player, am, "QUEUE", NOTHING));
+ return (add_to_generic(player, am, "QUEUE", 0));
}
static int
for (i = 0; i < db_top; i++) {
set_name(i, NULL);
set_lmod(i, NULL);
- atr_free(i);
+ atr_free_all(i);
free_locks(Locks(i));
}
}
*q++ = '\0';
flags = atoi(q);
- /* Remove obsolete AF_NUKED flag and AF_STATIC, just in case */
+ /* Remove obsolete AF_NUKED flag just in case */
flags &= ~AF_NUKED;
- flags &= ~AF_STATIC;
if (!(indb_flags & DBF_AF_VISUAL)) {
/* Remove AF_ODARK flag. If it wasn't there, set AF_VISUAL */
if (!(flags & AF_ODARK))
}
/* chomp chomp */
- atr_free(thing);
+ atr_free_all(thing);
List(thing) = NULL;
/* don't eat name otherwise examine will crash */
else
close = args[6];
+
switch (*string) {
case ':':
- safe_str(Name(speaker), buff, bp);
+ safe_str(accented_name(speaker), buff, bp);
string++;
if (*string == ' ') {
/* semipose it instead */
break;
case ';':
string++;
- safe_str(Name(speaker), buff, bp);
+ safe_str(accented_name(speaker), buff, bp);
if (*string == ' ') {
/* pose it instead */
safe_chr(' ', buff, bp);
if (!transform || (!say && !strstr(string, open))) {
/* nice and easy */
if (say)
- safe_format(buff, bp, "%s %s \"%s\"", Name(speaker), say_string, string);
+ safe_format(buff, bp, "%s %s \"%s\"", accented_name(speaker),
+ say_string, string);
else
safe_str(string, buff, bp);
LEAVE_OOREF;
return;
}
if (strlen(rbuff) > 0) {
- safe_format(buff, bp, "%s %s %s", Name(speaker), say_string, rbuff);
+ safe_format(buff, bp, "%s %s %s", accented_name(speaker), say_string, rbuff);
LEAVE_OOREF;
return;
} else if (null == 1) {
int delete = 0;
if (say) {
- safe_str(Name(speaker), buff, bp);
+ safe_str(accented_name(speaker), buff, bp);
safe_chr(' ', buff, bp);
safe_str(say_string, buff, bp);
safe_chr(' ', buff, bp);
#include "externs.h"
#include "parse.h"
#include "dbdefs.h"
+#include "attrib.h"
#include "log.h"
#include "match.h"
#include "attrib.h"
*bp = '\0';
if (flags & DOL_MAP) {
/* if we're doing a @map, copy the list to an attribute */
- (void) atr_add(player, "MAPLIST", outbuf, GOD, NOTHING);
+ (void) atr_add(player, "MAPLIST", outbuf, GOD, 0);
notify(player, T("Function mapped onto list."));
}
if (flags & DOL_NOTIFY) {
#include "command.h"
#include "parse.h"
#include "privtab.h"
-#include "confmagic.h"
#include "log.h"
+#include "case.h"
+#include "confmagic.h"
+
static void look_exits(dbref player, dbref loc, const char *exit_name);
static void look_contents(dbref player, dbref loc, const char *contents_name);
!strcmp(AL_NAME(atr), "DESCRIBE") && !strcmp(pattern, "*"))
return 0;
strcpy(fbuf, privs_to_letters(attr_privs_view, AL_FLAGS(atr)));
- if (atr_sub_branch(atr))
- strcat(fbuf, "`");
if (AF_Veiled(atr)) {
if (ShowAnsi(player))
notify_format(player,
!strcmp(AL_NAME(atr), "DESCRIBE") && !strcmp(pattern, "*"))
return 0;
strcpy(fbuf, privs_to_letters(attr_privs_view, AL_FLAGS(atr)));
- if (atr_sub_branch(atr))
- strcat(fbuf, "`");
r = safe_atr_value(atr);
if (ShowAnsi(player))
notify_format(player,
}
/* If background color, change the letter to a capital. */
if (*(ptr - 1) == '4')
- ansi_letter = toupper(ansi_letter);
+ ansi_letter = UPCASE(ansi_letter);
safe_chr(ansi_letter, value, &s);
}
/* No "else" here: If a two-digit code
if (dh->skipdef && ptr) {
/* Standard attribute. Get the default perms, if any. */
/* Are we different? If so, do as usual */
- int npmflags = AL_FLAGS(ptr) & (~AF_PREFIXMATCH);
+ unsigned int npmflags = AL_FLAGS(ptr) & (~AF_PREFIXMATCH);
if (AL_FLAGS(atr) != AL_FLAGS(ptr) && AL_FLAGS(atr) != npmflags)
privs = privs_to_string(attr_privs_view, AL_FLAGS(atr));
} else {
char *bp;
a = atr_get_noparent(leader, "FOLLOWERS");
if (!a) {
- (void) atr_add(leader, "FOLLOWERS", unparse_dbref(follower), GOD, NOTHING);
+ (void) atr_add(leader, "FOLLOWERS", unparse_dbref(follower), GOD, 0);
} else {
bp = tbuf1;
safe_str(atr_value(a), tbuf1, &bp);
safe_chr(' ', tbuf1, &bp);
safe_dbref(follower, tbuf1, &bp);
*bp = '\0';
- (void) atr_add(leader, "FOLLOWERS", tbuf1, GOD, NOTHING);
+ (void) atr_add(leader, "FOLLOWERS", tbuf1, GOD, 0);
}
}
char *bp;
a = atr_get_noparent(follower, "FOLLOWING");
if (!a) {
- (void) atr_add(follower, "FOLLOWING", unparse_dbref(leader), GOD, NOTHING);
+ (void) atr_add(follower, "FOLLOWING", unparse_dbref(leader), GOD, 0);
} else {
bp = tbuf1;
safe_str(atr_value(a), tbuf1, &bp);
safe_chr(' ', tbuf1, &bp);
safe_dbref(leader, tbuf1, &bp);
*bp = '\0';
- (void) atr_add(follower, "FOLLOWING", tbuf1, GOD, NOTHING);
+ (void) atr_add(follower, "FOLLOWING", tbuf1, GOD, 0);
}
}
/* Let's take it apart and put it back together w/o follower */
strcpy(flwr, unparse_dbref(follower));
strcpy(tbuf1, atr_value(a));
- (void) atr_add(leader, "FOLLOWERS",
- remove_word(tbuf1, flwr, ' '), GOD, NOTHING);
+ (void) atr_add(leader, "FOLLOWERS", remove_word(tbuf1, flwr, ' '), GOD, 0);
}
/* Delete someone from a player's FOLLOWING attribute */
/* Let's take it apart and put it back together w/o leader */
strcpy(ldr, unparse_dbref(leader));
strcpy(tbuf1, atr_value(a));
- (void) atr_add(follower, "FOLLOWING",
- remove_word(tbuf1, ldr, ' '), GOD, NOTHING);
+ (void) atr_add(follower, "FOLLOWING", remove_word(tbuf1, ldr, ' '), GOD, 0);
}
static void
return 0;
}
/* Something worked. Change password to SHS-encrypted */
- (void) atr_add(player, pword_attr, passwd, GOD, NOTHING);
+ (void) atr_add(player, pword_attr, passwd, GOD, 0);
}
free(saved);
return 1;
copy_flag_bitmask("FLAG", Flags(gst_id), flags);
}
mush_free((Malloc_t) guest_name, "gst_buf");
- atr_add(gst_id, "DESCRIBE", GUEST_DESCRIBE, gst_id, NOTHING);
+ atr_add(gst_id, "DESCRIBE", GUEST_DESCRIBE, gst_id, 0);
SLEVEL(gst_id) = LEVEL_GUEST;
Home(gst_id) = options.guest_start;
reserve_fd();
/* Ok, all's well, make a player */
player = make_player(name, passwd, host, ip);
- (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, NOTHING);
+ (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, 0);
SLEVEL(player) = LEVEL_UNREGISTERED;
powergroup_db_set(NOTHING, player, PLAYER_DEF_POWERGROUP, 1);
return player;
set_initial_warnings(player);
/* Modtime tracks login failures */
ModTime(player) = (time_t) 0;
- (void) atr_add(player, "XYXXY", mush_crypt(password), GOD, NOTHING);
+ (void) atr_add(player, "XYXXY", mush_crypt(password), GOD, 0);
giveto(player, START_BONUS); /* starting bonus */
- (void) atr_add(player, "LAST", show_time(mudtime, 0), GOD, NOTHING);
- (void) atr_add(player, "LASTSITE", host, GOD, NOTHING);
+ (void) atr_add(player, "LAST", show_time(mudtime, 0), GOD, 0);
+ (void) atr_add(player, "LASTSITE", host, GOD, 0);
(void) atr_add(player, "LASTIP", ip, GOD, NOTHING);
- (void) atr_add(player, "LASTFAILED", " ", GOD, NOTHING);
+ (void) atr_add(player, "LASTFAILED", " ", GOD, 0);
sprintf(temp, "%d", START_QUOTA);
- (void) atr_add(player, "RQUOTA", temp, GOD, NOTHING);
+ (void) atr_add(player, "RQUOTA", temp, GOD, 0);
(void) atr_add(player, "ICLOC", EMPTY_ATTRS ? "" : " ", GOD,
AF_MDARK | AF_PRIVATE | AF_NOCOPY);
#ifdef USE_MAILER
} else if (!ok_password(newobj)) {
notify(player, T("Bad new password."));
} else {
- (void) atr_add(player, "XYXXY", mush_crypt(newobj), GOD, NOTHING);
+ (void) atr_add(player, "XYXXY", mush_crypt(newobj), GOD, 0);
notify(player, T("You have changed your password."));
}
}
*/
/* set the new attributes */
- (void) atr_add(player, "LAST", s, GOD, NOTHING);
+ (void) atr_add(player, "LAST", s, GOD, 0);
if(!has_flag_by_name(player, "WEIRDSITE", TYPE_PLAYER)) {
- (void) atr_add(player, "LASTSITE", host, GOD, NOTHING);
- (void) atr_add(player, "LASTIP", ip, GOD, NOTHING);
+ (void) atr_add(player, "LASTSITE", host, GOD, 0);
+ (void) atr_add(player, "LASTIP", ip, GOD, 0);
}
- (void) atr_add(player, "LASTFAILED", " ", GOD, NOTHING);
+ (void) atr_add(player, "LASTFAILED", " ", GOD, 0);
}
bp = last_place;
safe_format(last_place, &bp, T("%s on %s"), host, show_time(mudtime, 0));
*bp = '\0';
- (void) atr_add(player, "LASTFAILED", last_place, GOD, NOTHING);
+ (void) atr_add(player, "LASTFAILED", last_place, GOD, 0);
}
#include <stdlib.h>
#include "copyrite.h"
-
#include "conf.h"
#include "externs.h"
#include "mushdb.h"
#include "dbdefs.h"
+#include "attrib.h"
#include "flags.h"
#include "attrib.h"
#include "htab.h"
int res;
if ((res = queue_attribute(thing, awhat, player)))
(void) atr_add(thing, "CHARGES", tprintf("%d", num - 1),
- Owner(b->creator), NOTHING);
+ Owner(b->creator), 0);
return res;
} else {
/* no charges left, try to execute runout */
- return queue_attribute(thing, "RUNOUT", player);
+ return queue_attribute(thing, "RUNOUT", 0);
}
}
}
else
limit = owned;
- (void) atr_add(IsDivision(who) ? who : Owner(who), "RQUOTA", tprintf("%d", limit), GOD, NOTHING);
+ (void) atr_add(IsDivision(who) ? who : Owner(who), "RQUOTA", tprintf("%d", limit), GOD, 0);
return limit;
}
return;
(void) atr_add(Owner(who), "RQUOTA",
- tprintf("%d", get_current_quota(who) + payment), GOD, NOTHING);
+ tprintf("%d", get_current_quota(who) + payment), GOD, 0);
/* Check If Division Quota has to be adjusted now */
if(GoodObject(Division(who)) && !NoQuota(Division(who)))
(void) atr_add(Division(who), "RQUOTA",
- tprintf("%d", get_current_quota(Division(who)) + payment), GOD, NOTHING);
+ tprintf("%d", get_current_quota(Division(who)) + payment), GOD, 0);
}
* attributes using this command and wildcards. Wiping a specific
* attr still works, though.
*/
+ int saved_count = AttrCount(thing);
+
if (wildcard(pattern) && (AL_FLAGS(atr) & AF_PRIVILEGE) && !Director(player))
return 0;
- return do_set_atr(thing, AL_NAME(atr), NULL, player, 0) == 1;
+ switch (wipe_atr(thing, AL_NAME(atr), player)) {
+ case AE_SAFE:
+ notify_format(player, T("Attribute %s is SAFE. Set it !SAFE to modify it."),
+ AL_NAME(atr));
+ return 0;
+ case AE_ERROR:
+ notify_format(player, T("Unable to wipe attribute %s"), AL_NAME(atr));
+ return 0;
+ case AE_TREE:
+ notify_format(player,
+ T("Attribute %s cannot be wiped because a child attribute cannot be wiped."),
+ AL_NAME(atr));
+ /* Fall through */
+ default:
+ return saved_count - AttrCount(thing);
+ }
}
/** Clear an attribute.
{
dbref thing;
char *pattern;
+ int wiped;
if ((pattern = strchr(name, '/')) != NULL)
*pattern++ = '\0';
return;
}
- we_are_wiping = 1;
-
- if (!atr_iter_get(player, thing, pattern, 0, wipe_helper, NULL))
+ switch ((wiped = atr_iter_get(player, thing, pattern, 0, wipe_helper, NULL))) {
+ case 0:
notify(player, T("No attributes wiped."));
- else
- notify(player, T("Attributes wiped."));
-
- we_are_wiping = 0;
+ break;
+ case 1:
+ notify(player, T("One attribute wiped."));
+ break;
+ default:
+ notify_format(player, T("%d attributes wiped."), wiped);
+ }
}
}
*tp = '\0';
*tp2 = '\0';
- (void) atr_add(player, "LASTPAGED", tbuf, GOD, NOTHING);
+ (void) atr_add(player, "LASTPAGED", tbuf, GOD, 0);
/* Reset tbuf to use later */
tp = tbuf;
#include "game.h"
#include "help.h"
#include "parse.h"
+#include "attrib.h"
#include "confmagic.h"
static char buf[BUFFER_LEN], *bp;
static char tbuf1[BUFFER_LEN];
char *p;
- int got_nameformat = 0;
couldunparse = 0;
if (!(GoodObject(loc) || (loc == NOTHING) || (loc == AMBIGUOUS) ||
/* Don't let 'em get dbrefs when they're IC */
if ((Can_Examine(player, loc) || can_link_to(player, loc) ||
JumpOk(loc) || ChownOk(loc) || DestOk(loc)) &&
- (!Myopic(player) || !obey_myopic) &&
- !(use_nameformat && got_nameformat)
- ) {
+ (!Myopic(player) || !obey_myopic)) {
/* show everything */
if (SUPPORT_PUEBLO)
couldunparse = 1;
bp = buf;
- if (ANSI_NAMES && ShowAnsi(player) && !got_nameformat)
+ if (ANSI_NAMES && ShowAnsi(player))
safe_format(buf, &bp, "%s%s%s(#%d%s)", ANSI_HILITE, tbuf1,
ANSI_NORMAL, loc, unparse_flags(loc, player));
else
*bp = '\0';
} else {
/* show only the name */
- if (ANSI_NAMES && ShowAnsi(player) && !got_nameformat) {
+ if (ANSI_NAMES && ShowAnsi(player)) {
bp = buf;
safe_format(buf, &bp, "%s%s%s", ANSI_HILITE, tbuf1, ANSI_NORMAL);
*bp = '\0';
limit = dlimit;
(void) atr_add(!IsDivision(who) ? Owner(who) : who, "RQUOTA", tprintf("%d", limit - owned), GOD,
- NOTHING);
+ 0);
notify_format(player, T("Objects: %d Limit: %d"), owned, limit);
}
}
if (limit != -1) {
if (limit <= owned) {
- (void) atr_add(who, "RQUOTA", "0", GOD, NOTHING);
+ (void) atr_add(who, "RQUOTA", "0", GOD, 0);
} else {
(void) atr_add(who, "RQUOTA", tprintf("%d", limit - owned), GOD,
- NOTHING);
+ 0);
}
}
}
notify(player, T("Bad password."));
} else {
/* it's ok, do it */
- (void) atr_add(victim, "XYXXY", mush_crypt(password), GOD, NOTHING);
+ (void) atr_add(victim, "XYXXY", mush_crypt(password), GOD, 0);
notify_format(player, T("Password for %s changed."), Name(victim));
notify_format(victim, T("Your password has been changed by %s."),
Name(player));
-#!/usr/local/bin/perl
+#!/usr/bin/env perl
#
# Generate game/txt/hlp/ files from the CHANGES file(s).
# Should be run by Makefile from top-level directory