GENCOMP code from PennMUSH
authorAri Johnson <ari@cobramush.org>
Tue, 20 Feb 2007 21:20:31 +0000 (21:20 +0000)
committerAri Johnson <ari@cobramush.org>
Tue, 20 Feb 2007 21:20:31 +0000 (21:20 +0000)
hdrs/externs.h
src/bsd.c
src/console.c
src/flags.c
src/function.c
src/fundb.c
src/funlist.c
src/funstr.c

index e44a0b449ad30eb78087f7555accfe195a44ba0d..c8b535ff26e1d5de4d99473a0eadceea2e3e5f07 100644 (file)
@@ -103,6 +103,10 @@ extern int hidden(dbref player);
 extern dbref guest_to_connect(dbref player);
 void dump_reboot_db(void);
 void close_ssl_connections(void);
+int least_idle_time(dbref player);
+int least_idle_time_priv(dbref player);
+int most_conn_time(dbref player);
+int most_conn_time_priv(dbref player);
 char *least_idle_ip(dbref player);
 char *least_idle_hostname(dbref player);
 extern int do_command(DESC *d, char *command);
@@ -592,11 +596,24 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu
 /** Default (case-insensitive) local wildcard match */
 #define local_wild_match(s,d) local_wild_match_case(s, d, 0)
 
-    /** Types of lists, based on what their elements are */
-    typedef enum list_type {
-      ALPHANUM_LIST, NUMERIC_LIST, DBREF_LIST, FLOAT_LIST, INSENS_ALPHANUM_LIST,
-      UNKNOWN_LIST
-    } list_type;
+/** Types of lists */
+
+    extern char ALPHANUM_LIST[];
+    extern char INSENS_ALPHANUM_LIST[];
+    extern char DBREF_LIST[];
+    extern char NUMERIC_LIST[];
+    extern char FLOAT_LIST[];
+    extern char DBREF_NAME_LIST[];
+    extern char DBREF_NAMEI_LIST[];
+    extern char DBREF_IDLE_LIST[];
+    extern char DBREF_CONN_LIST[];
+    extern char DBREF_CTIME_LIST[];
+    extern char DBREF_OWNER_LIST[];
+    extern char DBREF_LOCATION_LIST[];
+    extern char DBREF_ATTR_LIST[];
+    extern char DBREF_ATTRI_LIST[];
+    extern char *UNKNOWN_LIST;
+
 /* From function.c and other fun*.c */
     extern char *strip_braces(char const *line);
     extern void save_global_regs(const char *funcname, char *preserve[]);
@@ -614,7 +631,9 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu
     extern int delim_check(char *buff, char **bp, int nfargs, char **fargs,
                           int sep_arg, char *sep);
     extern int get_gender(dbref player);
-    extern int gencomp(char *a, char *b, list_type sort_type);
+    extern int gencomp(dbref player, char *a, char *b, char *sort_type);
+    extern const char *do_get_attrib(dbref executor, dbref thing,
+                                    const char *aname);
     extern char *ArabicToRoman(int);
     extern int RomanToArabic(char *);
 
@@ -654,7 +673,7 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu
     void local_flags(void);
 
 /* funlist.c */
-    void do_gensort(char *s[], int n, list_type sort_type);
+    void do_gensort(dbref player, char *s[], int n, char *sort_type);
 
 /* sig.c */
     /** Type definition for signal handlers */
index 08d5b56535beb60fd0b6213ae99f14495280addb..391b045fc11144df0fb817fb5ffd1149b8b64e70 100644 (file)
--- a/src/bsd.c
+++ b/src/bsd.c
@@ -4167,6 +4167,90 @@ lookup_desc(dbref executor, const char *name)
   }
 }
 
