From: Ari Johnson <ari@cobramush.org>
Date: Wed, 21 Feb 2007 01:35:59 +0000 (+0000)
Subject: Setting and resetting multiple attribute flags at once is now more flexible
X-Git-Tag: 0.73~148
X-Git-Url: https://git.theari.com/?a=commitdiff_plain;h=e253e5209043da690ebd3be7ce43af33e6227bff;p=cobramush.git

Setting and resetting multiple attribute flags at once is now more flexible
---

diff --git a/hdrs/attrib.h b/hdrs/attrib.h
index 8d4c693..2bb35e4 100644
--- a/hdrs/attrib.h
+++ b/hdrs/attrib.h
@@ -72,6 +72,8 @@ extern int do_set_atr(dbref thing, char const *RESTRICT atr,
 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);
+extern int string_to_atrflagsets(dbref player, const char *p, int *setbits,
+				 int *clrbits);
 extern const char *atrflag_to_string(int mask);
 extern void init_atr_name_tree(void);
 
diff --git a/hdrs/privtab.h b/hdrs/privtab.h
index b068c93..6d0f9af 100644
--- a/hdrs/privtab.h
+++ b/hdrs/privtab.h
@@ -28,6 +28,8 @@ struct priv_info {
 #define PrivShowBits(x) ((x)->bits_to_show)
 
 extern int string_to_privs(PRIV *table, const char *str, long int origprivs);
+extern int string_to_privsets(PRIV *table, const char *str, int *setprivs,
+			      int *clrprivs);
 extern int letter_to_privs(PRIV *table, const char *str, long int origprivs);
 extern const char *privs_to_string(PRIV *table, int privs);
 extern const char *privs_to_letters(PRIV *table, int privs);
diff --git a/src/attrib.c b/src/attrib.c
index 5ca7050..287538a 100644
--- a/src/attrib.c
+++ b/src/attrib.c
@@ -295,6 +295,31 @@ string_to_atrflag(dbref player, char const *p)
   return f;
 }
 
+/** Convert a string of attribute flags to a pair of bitmasks.
+ * Given a space-separated string of attribute flags, look them up
+ * and return bitmasks of those to set or clear
+ * if player is permitted to use all of those flags.
+ * \param player the dbref to use for privilege checks.
+ * \param p a space-separated string of attribute flags.
+ * \param setbits pointer to address of bitmask to set.
+ * \param clrbits pointer to address of bitmask to clear.
+ * \return setbits or -1 on error.
+ */
+int
+string_to_atrflagsets(dbref player, char const *p, int *setbits, int *clrbits)
+{
+  int f;
+  *setbits = *clrbits = 0;
+  f = string_to_privsets(attr_privs, p, setbits, clrbits);
+  if (f <= 0)
+    return -1;
+  if (!Prived(player) && ((*setbits & AF_MDARK) || (*clrbits & AF_MDARK)))
+    return -1;
+  if (!See_All(player) && ((*setbits & AF_PRIVILEGE) || (*clrbits & AF_PRIVILEGE)))
+    return -1;
+  return *setbits;
+}
+
 /** Convert an attribute flag bitmask into a list of the full
  * names of the flags.
  * \param mask the bitmask of attribute flags to display.
diff --git a/src/privtab.c b/src/privtab.c
index c399a5e..5efcd58 100644
--- a/src/privtab.c
+++ b/src/privtab.c
@@ -68,6 +68,58 @@ string_to_privs(PRIV *table, const char *str, long int origprivs)
   return ((origprivs | yes) & ~no);
 }
 
+/** Convert a string to 2 sets of privilege bits, privs to set and
+ * privs to clear.
+ * \param table pointer to a privtab.
+ * \param str a space-separated string of privilege names to apply.
+ * \param setprivs pointer to address to store privileges to set.
+ * \param clrprivs pointer to address to store privileges to clear.
+ * \retval 1 string successfully parsed for bits with no errors.
+ * \retval 0 string contained no privs
+ * \retval -1 string at least one name matched no privs.
+ */
+int
+string_to_privsets(PRIV *table, const char *str, int *setprivs, int *clrprivs)
+{
+  PRIV *c;
+  char *p, *r;
+  char tbuf1[BUFFER_LEN];
+  int not;
+  int words = 0;
+  int err = 0;
+  int found = 0;
+
+  *setprivs = *clrprivs = 0;
+  if (!str || !*str)
+    return 0;
+  strcpy(tbuf1, str);
+  r = trim_space_sep(tbuf1, ' ');
+  while ((p = split_token(&r, ' '))) {
+    words++;
+    not = 0;
+    if (*p == '!') {
+      not = 1;
+      if (!*++p) {
+      err = 1;
+      continue;
+      }
+    }
+    for (c = table; c->name; c++) {
+      if (string_prefix(c->name, p)) {
+      found++;
+      if (not)
+        *clrprivs |= c->bits_to_set;
+      else
+        *setprivs |= c->bits_to_set;
+      break;
+      }
+    }
+  }
+  if (err || (words != found))
+    return -1;
+  return 1;
+}
+
 /** Convert a letter string to a set of privilege bits, masked by an original set.
  * Given a privs table, a letter string, and an original set of privileges,
  * return a modified set of privileges by applying the privs in the
diff --git a/src/set.c b/src/set.c
index d06ec83..92119c5 100644
--- a/src/set.c
+++ b/src/set.c
@@ -450,9 +450,10 @@ do_chzone(dbref player, char const *name, char const *newobj, int noisy)
 
 /** Structure for af_helper() data. */
 struct af_args {
-  int f;		/**< flag bits */
-  int clear;		/**< True to remove the flag */
-  char *flag;		/**< flag name */
+  int setf;		/**< flag bits to set */
+  int clrf;		/**< flag bits to clear */
+  char *setflags;	/**< list of names of flags to set */
+  char *clrflags;	/**< list of names of flags to clear */
 };
 
 static int
