PennMUSH Incorp 182p4..
authorRick Bird <nveid@bender.theari.com>
Fri, 25 Mar 2011 21:09:24 +0000 (17:09 -0400)
committerRick Bird <nveid@bender.theari.com>
Fri, 25 Mar 2011 21:09:24 +0000 (17:09 -0400)
  * Loading a db with empty attributes used as the roots of
    attribute trees didn't work if empty_attrs is set to no.
    Reported by Kevin. [SW]
  * Bugs in wiping attribute trees with attributes the wiper
    doesn't have permission to delete fixed. [SW]
  * @wipe reports the number of attributes deleted. [183]
  * speak() uses accented names. Sketch.

22 files changed:
hdrs/attrib.h
hdrs/chunk.h
src/atr_tab.c
src/attrib.c
src/bsd.c
src/cque.c
src/db.c
src/destroy.c
src/funstr.c
src/funtime.c
src/game.c
src/look.c
src/move.c
src/player.c
src/plyrlist.c
src/predicat.c
src/set.c
src/speech.c
src/timer.c
src/unparse.c
src/wiz.c
utils/mkvershlp.pl

index 82168a2238b0ae24dd8f5fc76ef77ec8c8cccfd7..a76bb83b783bdce22dcff0b8026b5eac0c181340 100644 (file)
@@ -1,3 +1,9 @@
+/**
+ * \file attrib.h
+ *
+ * \brief Attribute-related prototypes and constants.
+ */
+
 #ifndef _ATTRIB_H
 #define _ATTRIB_H
 
@@ -13,7 +19,7 @@
 
 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 */
@@ -42,23 +48,36 @@ extern void attr_init_postconfig(void);
 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,
@@ -70,7 +89,7 @@ extern int atr_comm_divmatch(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);
@@ -90,6 +109,7 @@ safe_atr_value(ATTR *atr)
 
 
 /* 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 */
@@ -103,7 +123,7 @@ safe_atr_value(ATTR *atr)
 #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 */
@@ -115,8 +135,16 @@ safe_atr_value(ATTR *atr)
 #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[];
@@ -135,10 +163,14 @@ safe_atr_value(ATTR *atr)
 #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 */
index 25fa8cfff7d02e117ab79dc647da4c8e43f490dc..9eb38e885c843bd017c5c4ae78e7b0a69153b027 100644 (file)
@@ -1,5 +1,4 @@
-/* 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_
 
index dbc9076e43ae9821cb2815dbd247d3408a073e04..72c915eb961d2463c01373c1d7abc9dcf9b5df72 100644 (file)
@@ -86,6 +86,7 @@ PRIV attr_privs_view[] = {
   {"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}
 };
 
index 1906b6b8a4449cef1a6b86527901336305617653..e261366774e5c385f72c61a51bd584ac0d9d0b80 100644 (file)
 #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;
 
@@ -52,13 +43,9 @@ extern PRIV attr_privs_set[];
 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 };
 
@@ -81,11 +68,17 @@ typedef struct atrpage {
   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.
@@ -264,7 +257,7 @@ find_atr_in_list(ATTR * atr, char const *name)
   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
@@ -358,8 +351,7 @@ atrflag_to_string(int mask)
       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; \
@@ -377,12 +369,14 @@ atrflag_to_string(int mask)
  * \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;
@@ -447,7 +441,7 @@ can_create_attr(dbref player, dbref obj, char const *atr_name, int flags)
     return AE_TOOMANY;
   }
 
-  return 1;
+  return AE_OKAY;
 }
 
 /*======================================================================*/
@@ -469,8 +463,11 @@ create_atr(dbref thing, char const *atr_name)
     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;
@@ -503,11 +500,14 @@ create_atr(dbref thing, char const *atr_name)
  */
 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;
@@ -527,7 +527,35 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
   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;
 
@@ -540,6 +568,7 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
     unsigned char *t = compress(s);
     if (!t)
       return;
+
     ptr->data = chunk_create(t, u_strlen(t), derefs);
     free(t);
 
@@ -560,17 +589,16 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
  * \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;
@@ -604,8 +632,8 @@ atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
 
   /* 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;
     }
@@ -615,13 +643,13 @@ atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
     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,
@@ -634,20 +662,21 @@ atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
           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 = '`';
     }
@@ -707,15 +736,14 @@ atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
  * \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)
@@ -726,7 +754,7 @@ atr_clr(dbref thing, char const *atr, dbref player)
 
   if (!ptr) {
     ooref = tooref;
-    return 0;
+    return AE_NOTFOUND;
   }
 
   if (ptr && AF_Safe(ptr)) {
@@ -738,59 +766,79 @@ atr_clr(dbref thing, char const *atr, dbref player)
     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
@@ -965,7 +1013,7 @@ atr_iter_get(dbref player, dbref thing, const char *name, int mortal,
  * \param thing dbref of object
  */
 void