+/** Return the conn time of the longest-connected connection of a player.
+ * This function treats hidden connectios as nonexistent.
+ * \param player dbref of player to get ip for.
+ * \return connection time of player as an INT, or -1 if not found or hidden.
+ */
+int
+most_conn_time(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && !Hidden(d) && (!match ||
+                                               (d->connected_at >
+                                                match->connected_at)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->connected_at);
+    return (int) result;
+  } else
+    return -1;
+}
+
+/** Return the conn time of the longest-connected connection of a player.
+ * This function does includes hidden people.
+ * \param player dbref of player to get ip for.
+ * \return connection time of player as an INT, or -1 if not found.
+ */
+int
+most_conn_time_priv(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && (!match ||
+                                 (d->connected_at > match->connected_at)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->connected_at);
+    return (int) result;
+  } else
+    return -1;
+}
+
+/** Return the idle time of the least-idle connection of a player.
+ * This function treats hidden connections as nonexistant.
+ * \param player dbref of player to get time for.
+ * \return idle time of player as an INT, or -1 if not found or hidden.
+ */
+int
+least_idle_time(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && !Hidden(d) &&
+       (!match || (d->last_time > match->last_time)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->last_time);
+    return (int) result;
+  } else
+    return -1;
+}
+
+/** Return the idle time of the least-idle connection of a player.
+ * This function performs no permission checking.
+ * \param player dbref of player to get time for.
+ * \return idle time of player as an INT, or -1 if not found.
+ */
+int
+least_idle_time_priv(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && (!match || (d->last_time > match->last_time)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->last_time);
+    return (int) result;
+  } else
+    return -1;
+}
+
 /** Return the ip address of the least-idle connection of a player.
  * This function performs no permission checking, and returns the
  * pointer from the descriptor itself (so don't destroy the result!)
index ed58bf55ce3b4042d40dae5998f24cd15d515402..983c78c3ffc00eb2099e2496d6aa56f951e80208 100644 (file)
@@ -3443,6 +3443,90 @@ lookup_desc(dbref executor, const char *name)
   }
 }
 
+/** Return the conn time of the longest-connected connection of a player.
+ * This function treats hidden connectios as nonexistent.
+ * \param player dbref of player to get ip for.
+ * \return connection time of player as an INT, or -1 if not found or hidden.
+ */
+int
+most_conn_time(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && !Hidden(d) && (!match ||
+                                               (d->connected_at >
+                                                match->connected_at)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->connected_at);
+    return (int) result;
+  } else
+    return -1;
+}
+
+/** Return the conn time of the longest-connected connection of a player.
+ * This function does includes hidden people.
+ * \param player dbref of player to get ip for.
+ * \return connection time of player as an INT, or -1 if not found.
+ */
+int
+most_conn_time_priv(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && (!match ||
+                                 (d->connected_at > match->connected_at)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->connected_at);
+    return (int) result;
+  } else
+    return -1;
+}
+
+/** Return the idle time of the least-idle connection of a player.
+ * This function treats hidden connections as nonexistant.
+ * \param player dbref of player to get time for.
+ * \return idle time of player as an INT, or -1 if not found or hidden.
+ */
+int
+least_idle_time(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && !Hidden(d) &&
+       (!match || (d->last_time > match->last_time)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->last_time);
+    return (int) result;
+  } else
+    return -1;
+}
+
+/** Return the idle time of the least-idle connection of a player.
+ * This function performs no permission checking.
+ * \param player dbref of player to get time for.
+ * \return idle time of player as an INT, or -1 if not found.
+ */
+int
+least_idle_time_priv(dbref player)
+{
+  DESC *d, *match = NULL;
+  DESC_ITER_CONN(d) {
+    if ((d->player == player) && (!match || (d->last_time > match->last_time)))
+      match = d;
+  }
+  if (match) {
+    double result = difftime(mudtime, match->last_time);
+    return (int) result;
+  } else
+    return -1;
+}
+
 /** Return the ip address of the least-idle connection of a player.
  * This function performs no permission checking, and returns the
  * pointer from the descriptor itself (so don't destroy the result!)
index a8be8971b8b486257030faed7a67f423e9475896..31f1082fc624d2575d5c819290459b5d10d1b30a 100644 (file)
@@ -2490,7 +2490,7 @@ list_all_flags(const char *ns, const char *name, dbref privs, int which)
        ptrs[numptrs++] = (char *) f->name;
     }
   }
-  do_gensort(ptrs, numptrs, ALPHANUM_LIST);
+  do_gensort(privs, ptrs, numptrs, ALPHANUM_LIST);
   bp = buf;
   for (i = 0; i < numptrs; i++) {
     switch (which) {
index c9246c27599e246f791a5e53b8d61f2481ec3ae3..d7a6319a373a79906588a60cbbd5033d86466ab2 100644 (file)
@@ -761,7 +761,9 @@ list_functions(void)
     ptrs[nptrs++] = fp->name;
     fp = (FUN *) hash_nextentry(&htab_user_function);
   }
-  do_gensort((char **) ptrs, nptrs, 0);
+  /* do_gensort needs a dbref now, but only for sort types that aren't
+   * used here anyway */
+  do_gensort((dbref) 0, (char **) ptrs, nptrs, 0);
   bp = buff;
   safe_str(ptrs[0], buff, &bp);
   for (i = 1; i < nptrs; i++) {
index 09f61effb407c55ab47333c5337847d16dd72c93..8b9ef7da9c827fdfa9b65ecbecb262224c98c544 100644 (file)
@@ -44,7 +44,7 @@ static dbref
                     int start, int count, int *retcount);
 
 
-static const char *
+const char *
 do_get_attrib(dbref executor, dbref thing, const char *attrib)
 {
   ATTR *a;
index 47f1c32c3c750e86964b782921969389b7283aaf..9eab2a2a65fc0788f5317c5f349fb8d76f48ca0e 100644 (file)
@@ -10,6 +10,7 @@
 #include "config.h"
 #include <string.h>
 #include <ctype.h>
+#include "ansi.h"
 #include "conf.h"
 #include "case.h"
 #include "externs.h"
 #define MAX_SORTSIZE (BUFFER_LEN / 2)  /**< Maximum number of elements to sort */
 
 static char *next_token(char *str, char sep);
-static list_type autodetect_list(char **ptrs, int nptrs);
-static list_type get_list_type(char **args, int nargs,
-                              int type_pos, char **ptrs, int nptrs);
-static list_type get_list_type_noauto(char **args, int nargs, int type_pos);
-static int a_comp(const void *s1, const void *s2);
-static int ai_comp(const void *s1, const void *s2);
+static char *autodetect_list(char **ptrs, int nptrs);
+static char *get_list_type(char **args, int nargs,
+                          int type_pos, char **ptrs, int nptrs);
+static char *get_list_type_noauto(char **args, int nargs, int type_pos);
 static int i_comp(const void *s1, const void *s2);
 static int f_comp(const void *s1, const void *s2);
 static int u_comp(const void *s1, const void *s2);
@@ -691,20 +690,31 @@ FUNCTION(fun_shuffle)
   arr2list(words, n, buff, bp, osep);
 }
 