@@ -467,23 +468,25 @@ af_helper(dbref player, dbref thing, dbref parent __attribute__ ((__unused__)),
    * There is one special case - the resetting of the SAFE flag.
    */
   if (!(Can_Write_Attr(player, thing, AL_ATTR(atr)) ||
-	(af->clear && (af->f & AF_SAFE) &&
+	((af->clrf & AF_SAFE) &&
 	 Can_Write_Attr_Ignore_Safe(player, thing, AL_ATTR(atr))))) {
     notify_format(player, T("You cannot change that flag on %s/%s"),
 		  Name(thing), AL_NAME(atr));
     return 0;
   }
 
-  if (af->clear) {
-    AL_FLAGS(atr) &= ~af->f;
+  /* Clear flags first, then set flags */
+  if (af->clrf) {
+    AL_FLAGS(atr) &= ~af->clrf;
     if (!AreQuiet(player, thing))
       notify_format(player, T("%s/%s - %s reset."), Name(thing), AL_NAME(atr),
-		    af->flag);
-  } else {
-    AL_FLAGS(atr) |= af->f;
+		    af->clrflags);
+  }
+  if (af->setf) {
+    AL_FLAGS(atr) |= af->setf;
     if (!AreQuiet(player, thing))
       notify_format(player, T("%s/%s - %s set."), Name(thing), AL_NAME(atr),
-		    af->flag);
+		    af->setflags);
   }
 
   return 1;
@@ -525,21 +528,22 @@ do_attrib_flags(dbref player, const char *obj, const char *atrname,
     return;
   }
 
-  af.clear = 0;
-
-  /* move past NOT token if there is one */
-  for (p = flag; *p && ((*p == NOT_TOKEN) || isspace((unsigned char) *p)); p++)
-    if (*p == NOT_TOKEN)
-      af.clear = !af.clear;
+  p = flag;
+  /* Skip leading spaces */
+  while (*p && isspace((unsigned char) *p))
+    p++;
 
-  if ((af.f = string_to_atrflag(player, p)) < 0) {
+  af.setf = af.clrf = 0;
+  if (string_to_atrflagsets(player, p, &af.setf, &af.clrf) < 0) {
     notify(player, T("Unrecognized attribute flag."));
     return;
   }
-  af.flag = mush_strdup(atrflag_to_string(af.f), "af_flag list");
+  af.clrflags = mush_strdup(atrflag_to_string(af.clrf), "al_flag list");
+  af.setflags = mush_strdup(atrflag_to_string(af.setf), "al_flag list");
   if (!atr_iter_get(player, thing, atrname, 0, af_helper, &af))
     notify(player, T("No attribute found to change."));
-  mush_free((Malloc_t) af.flag, "af_flag list");
+  mush_free((Malloc_t) af.clrflags, "af_flag list");
+  mush_free((Malloc_t) af.setflags, "af_flag list");
 }