-atr_free(dbref thing)
+atr_free_all(dbref thing)
 {
   ATTR *ptr;
 
@@ -982,17 +1030,7 @@ atr_free(dbref thing)
 
   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);
   }
 }
 
@@ -1740,12 +1778,12 @@ one_comm_match(dbref thing, dbref player, const char *atr, const char *str)
  */
 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;
@@ -1850,14 +1888,26 @@ do_set_atr(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
       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);
@@ -1869,12 +1919,15 @@ do_set_atr(dbref thing, const char *RESTRICT atr, const char *RESTRICT s,
     } 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);
@@ -2075,14 +2128,14 @@ do_atrchown(dbref player, const char *arg1, const char *arg2)
  * \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;
@@ -2272,7 +2325,105 @@ can_write_attr_internal(dbref player, dbref obj, ATTR * atr, int safe)
     *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.
index f2efb8bec601aa00ba64bcd1155098c884ff2ad8..085fa0190e20315672a31567e72a5a9eaecb2b0f 100644 (file)
--- a/src/bsd.c
+++ b/src/bsd.c
@@ -1468,7 +1468,7 @@ logout_sock(DESC *d)
     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);
@@ -1552,7 +1552,7 @@ shutdownsock(DESC *d)
       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);
@@ -3887,7 +3887,7 @@ announce_disconnect(dbref 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));
@@ -5323,7 +5323,7 @@ load_reboot_db(void)
     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;
@@ -5646,7 +5646,7 @@ COMMAND(cmd_su) {
        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.");
index 48e534353966351cd5c1425ef6860c113a0f77fb..c60d19379c44447d619af042866403c363afd169 100644 (file)
@@ -182,7 +182,7 @@ add_to_generic(dbref player, int am, const char *name, int flags)
 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
index b961e26ae67b9c95a4009fc6b60a41d2cc066b18..4be028ae1eac0346b80ccc2d61e296d8e34c5503 100644 (file)
--- a/src/db.c
+++ b/src/db.c
@@ -1247,7 +1247,7 @@ db_free(void)
     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));
     }
 
@@ -1294,9 +1294,8 @@ get_list(FILE * f, dbref 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))
index 0c23386b3475488af8ca285190a1bb64c33d9b35..67db9a8575e5cbab5e1629432d3f6bdff4b99a95 100644 (file)
@@ -704,7 +704,7 @@ free_object(dbref thing)
   }
 
   /* chomp chomp */
-  atr_free(thing);
+  atr_free_all(thing);
   List(thing) = NULL;
   /* don't eat name otherwise examine will crash */
 
index 52b05b02d3e43979465fca9d8b32517554ac61da..c4efed05099c6cd67034c263a6e75cbe931c1f0d 100644 (file)
@@ -2205,9 +2205,10 @@ FUNCTION(fun_speak)
   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 */
@@ -2218,7 +2219,7 @@ FUNCTION(fun_speak)
     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);
@@ -2240,7 +2241,8 @@ FUNCTION(fun_speak)
   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;
@@ -2258,7 +2260,7 @@ FUNCTION(fun_speak)
       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) {
@@ -2280,7 +2282,7 @@ FUNCTION(fun_speak)
     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);
index 518cf624f7439665a6861d490f499a7c10f33dc9..aa9bec5f7a21181310a4d3740058ac71cc7f6684 100644 (file)
@@ -20,6 +20,7 @@
 #include "externs.h"
 #include "parse.h"
 #include "dbdefs.h"
+#include "attrib.h"
 #include "log.h"
 #include "match.h"
 #include "attrib.h"