-static list_type
+typedef enum {
+  L_NUMERIC,
+  L_FLOAT,
+  L_ALPHANUM,
+  L_DBREF
+} ltype;
+
+static char *
 autodetect_list(char *ptrs[], int nptrs)
 {
-  list_type sort_type;
+  char * sort_type;
+  ltype lt;
   int i;
 
+
+  lt = L_NUMERIC;
   sort_type = NUMERIC_LIST;
 
   for (i = 0; i < nptrs; i++) {
-    switch (sort_type) {
-    case NUMERIC_LIST:
+    switch (lt) {
+    case L_NUMERIC:
       if (!is_strict_integer(ptrs[i])) {
        /* If it's not an integer, see if it's a floating-point number */
        if (is_strict_number(ptrs[i])) {
+         lt = L_FLOAT;
          sort_type = FLOAT_LIST;
        } else if (i == 0) {
 
@@ -712,18 +722,19 @@ autodetect_list(char *ptrs[], int nptrs)
           * alphanumeric guess, unless this is the first
           * element and we have a dbref.
           */
-         if (is_objid(ptrs[i]))
+         if (is_objid(ptrs[i])) {
+           lt = L_DBREF;
            sort_type = DBREF_LIST;
-         else
+         else
            return ALPHANUM_LIST;
        }
       }
       break;
-    case FLOAT_LIST:
+    case L_FLOAT:
       if (!is_strict_number(ptrs[i]))
        return ALPHANUM_LIST;
       break;
-    case DBREF_LIST:
+    case L_DBREF:
       if (!is_objid(ptrs[i]))
        return ALPHANUM_LIST;
       break;
@@ -734,117 +745,281 @@ autodetect_list(char *ptrs[], int nptrs)
   return sort_type;
 }
 
-static list_type
-get_list_type(char *args[], int nargs, int type_pos, char *ptrs[], int nptrs)
+
+typedef struct sort_record s_rec;
+
+typedef int (*qsort_func) (const void *, const void *);
+typedef void (*makerecord) (s_rec *, dbref player, char *sortflags);
+
+#define GENRECORD(x) void x(s_rec *rec,dbref player,char *sortflags); \
+  void x(s_rec *rec, \
+    dbref player __attribute__ ((__unused__)), \
+    char *sortflags __attribute__ ((__unused__)))
+
+/** Sorting strings by different values. We store both the string and
+ * its 'key' to sort by. Sort of a hardcode munge.
+ */
+struct sort_record {
+  char *val;    /**< The string this is */
+  dbref db;     /**< dbref (default 0, bad is -1) */
+  char *str;    /**< string comparisons */
+  int num;      /**< integer comparisons */
+  NVAL numval;  /**< float comparisons */
+  int freestr;  /**< free str on completion */
+};
+
+/* Compare(r,x,y) {
+ *   if (x->db < 0 && y->db < 0)
+ *     return 0;  // Garbage is identical.
+ *   if (x->db < 0)
+ *     return 2;  // Garbage goes last.
+ *   if (y->db < 0)
+ *     return -2; // Garbage goes last.
+ *   if (r < 0)
+ *     return -2; // different
+ *   if (r > 0)
+ *     return 2;  // different
+ *   if (x->db < y->db)
+ *     return -1; // similar
+ *   if (y->db < x-db)
+ *     return 1;  // similar
+ *   return 0;    // identical
+ * }
+ */
+
+/* If I could, I'd let sort() toss out non-existant dbrefs
+ * Instead, sort stuffs them into a jumble at the end. */
+
+#define Compare(r,x,y) \
+        ((x->db < 0 || y->db < 0) ? \
+           ((x->db < 0 && y->db < 0) ? 0 : (x->db < 0 ? 2 : -2)) \
+           : ((r != 0) ? (r < 0 ? -2 : 2) \
+             : (x->db == y->db ? 0 : (x->db < y->db ? -1 : 1)) \
+           ) \
+         )
+
+static int
+s_comp(const void *s1, const void *s2)
 {
-  if (nargs >= type_pos) {
-    switch (*args[type_pos - 1]) {
-    case 'A':
-    case 'a':
-      return ALPHANUM_LIST;
-    case 'I':
-    case 'i':
-      return INSENS_ALPHANUM_LIST;
-    case 'D':
-    case 'd':
-      return DBREF_LIST;
-    case 'N':
-    case 'n':
-      return NUMERIC_LIST;
-    case 'F':
-    case 'f':
-      return FLOAT_LIST;
-    case '\0':
-      return autodetect_list(ptrs, nptrs);
-    default:
-      return ALPHANUM_LIST;
-    }
-  }
-  return autodetect_list(ptrs, nptrs);
+  const s_rec *sr1 = (const s_rec *) s1;
+  const s_rec *sr2 = (const s_rec *) s2;
+  int res = 0;
+  res = strcoll(sr1->str, sr2->str);
+  return Compare(res, sr1, sr2);
 }
 
-static list_type
-get_list_type_noauto(char *args[], int nargs, int type_pos)
+static int
+si_comp(const void *s1, const void *s2)
 {
-  if (nargs >= type_pos) {
-    switch (*args[type_pos - 1]) {
-    case 'A':
-    case 'a':
-      return ALPHANUM_LIST;
-    case 'I':
-    case 'i':
-      return INSENS_ALPHANUM_LIST;
-    case 'D':
-    case 'd':
-      return DBREF_LIST;
-    case 'N':
-    case 'n':
-      return NUMERIC_LIST;
-    case 'F':
-    case 'f':
-      return FLOAT_LIST;
-    default:
-      return UNKNOWN_LIST;
-    }
-  }
-  return UNKNOWN_LIST;
+  const s_rec *sr1 = (const s_rec *) s1;
+  const s_rec *sr2 = (const s_rec *) s2;
+  int res = 0;
+  res = strcasecoll(sr1->str, sr2->str);
+  return Compare(res, sr1, sr2);
 }
 
 static int
-a_comp(const void *s1, const void *s2)
+i_comp(const void *s1, const void *s2)
 {
-  return strcoll(*(char *const *) s1, *(char *const *) s2);
+  const s_rec *sr1 = (const s_rec *) s1;
+  const s_rec *sr2 = (const s_rec *) s2;
+  int res = 0;
+  res = sr1->num - sr2->num;
+  return Compare(res, sr1, sr2);
 }
 
 static int
-ai_comp(const void *s1, const void *s2)
+f_comp(const void *s1, const void *s2)
 {
-  return strcasecoll(*(char *const *) s1, *(char *const *) s2);
+  const s_rec *sr1 = (const s_rec *) s1;
+  const s_rec *sr2 = (const s_rec *) s2;
+  NVAL res = 0;
+  res = sr1->numval - sr2->numval;
+  return Compare(res, sr1, sr2);
 }
 
-/** An integer, for sorting purposes. We store both the string and
- * the int forms to make some things more efficient.
- */
-typedef struct i_record {
-  char *str;   /**< string representation */
-  int num;     /**< integer representation */
-} i_rec;
-
-/** Integer comparison routine for sorts.
- * \param s1 void pointer to an i_record.
- * \param s2 void pointer to an i_record.
- * \retval <0 s1's integer is < s2's integer.
- * \retval 0 s1's integer = s2's integer.
- * \retval >0 s1's integer is > s2's integer.
- */
-static int
-i_comp(const void *s1, const void *s2)
+GENRECORD(gen_alphanum)
 {
-  if (((const i_rec *) s1)->num > ((const i_rec *) s2)->num)
-    return 1;
-  if (((const i_rec *) s1)->num < ((const i_rec *) s2)->num)
-    return -1;
-  return 0;
+  size_t len;
+  if (strchr(rec->val, ESC_CHAR)) {
+    rec->str = mush_strdup(remove_markup(rec->val, &len), "genrecord");
+    rec->freestr = 1;
+  } else {
+    rec->str = rec->val;
+  }
 }
 
-/** A double, for sorting purposes. We store both the string and
- * the NVAL forms to make some things more efficient.
- */
-typedef struct f_record {
-  char *str;   /**< string representation */
-  NVAL num;    /**< numeric representation */
-} f_rec;
+GENRECORD(gen_dbref)
+{
+  rec->num = qparse_dbref(rec->val);
+}
 
-static int
-f_comp(const void *s1, const void *s2)
+GENRECORD(gen_num)
 {
-  if (((const f_rec *) s1)->num > ((const f_rec *) s2)->num)
-    return 1;
-  if (((const f_rec *) s1)->num < ((const f_rec *) s2)->num)
-    return -1;
-  return 0;
+  rec->num = parse_integer(rec->val);
+}
+
+GENRECORD(gen_float)
+{
+  rec->numval = parse_number(rec->val);
+}
+
+#define RealGoodObject(x) (GoodObject(x) && !IsGarbage(x))
+
+GENRECORD(gen_db_name)
+{
+  rec->str = (char *) "";
+  if (RealGoodObject(rec->db))
+    rec->str = (char *) Name(rec->db);
+}
+
+GENRECORD(gen_db_idle)
+{
+  rec->num = -1;
+  if (RealGoodObject(rec->db)) {
+    if (Priv_Who(player))
+      rec->num = least_idle_time_priv(rec->db);
+    else
+      rec->num = least_idle_time(rec->db);
+  }
+}
+
+GENRECORD(gen_db_conn)
+{
+  rec->num = -1;
+  if (RealGoodObject(rec->db)) {
+    if (Priv_Who(player))
+      rec->num = most_conn_time_priv(rec->db);
+    else
+      rec->num = most_conn_time(rec->db);
+  }
+}
+
+GENRECORD(gen_db_ctime)
+{
+  if (RealGoodObject(rec->db))
+    rec->num = CreTime(rec->db);
+}
+
+GENRECORD(gen_db_owner)
+{
+  if (RealGoodObject(rec->db))
+    rec->num = Owner(rec->db);
+}
+
+GENRECORD(gen_db_loc)
+{
+  rec->num = -1;
+  if (RealGoodObject(rec->db) && Can_Locate(player, rec->db)) {
+    rec->num = Location(rec->db);
+  }
+}
+
+GENRECORD(gen_db_attr)
+{
+  /* Eek, I hate dealing with memory issues. */
+
+  static char *defstr = (char *) "";
+  const char *ptr;
+
+  rec->str = defstr;
+  if (RealGoodObject(rec->db) && sortflags && *sortflags &&
+      (ptr = do_get_attrib(player, rec->db, sortflags)) != NULL) {
+    rec->str = mush_strdup(ptr, "genrecord");
+    rec->freestr = 1;
+  }
+}
+
+typedef struct _list_type_list_ {
+  char *name;
+  makerecord make_record;
+  qsort_func sorter;
+  int isdbs;
+} list_type_list;
+
+char ALPHANUM_LIST[] = "A";
+char INSENS_ALPHANUM_LIST[] = "I";
+char DBREF_LIST[] = "D";
+char NUMERIC_LIST[] = "N";
+char FLOAT_LIST[] = "F";
+char DBREF_NAME_LIST[] = "NAME";
+char DBREF_NAMEI_LIST[] = "NAMEI";
+char DBREF_IDLE_LIST[] = "IDLE";
+char DBREF_CONN_LIST[] = "CONN";
+char DBREF_CTIME_LIST[] = "CTIME";
+char DBREF_OWNER_LIST[] = "OWNER";
+char DBREF_LOCATION_LIST[] = "LOC";
+char DBREF_ATTR_LIST[] = "ATTR";
+char DBREF_ATTRI_LIST[] = "ATTRI";
+char *UNKNOWN_LIST = NULL;
+
+list_type_list ltypelist[] = {
+  /* List type name,            recordmaker,    comparer, dbrefs? */
+  {ALPHANUM_LIST, gen_alphanum, s_comp, 0},
+  {INSENS_ALPHANUM_LIST, gen_alphanum, si_comp, 0},
+  {DBREF_LIST, gen_dbref, i_comp, 0},
+  {NUMERIC_LIST, gen_num, i_comp, 0},
+  {FLOAT_LIST, gen_float, f_comp, 0},
+  {DBREF_NAME_LIST, gen_db_name, s_comp, 1},
+  {DBREF_NAMEI_LIST, gen_db_name, si_comp, 1},
+  {DBREF_IDLE_LIST, gen_db_idle, i_comp, 1},
+  {DBREF_CONN_LIST, gen_db_conn, i_comp, 1},
+  {DBREF_CTIME_LIST, gen_db_ctime, i_comp, 1},
+  {DBREF_OWNER_LIST, gen_db_owner, i_comp, 1},
+  {DBREF_LOCATION_LIST, gen_db_loc, i_comp, 1},
+  {DBREF_ATTR_LIST, gen_db_attr, s_comp, 1},
+  {DBREF_ATTRI_LIST, gen_db_attr, si_comp, 1},
+  /* This stops the loop, so is default */
+  {NULL, gen_alphanum, s_comp, 0}
+};
+
+char *
+get_list_type(char *args[], int nargs, int type_pos, char *ptrs[], int nptrs)
+{
+  static char stype[BUFFER_LEN];
+  int i;
+  char *str;
+  if (nargs >= type_pos) {
+    str = args[type_pos - 1];
+    if (*str) {
+      strcpy(stype, str);
+      str = strchr(stype, ':');
+      if (str)
+       *(str++) = '\0';
+      for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, stype);
+          i++) ;
+      /* return ltypelist[i].name; */
+      if (ltypelist[i].name) {
+       return args[type_pos - 1];
+      }
+    }
+  }
+  return autodetect_list(ptrs, nptrs);
+}
+
+char *
+get_list_type_noauto(char *args[], int nargs, int type_pos)
+{
+  static char stype[BUFFER_LEN];
+  int i;
+  char *str;
+  if (nargs >= type_pos) {
+    str = args[type_pos - 1];
+    if (*str) {
+      strcpy(stype, str);
+      str = strchr(stype, ':');
+      if (str)
+       *(str++) = '\0';
+      for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, stype);
+          i++) ;
+      /* return ltypelist[i].name; */
+      return args[type_pos - 1];
+    }
+  }
+  return UNKNOWN_LIST;
 }
 
+
 static dbref ucomp_executor, ucomp_caller, ucomp_enactor;
 static char ucomp_buff[BUFFER_LEN];
 static PE_Info *ucomp_pe_info;
@@ -877,129 +1052,110 @@ u_comp(const void *s1, const void *s2)
   return n;
 }
 
-/** Compare two values based on sort_type.
- * \param a one value.
- * \param b another value.
- * \param sort_type how to compare the values.
- * \retval <0 a < b
- * \retval 0  a = b
- * \retval >0 a > b
+/** A generic comparer routine to compare two values of any sort type.
+ * \param
  */
 int
-gencomp(char *a, char *b, list_type sort_type)
-{
-  switch (sort_type) {
-  case NUMERIC_LIST:
-    {
-      int na, nb;
-      na = parse_integer(a);
-      nb = parse_integer(b);
-      if (na < nb)
-       return -1;
-      if (na > nb)
-       return 1;
-      return 0;
-    }
-  case DBREF_LIST:
-    {
-      int dga, dgb;
-      dga = parse_objid(a);
-      dgb = parse_objid(b);
-      if (dga < dgb)
-       return -1;
-      if (dga > dgb)
-       return 1;
-      return 0;
-    }
-  case FLOAT_LIST:
-    {
-      NVAL na, nb;
-      na = parse_number(a);
-      nb = parse_number(b);
-      if (na < nb)
-       return -1;
-      if (na > nb)
-       return 1;
-      return 0;
-    }
-  case INSENS_ALPHANUM_LIST:
-    {
-      int result;
-      result = strcasecoll(a, b);
-      if (result < 0)
-       return -1;
-      if (result > 0)
-       return 1;
-      return 0;
-    }
-  case ALPHANUM_LIST:          /* Falls through */
-  default:
-    {
-      int result;
-      result = strcoll(a, b);
-      if (result < 0)
-       return -1;
-      if (result > 0)
-       return 1;
-      return 0;
-    }
+gencomp(dbref player, char *a, char *b, char *sort_type)
+{
+  char *ptr;
+  int i, len;
+  int result;
+  s_rec s1, s2;
+  ptr = NULL;
+  if (!sort_type) {
+    /* Advance i to the default */
+    for (i = 0; ltypelist[i].name; i++) ;
+  } else if ((ptr = strchr(sort_type, ':'))) {
+    len = ptr - sort_type;
+    ptr += 1;
+    if (!*ptr)
+      ptr = NULL;
+    for (i = 0;
+        ltypelist[i].name && strncasecmp(ltypelist[i].name, sort_type, len);
+        i++) ;
+  } else {
+    for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, sort_type);
+        i++) ;
+  }
+  s1.freestr = s2.freestr = 0;
+  if (ltypelist[i].isdbs) {
+    s1.db = parse_dbref(a);
+    s2.db = parse_dbref(b);
+    if (!RealGoodObject(s1.db))
+      s1.db = NOTHING;
+    if (!RealGoodObject(s2.db))
+      s2.db = NOTHING;
+  } else {
+    s1.db = s2.db = 0;
   }
+
+  s1.val = a;
+  s2.val = b;
+  ltypelist[i].make_record(&s1, player, ptr);
+  ltypelist[i].make_record(&s2, player, ptr);
+  result = ltypelist[i].sorter((const void *) &s1, (const void *) &s2);
+  if (s1.freestr)
+    mush_free(s1.str, "genrecord");
+  if (s2.freestr)
+    mush_free(s2.str, "genrecord");
+  return result;
 }
 