index 37d3db2f163e8d264c1446b6a3c973cc8ed52d19..005a52db7ac92b54ddeceb739938e593e1ea7706 100644 (file)
@@ -1954,7 +1954,7 @@ do_dolist(dbref player, char *list, char *command, dbref cause,
   *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) {
index d878328261a460189447cd4e8287d44a129fc86d..a563d60e171a194ed850a56ebd8300c8c9e370b3 100644 (file)
 #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);
@@ -344,8 +346,6 @@ look_helper_veiled(dbref player, dbref thing __attribute__ ((__unused__)),
       !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,
@@ -388,8 +388,6 @@ look_helper(dbref player, dbref thing __attribute__ ((__unused__)),
       !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,
@@ -1637,7 +1635,7 @@ decompose_str(char *what)
              }
              /* 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
@@ -1708,7 +1706,7 @@ decompile_helper(dbref player, dbref thing __attribute__ ((__unused__)),
     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 {
index d58e799152c88bc62e54a034dbf66cb10b97d855..65b9aedd37915ee11f014c86c2db6c2af72d1aa0 100644 (file)
@@ -1127,14 +1127,14 @@ add_follower(dbref leader, dbref follower)
   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);
   }
 }
 
@@ -1147,14 +1147,14 @@ add_following(dbref follower, dbref leader)
   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);
   }
 }
 
@@ -1186,8 +1186,7 @@ del_follower(dbref leader, dbref follower)
   /* 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 */
@@ -1203,8 +1202,7 @@ del_following(dbref follower, dbref leader)
   /* 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
index 112264dcc98f1c470eef407ab730c246c0ad1689..8206c07677d112f12be6220b750bf2b97770e866 100644 (file)
@@ -103,7 +103,7 @@ password_check(dbref player, const char *password)
        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;
@@ -223,7 +223,7 @@ dbref create_guest(const char *host, const char *ip) {
                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;
@@ -391,7 +391,7 @@ email_register_player(const char *name, const char *email, const char *host,
   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;
@@ -432,14 +432,14 @@ make_player(const char *name, const char *password, const char *host,
   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
@@ -503,7 +503,7 @@ do_password(dbref player, dbref cause, const char *old, const char *newobj)
   } 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."));
   }
 }
@@ -554,12 +554,12 @@ check_last(dbref player, const char *host, const char *ip)
    */
 
   /* 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);
 }
 
 
@@ -575,5 +575,5 @@ check_lastfailed(dbref player, const char *host)
   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);
 }
index 2f4b6c245c01c9c293c6895d401380a423edc895..75377aa6d4fd5a1ca0a4f2ca652dad1992e7466f 100644 (file)
 #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"
index 73ccee775dc34aaac32d87c00d9b2f036c572bf7..a9b4f46caddb976100abb8e58e5815e829a43ed1 100644 (file)
@@ -124,11 +124,11 @@ charge_action(dbref player, dbref thing, const char *awhat)
       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);
     }
   }
 }
@@ -639,7 +639,7 @@ get_current_quota(dbref who)
   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;
 }
@@ -657,13 +657,13 @@ change_quota(dbref who, int payment)
     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);
 
     
 }
index 214b2c952046a513140fde4b0de63672ce03d86d..6c89b1d168aae11f5de247e707e25b5444c88ac3 100644 (file)
--- a/src/set.c
+++ b/src/set.c
@@ -1084,9 +1084,26 @@ wipe_helper(dbref player, dbref thing, dbref parent __attribute__ ((__unused__))
    * 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.
@@ -1101,6 +1118,7 @@ do_wipe(dbref player, char *name)
 {
   dbref thing;
   char *pattern;
+  int wiped;
 
   if ((pattern = strchr(name, '/')) != NULL)
     *pattern++ = '\0';
@@ -1121,12 +1139,14 @@ do_wipe(dbref player, char *name)
     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);
+  }
 }
index a2e9fc068cdf8418b19e44ea63ec6ea70e40a88e..c24c41a42740fd361a635d9304b003d449bc0f5c 100644 (file)
@@ -849,7 +849,7 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause,
   }
   *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;
index 0d9ed7d306b65879e9b11ede4ee60a2eacdb6617..dd2bca8a2e6d58478289eb1e88682b6679f05fb4 100644 (file)
@@ -39,6 +39,7 @@
 #include "game.h"
 #include "help.h"
 #include "parse.h"
+#include "attrib.h"
 #include "confmagic.h"
 
 
index 59f2d9126f747b59132ff59ea97ea289ebbf96b2..62278bb53e3d9a539dc840cb192f0e4823e3b03c 100644 (file)
@@ -121,7 +121,6 @@ real_unparse(dbref player, dbref loc, int obey_myopic, int use_nameformat,
   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) ||
@@ -146,14 +145,12 @@ real_unparse(dbref player, dbref loc, int obey_myopic, int use_nameformat,
     /* 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
@@ -162,7 +159,7 @@ real_unparse(dbref player, dbref loc, int obey_myopic, int use_nameformat,
       *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';
index fa19335b0385326e558b327c02564818501feabd..5379258ae3280bbca4277f38f00dc0d0bb73b870 100644 (file)
--- a/src/wiz.c
+++ b/src/wiz.c
@@ -221,7 +221,7 @@ do_quota(dbref player, const char *arg1, const char *arg2, int set_q)
     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);
 }
@@ -284,10 +284,10 @@ do_allquota(dbref player, const char *arg1, int quiet)
     }
     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);
       }
     }
   }
@@ -811,7 +811,7 @@ do_newpassword(dbref player, dbref cause,
       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));
index 9ff7cc9ca0002f3f4583f6688531a11fe036e297..9326f0c30459e0376a4bfb84c3caadee4c71fbce 100755 (executable)
@@ -1,4 +1,4 @@
-#!/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