-/** A generic sort routine to sort an array in place.
+/** A generic sort routine to sort several different
+ * types of arrays, in place.
+ * \param player the player executing the sort.
  * \param s the array to sort.
- * \param n number of elements in array s.
- * \param sort_type type of sort.
+ * \param n number of elements in array s
+ * \param sort_type the string that describes the sort type.
  */
+
 void
-do_gensort(char *s[], int n, list_type sort_type)
+do_gensort(dbref player, char *s[], int n, char *sort_type)
 {
-  int i;
-  f_rec *fp;
-  i_rec *ip;
-
-  switch (sort_type) {
-  case ALPHANUM_LIST:
-  case UNKNOWN_LIST:
-    qsort(s, n, sizeof(char *), a_comp);
-    break;
-  case INSENS_ALPHANUM_LIST:
-    qsort(s, n, sizeof(char *), ai_comp);
-    break;
-  case NUMERIC_LIST:
-    ip = (i_rec *) mush_malloc(n * sizeof(i_rec), "do_gensort.int_list");
-    for (i = 0; i < n; i++) {
-      ip[i].str = s[i];
-      ip[i].num = parse_integer(s[i]);
-    }
-    qsort((void *) ip, n, sizeof(i_rec), i_comp);
-    for (i = 0; i < n; i++)
-      s[i] = ip[i].str;
-    mush_free((Malloc_t) ip, "do_gensort.int_list");
-    break;
-  case DBREF_LIST:
-    ip = (i_rec *) mush_malloc(n * sizeof(i_rec), "do_gensort.dbref_list");
-    for (i = 0; i < n; i++) {
-      ip[i].str = s[i];
-      ip[i].num = qparse_dbref(s[i]);
-    }
-    qsort((void *) ip, n, sizeof(i_rec), i_comp);
-    for (i = 0; i < n; i++)
-      s[i] = ip[i].str;
-    mush_free((Malloc_t) ip, "do_gensort.dbref_list");
-    break;
-  case FLOAT_LIST:
-    fp = (f_rec *) mush_malloc(n * sizeof(f_rec), "do_gensort.num_list");
-    for (i = 0; i < n; i++) {
-      fp[i].str = s[i];
-      fp[i].num = parse_number(s[i]);
+  char *ptr;
+  static char stype[BUFFER_LEN];
+  int i, sorti;
+  s_rec *sp;
+  ptr = NULL;
+  if (!sort_type || !*sort_type) {
+    /* Advance sorti to the default */
+    for (sorti = 0; ltypelist[sorti].name; sorti++) ;
+  } else if (strchr(sort_type, ':') != NULL) {
+    strcpy(stype, sort_type);
+    ptr = strchr(stype, ':');
+    *(ptr++) = '\0';
+    if (!*ptr)
+      ptr = NULL;
+    for (sorti = 0;
+        ltypelist[sorti].name && strcasecmp(ltypelist[sorti].name, stype);
+        sorti++) ;
+  } else {
+    for (sorti = 0;
+        ltypelist[sorti].name && strcasecmp(ltypelist[sorti].name, sort_type);
+        sorti++) ;
+  }
+  sp = (s_rec *) mush_malloc(n * sizeof(s_rec), "do_gensort");
+  for (i = 0; i < n; i++) {
+    sp[i].val = s[i];
+    sp[i].freestr = 0;
+    sp[i].db = 0;
+    sp[i].str = NULL;
+    if (ltypelist[sorti].isdbs) {
+      sp[i].db = parse_objid(s[i]);
+      if (!RealGoodObject(sp[i].db))
+       sp[i].db = NOTHING;
     }
-    qsort((void *) fp, n, sizeof(f_rec), f_comp);
-    for (i = 0; i < n; i++)
-      s[i] = fp[i].str;
-    mush_free((Malloc_t) fp, "do_gensort.num_list");
-    break;
+    ltypelist[sorti].make_record(&(sp[i]), player, ptr);
+  }
+  qsort((void *) sp, n, sizeof(s_rec), ltypelist[sorti].sorter);
+
+  for (i = 0; i < n; i++) {
+    s[i] = sp[i].val;
+    if (sp[i].freestr)
+      mush_free(sp[i].str, "genrecord");
   }
+  mush_free((Malloc_t) sp, "do_gensort");
 }
 
 /* ARGSUSED */
@@ -1007,7 +1163,7 @@ FUNCTION(fun_sort)
 {
   char *ptrs[MAX_SORTSIZE];
   int nptrs;
-  list_type sort_type;
+  char *sort_type;
   char sep;
   char outsep[BUFFER_LEN];
 
@@ -1025,7 +1181,7 @@ FUNCTION(fun_sort)
 
   nptrs = list2arr(ptrs, MAX_SORTSIZE, args[0], sep);
   sort_type = get_list_type(args, nargs, 2, ptrs, nptrs);
-  do_gensort(ptrs, nptrs, sort_type);
+  do_gensort(executor, ptrs, nptrs, sort_type);
   arr2list(ptrs, nptrs, buff, bp, outsep);
 }
 
@@ -1155,7 +1311,7 @@ FUNCTION(fun_setinter)
   char sep;
   char **a1, **a2;
   int n1, n2, x1, x2, val;
-  list_type sort_type = ALPHANUM_LIST;
+  char *sort_type = ALPHANUM_LIST;
   int osepl = 0;
   char *osep = NULL, osepd[2] = { '\0', '\0' };
 
@@ -1169,7 +1325,7 @@ FUNCTION(fun_setinter)
   a1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray");
   a2 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray");
   if (!a1 || !a2)
-    mush_panic("Unable to allocate memory in fun_setinter");
+    mush_panic("Unable to allocate memory in fun_setunion");
 
   /* make arrays out of the lists */
   n1 = list2arr(a1, MAX_SORTSIZE, args[0], sep);
@@ -1198,12 +1354,12 @@ FUNCTION(fun_setinter)
     osepl = arglens[4];
   }
   /* sort each array */
-  do_gensort(a1, n1, sort_type);
-  do_gensort(a2, n2, sort_type);
+  do_gensort(executor, a1, n1, sort_type);
+  do_gensort(executor, a2, n2, sort_type);
 
   /* get the first value for the intersection, removing duplicates */
   x1 = x2 = 0;
-  while ((val = gencomp(a1[x1], a2[x2], sort_type))) {
+  while ((val = gencomp(executor, a1[x1], a2[x2], sort_type))) {
     if (val < 0) {
       x1++;
       if (x1 >= n1) {
@@ -1221,7 +1377,7 @@ FUNCTION(fun_setinter)
     }
   }
   safe_str(a1[x1], buff, bp);
-  while (!gencomp(a1[x1], a2[x2], sort_type)) {
+  while (!gencomp(executor, a1[x1], a2[x2], sort_type)) {
     x1++;
     if (x1 >= n1) {
       mush_free((Malloc_t) a1, "ptrarray");
@@ -1232,7 +1388,7 @@ FUNCTION(fun_setinter)
 
   /* get values for the intersection, until at least one list is empty */
   while ((x1 < n1) && (x2 < n2)) {
-    while ((val = gencomp(a1[x1], a2[x2], sort_type))) {
+    while ((val = gencomp(executor, a1[x1], a2[x2], sort_type))) {
       if (val < 0) {
        x1++;
        if (x1 >= n1) {
@@ -1251,7 +1407,7 @@ FUNCTION(fun_setinter)
     }
     safe_strl(osep, osepl, buff, bp);
     safe_str(a1[x1], buff, bp);
-    while (!gencomp(a1[x1], a2[x2], sort_type)) {
+    while (!gencomp(executor, a1[x1], a2[x2], sort_type)) {
       x1++;
       if (x1 >= n1) {
        mush_free((Malloc_t) a1, "ptrarray");
@@ -1270,8 +1426,7 @@ FUNCTION(fun_setunion)
   char sep;
   char **a1, **a2;
   int n1, n2, x1, x2, val;
-  int lastx1, lastx2, found;
-  list_type sort_type = ALPHANUM_LIST;
+  char *sort_type = ALPHANUM_LIST;
   int osepl = 0;
   char *osep = NULL, osepd[2] = { '\0', '\0' };
 
@@ -1285,7 +1440,7 @@ FUNCTION(fun_setunion)
   a1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray");
   a2 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray");
   if (!a1 || !a2)
-    mush_panic("Unable to allocate memory in fun_setdiff");
+    mush_panic("Unable to allocate memory in fun_setunion");
 
   /* make arrays out of the lists */
   n1 = list2arr(a1, MAX_SORTSIZE, args[0], sep);
@@ -1315,88 +1470,63 @@ FUNCTION(fun_setunion)
   }
 
   /* sort each array */
-  do_gensort(a1, n1, sort_type);
-  do_gensort(a2, n2, sort_type);
-
-  /* get values for the union, in order, skipping duplicates */
-  lastx1 = lastx2 = -1;
-  found = x1 = x2 = 0;
-  if (n1 == 1 && !*a1[0])
-    n1 = 0;
-  if (n2 == 1 && !*a2[0])
-    n2 = 0;
-  while ((x1 < n1) || (x2 < n2)) {
-    /* If we've already copied off something from a1, and our current
-     * look at a1 is the same element, or we've copied from a2 and
-     * our current look at a1 is the same element, skip forward in a1.
-     */
-    if (x1 < n1 && lastx1 >= 0) {
-      val = gencomp(a1[lastx1], a1[x1], sort_type);
-      if (val == 0) {
-       x1++;
-       continue;
-      }
+  do_gensort(executor, a1, n1, sort_type);
+  do_gensort(executor, a2, n2, sort_type);
+
+  /* get the first value for the difference, removing duplicates */
+  x1 = x2 = 0;
+  while ((val = gencomp(executor, a1[x1], a2[x2], sort_type)) >= 0) {
+    if (val > 0) {
+      x2++;
+      if (x2 >= n2)
+       break;
     }
-    if (x1 < n1 && lastx2 >= 0) {
-      val = gencomp(a2[lastx2], a1[x1], sort_type);
-      if (val == 0) {
-       x1++;
-       continue;
+    if (!val) {
+      x1++;
+      if (x1 >= n1) {
+       mush_free((Malloc_t) a1, "ptrarray");
+       mush_free((Malloc_t) a2, "ptrarray");
+       return;
       }
     }
-    if (x2 < n2 && lastx1 >= 0) {
-      val = gencomp(a1[lastx1], a2[x2], sort_type);
-      if (val == 0) {
-       x2++;
-       continue;
-      }
+  }
+  safe_str(a1[x1], buff, bp);
+  do {
+    x1++;
+    if (x1 >= n1) {
+      mush_free((Malloc_t) a1, "ptrarray");
+      mush_free((Malloc_t) a2, "ptrarray");
+      return;
     }
-    if (x2 < n2 && lastx2 >= 0) {
-      val = gencomp(a2[lastx2], a2[x2], sort_type);
-      if (val == 0) {
-       x2++;
-       continue;
-      }
+  } while (!gencomp(executor, a1[x1], a1[x1 - 1], sort_type));
+
+  /* get values for the difference, until at least one list is empty */
+  while (x2 < n2) {
+    if ((val = gencomp(executor, a1[x1], a2[x2], sort_type)) < 0) {
+      safe_strl(osep, osepl, buff, bp);
+      safe_str(a1[x1], buff, bp);
     }
-    if (x1 >= n1) {
-      /* Just copy off the rest of a2 */
-      if (x2 < n2) {
-       if (found)
-         safe_strl(osep, osepl, buff, bp);
-       safe_str(a2[x2], buff, bp);
-       lastx2 = x2;
-       x2++;
-       found = 1;
-      }
-    } else if (x2 >= n2) {
-      /* Just copy off the rest of a1 */
-      if (x1 < n1) {
-       if (found)
-         safe_strl(osep, osepl, buff, bp);
-       safe_str(a1[x1], buff, bp);
-       lastx1 = x1;
-       x1++;
-       found = 1;
-      }
-    } else {
-      /* At this point, we're merging. Take the lower of the two. */
-      val = gencomp(a1[x1], a2[x2], sort_type);
-      if (val <= 0) {
-       if (found)
-         safe_strl(osep, osepl, buff, bp);
-       safe_str(a1[x1], buff, bp);
-       lastx1 = x1;
+    if (val <= 0) {
+      do {
        x1++;
-       found = 1;
-      } else {
-       if (found)
-         safe_strl(osep, osepl, buff, bp);
-       safe_str(a2[x2], buff, bp);
-       lastx2 = x2;
-       x2++;
-       found = 1;
-      }
+       if (x1 >= n1) {
+         mush_free((Malloc_t) a1, "ptrarray");
+         mush_free((Malloc_t) a2, "ptrarray");
+         return;
+       }
+      } while (!gencomp(executor, a1[x1], a1[x1 - 1], sort_type));
     }
+    if (val >= 0)
+      x2++;
+  }
+
+  /* empty out remaining values, still removing duplicates */
+  while (x1 < n1) {
+    safe_strl(osep, osepl, buff, bp);
+    safe_str(a1[x1], buff, bp);
+    do {
+      x1++;
+    } while ((x1 < n1) && !gencomp(executor, a1[x1], a1[x1 - 1], sort_type));
   }
   mush_free((Malloc_t) a1, "ptrarray");
   mush_free((Malloc_t) a2, "ptrarray");
@@ -1408,7 +1538,7 @@ FUNCTION(fun_setdiff)
   char sep;
   char **a1, **a2;
   int n1, n2, x1, x2, val;
-  list_type sort_type = ALPHANUM_LIST;
+  char *sort_type = ALPHANUM_LIST;
   int osepl = 0;
   char *osep = NULL, osepd[2] = { '\0', '\0' };
 
@@ -1422,7 +1552,7 @@ FUNCTION(fun_setdiff)
   a1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray");
   a2 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray");
   if (!a1 || !a2)
-    mush_panic("Unable to allocate memory in fun_setdiff");
+    mush_panic("Unable to allocate memory in fun_setunion");
 
   /* make arrays out of the lists */
   n1 = list2arr(a1, MAX_SORTSIZE, args[0], sep);
@@ -1443,7 +1573,7 @@ FUNCTION(fun_setdiff)
       osepd[0] = sep;
       osep = osepd;
       if (sep)
-      osepl = 1;
+       osepl = 1;
     }
   } else if (nargs == 5) {
     sort_type = get_list_type(args, nargs, 4, a1, n1);
@@ -1452,12 +1582,12 @@ FUNCTION(fun_setdiff)
   }
 
   /* sort each array */
-  do_gensort(a1, n1, sort_type);
-  do_gensort(a2, n2, sort_type);
+  do_gensort(executor, a1, n1, sort_type);
+  do_gensort(executor, a2, n2, sort_type);
 
   /* get the first value for the difference, removing duplicates */
   x1 = x2 = 0;
-  while ((val = gencomp(a1[x1], a2[x2], sort_type)) >= 0) {
+  while ((val = gencomp(executor, a1[x1], a2[x2], sort_type)) >= 0) {
     if (val > 0) {
       x2++;
       if (x2 >= n2)
@@ -1480,11 +1610,11 @@ FUNCTION(fun_setdiff)
       mush_free((Malloc_t) a2, "ptrarray");
       return;
     }
-  } while (!gencomp(a1[x1], a1[x1 - 1], sort_type));
+  } while (!gencomp(executor, a1[x1], a1[x1 - 1], sort_type));
 
   /* get values for the difference, until at least one list is empty */
   while (x2 < n2) {
-    if ((val = gencomp(a1[x1], a2[x2], sort_type)) < 0) {
+    if ((val = gencomp(executor, a1[x1], a2[x2], sort_type)) < 0) {
       safe_strl(osep, osepl, buff, bp);
       safe_str(a1[x1], buff, bp);
     }
@@ -1496,7 +1626,7 @@ FUNCTION(fun_setdiff)
          mush_free((Malloc_t) a2, "ptrarray");
          return;
        }
-      } while (!gencomp(a1[x1], a1[x1 - 1], sort_type));
+      } while (!gencomp(executor, a1[x1], a1[x1 - 1], sort_type));
     }
     if (val >= 0)
       x2++;
@@ -1508,7 +1638,7 @@ FUNCTION(fun_setdiff)
     safe_str(a1[x1], buff, bp);
     do {
       x1++;
-    } while ((x1 < n1) && !gencomp(a1[x1], a1[x1 - 1], sort_type));
+    } while ((x1 < n1) && !gencomp(executor, a1[x1], a1[x1 - 1], sort_type));
   }
   mush_free((Malloc_t) a1, "ptrarray");
   mush_free((Malloc_t) a2, "ptrarray");
index e2e26f99de71fcd47112d17f8f1d5dc454f16971..250c78bd5551654bc0fb961828fd75094df44892 100644 (file)
@@ -46,6 +46,7 @@ static int align_one_line(char *buff, char **bp, int ncols,
                          char *ptrs[MAX_COLS], ansi_string *as[MAX_COLS],
                          int linenum, char *fieldsep, int fslen, char *linesep,
                          int lslen, char filler);
+static int comp_gencomp(dbref exceutor, char *left, char *right, char *type);
 void init_tag_hashtab(void);
 void init_pronouns(void);
 
@@ -460,6 +461,14 @@ FUNCTION(fun_strreplace)
 
 }
 
+static int
+comp_gencomp(dbref executor, char *left, char *right, char *type)
+{
+  int c;
+  c = gencomp(executor, left, right, type);
+  return (c > 0 ? 1 : (c < 0 ? -1 : 0));
+}
+
 /* ARGSUSED */
 FUNCTION(fun_comp)
 {
@@ -481,7 +490,8 @@ FUNCTION(fun_comp)
       memcpy(left, l, llen);
       r = remove_markup(args[1], &rlen);
       memcpy(right, r, rlen);
-      safe_integer(gencomp(left, right, ALPHANUM_LIST), buff, bp);
+      safe_integer(comp_gencomp(executor, left, right, ALPHANUM_LIST), buff,
+                  bp);
       return;
     }
   case 'I':                    /* Case-insensitive lexicographic */
@@ -492,7 +502,8 @@ FUNCTION(fun_comp)
       memcpy(left, l, llen);
       r = remove_markup(args[1], &rlen);
       memcpy(right, r, rlen);
-      safe_integer(gencomp(left, right, INSENS_ALPHANUM_LIST), buff, bp);
+      safe_integer(comp_gencomp(executor, left, right, INSENS_ALPHANUM_LIST),
+                  buff, bp);
       return;
     }
   case 'N':                    /* Integers */
@@ -500,14 +511,16 @@ FUNCTION(fun_comp)
       safe_str(T(e_ints), buff, bp);
       return;
     }
-    safe_integer(gencomp(args[0], args[1], NUMERIC_LIST), buff, bp);
+    safe_integer(comp_gencomp(executor, args[0], args[1], NUMERIC_LIST), buff,
+                bp);
     return;
   case 'F':
     if (!is_strict_number(args[0]) || !is_strict_number(args[1])) {
       safe_str(T(e_nums), buff, bp);
       return;
     }
-    safe_integer(gencomp(args[0], args[1], FLOAT_LIST), buff, bp);
+    safe_integer(comp_gencomp(executor, args[0], args[1], FLOAT_LIST), buff,
+                bp);
     return;
   case 'D':
     {
@@ -518,7 +531,8 @@ FUNCTION(fun_comp)
        safe_str(T("#-1 INVALID DBREF"), buff, bp);
        return;
       }
-      safe_integer(gencomp(args[0], args[1], DBREF_LIST), buff, bp);
+      safe_integer(comp_gencomp(executor, args[0], args[1], DBREF_LIST), buff,
+                  bp);
       return;
     }
   default: