New functions: ps(), psinfo(), notify(), drain()
authorAri Johnson <ari@theari.com>
Thu, 19 Feb 2015 20:02:49 +0000 (15:02 -0500)
committerAri Johnson <ari@theari.com>
Thu, 19 Feb 2015 20:02:49 +0000 (15:02 -0500)
game/txt/hlp/cobra_func.hlp
hdrs/externs.h
src/cque.c
src/function.c
src/funmisc.c

index dc2efaf7c7bf6b390e278d3a61ab9180e315a39a..e5f9404fcbf8a94da355d2c3ebc2c406a04da4c5 100644 (file)
@@ -4702,14 +4702,14 @@ wait(<object>/<time>,<functions>)
   More forms that support semaphores on arbitrary attributes are described in
   help @wait2
 
-  See also the help for: SEMAPHORES, @drain, @notify, signal()
+  See also: SEMAPHORES, @wait, signal(), notify(), drain)
 
 & trigger()
-Trigger(<object>/<attribute>,<val1>,<val2>,...,<val10>)
+  trigger(<object>/<attribute>,<val1>,<val2>,...,<val10>)
 
   Works just like @trigger that fills in those fields.
 
-  See also the help for: @trigger
+  See also: @trigger
 
 & signal()
   signal(<queue id>,<signal>[,<signal argument>])
@@ -4727,3 +4727,51 @@ Trigger(<object>/<attribute>,<val1>,<val2>,...,<val10>)
     CONTINUE    - Resume the countdown timer for the queue entry
     TIME        - Set the countdown timer for the queue entry to the argument
     QUERY_T     - Return the value of the countdown timer for the queue entry
+
+& ps()
+  ps([<object>[,<type]])
+
+  Lists currently pending QIDs. If <object> is not specified, then the
+  executor's queue is listed. <type> is one of:
+    player    - list the player queue
+    object    - list the object queue
+    wait      - list the wait queue
+    semaphore - list the semaphore queue
+    all       - list all queues
+  If <type> is not specified, then 'all' is assumed.
+
+  See also: wait(), psinfo(), signal()
+
+& psinfo()
+  psinfo(<qid>)
+
+  Determine information about the pending queue entry <qid>.
+
+  See also: ps(), wait(), signal()
+
+& notify()
+  notify(<object>[,<attribute>[,<count>]])
+
+  Notify <object>/<attribute>. If <attribute> is not specified, then SEMAPHORE
+  is used. If <attribute> is ANY, then any attribute is notified. If <count> is
+  specified, then the object will be notified that many times. If <count> is
+  ALL, then all waiting semaphore queue entires will be notified. Otherwise,
+  <count> is assumed to be 1.
+
+  The number of queue entries affected is returned. If the return value is
+  less than <count>, then the semaphore attribute will be negative.
+
+  See also: SEMAPHORES, @notify, wait(), drain(), ps(), psinfo(), signal()
+
+& drain()
+  drain(<object>[,<attribute>[,<count>]])
+
+  Drain semaphores from <object>/<attribute>. If <attribute> is not specified,
+  then SEMAPHORE is drained. If <attribute> is ANY, then any attribute is
+  drained. If <count> is specified, then a maximum of <count> queued commands
+  will be drained. If <count> is ALL or unspecified, then all queued commands
+  will be drained from the semaphore queue.
+
+  The number of queue entries affected is returned.
+
+  See also: SEMAPHORES, @drain, wait(), notify(), ps(), psinfo(), signal()
index f95f84187e816b5b825931716cbbf55a8234dc85..d7eb5d557e91a6ff49d936dd83aba55daa551afe 100644 (file)
@@ -246,8 +246,8 @@ extern int queue_attribute_useatr(dbref executor, ATTR *a, dbref enactor);
 #define queue_attribute(a,b,c) queue_attribute_base(a,b,c,0)
 /** Queue the code in an attribute, excluding parent objects */
 #define queue_attribute_noparent(a,b,c) queue_attribute_base(a,b,c,1)
-extern void dequeue_semaphores(dbref thing, char const *aname, int count,
-                              int all, int drain);
+extern int dequeue_semaphores(dbref thing, char const *aname, int count,
+                             int all, int drain);
 extern void shutdown_queues(void);
 extern void do_hourly(void);
 
index 1b45f81d81f830307244ca87ae6a7318029f98bd..7b880ffcad49a221c571e526274b63bd66108f30 100644 (file)
@@ -823,18 +823,20 @@ drain_helper(dbref player __attribute__ ((__unused__)), dbref thing,
 /** Drain or notify a semaphore.
  * This function dequeues an entry in the semaphore queue and either
  * discards it (drain) or executes it (notify). Maybe more than one.
+ * Returns the number of entries affected.
  * \param thing object serving as semaphore.
  * \param aname attribute serving as semaphore.
  * \param count number of entries to dequeue.
  * \param all if 1, dequeue all entries.
  * \param drain if 1, drain rather than notify the entries.
  */
-void
+int
 dequeue_semaphores(dbref thing, char const *aname, int count, int all,
                   int drain)
 {
   BQUE **point;
   BQUE *entry;
+  int affected = 0;
 
   if (all)
     count = INT_MAX;
@@ -860,6 +862,7 @@ dequeue_semaphores(dbref thing, char const *aname, int count, int all,
 
     /* Update bookkeeping */
     count--;
+    affected++;
     add_to_sem(entry->sem, -1, entry->semattr);
 
     /* Dispose of the entry as appropriate: discard if @drain, or put
@@ -898,6 +901,8 @@ dequeue_semaphores(dbref thing, char const *aname, int count, int all,
    * @notify/any or @notify/all. */
   if (!drain && aname && !all && count > 0)
     add_to_sem(thing, -count, aname);
+
+  return affected;
 }
 
 COMMAND (cmd_notify_drain) {
@@ -972,7 +977,7 @@ COMMAND (cmd_notify_drain) {
       count = 1;
   }
 
-  dequeue_semaphores(thing, aname, count, all, drain);
+  (void) dequeue_semaphores(thing, aname, count, all, drain);
 
   if (drain) {
     quiet_notify(player, T("Drained."));
@@ -1687,19 +1692,345 @@ const char *get_namedreg(HASHTAB *regs, const char *name) {
   return "";
 }
 
+FUNCTION(fun_drain) {
+  dbref thing;
+  char *aname = "SEMAPHORE";
+  int count = INT_MAX;
+  int all = 1;
+
+  if (!command_check_byname(executor, "@drain")) {
+    safe_str("#-1 PERMISSION DENIED", buff, bp);
+    return;
+  }
+
+  if (!args[0] && *args[0]) {
+    safe_str(T(e_match), buff, bp);
+    return;
+  }
+
+  thing = match_result(executor, args[0], NOTYPE, MAT_EVERYTHING);
+  if (thing == NOTHING) {
+    safe_str(T(e_match), buff, bp);
+    return;
+  } else if (thing == AMBIGUOUS) {
+    safe_str(T("#-1 AMBIGUOUS MATCH"), buff, bp);
+    return;
+  }
+
+  if (nargs >= 2 && args[1] && *args[1]) {
+    if (string_prefix("any", args[1])) {
+      aname = NULL;
+    } else {
+      aname = args[1];
+      upcasestr(aname);
+    }
+  }
+
+  if (nargs >= 3 && args[2] && *args[2]) {
+    if (is_integer(args[2])) {
+      count = parse_integer(args[2]);
+      if (count <= 0) {
+        safe_str(T(e_uint), buff, bp);
+        return;
+      }
+      all = 0;
+    } else {
+      if (string_prefix("all", args[2])) {
+        count = INT_MAX;
+        all = 1;
+      } else {
+        safe_str(T(e_uint), buff, bp);
+        return;
+      }
+    }
+  }
+
+  if ((!controls(executor, thing) && !LinkOk(thing))
+      || (aname && !waitable_attr(thing, aname))) {
+    safe_str(T(e_perm), buff, bp);
+    return;
+  }
+
+  safe_integer(dequeue_semaphores(thing, aname, count, all, 1), buff, bp);
+}
+
+FUNCTION(fun_notify) {
+  dbref thing;
+  char *aname = "SEMAPHORE";
+  int count = 1;
+  int all = 0;
+
+  if (!command_check_byname(executor, "@notify")) {
+    safe_str("#-1 PERMISSION DENIED", buff, bp);
+    return;
+  }
+
+  if (!args[0] && *args[0]) {
+    safe_str(T(e_match), buff, bp);
+    return;
+  }
+
+  thing = match_result(executor, args[0], NOTYPE, MAT_EVERYTHING);
+  if (thing == NOTHING) {
+    safe_str(T(e_match), buff, bp);
+    return;
+  } else if (thing == AMBIGUOUS) {
+    safe_str(T("#-1 AMBIGUOUS MATCH"), buff, bp);
+    return;
+  }
+
+  if (nargs >= 2 && args[1] && *args[1]) {
+    if (string_prefix("any", args[1])) {
+      aname = NULL;
+    } else {
+      aname = args[1];
+      upcasestr(aname);
+    }
+  }
+
+  if (nargs >= 3 && args[2] && *args[2]) {
+    if (is_integer(args[2])) {
+      count = parse_integer(args[2]);
+      if (count <= 0) {
+        safe_str(T(e_uint), buff, bp);
+        return;
+      }
+    } else {
+      if (string_prefix("all", args[2])) {
+        count = INT_MAX;
+        all = 1;
+      } else {
+        safe_str(T(e_uint), buff, bp);
+        return;
+      }
+    }
+  }
+
+  if ((!controls(executor, thing) && !LinkOk(thing))
+      || (aname && !waitable_attr(thing, aname))) {
+    safe_str(T(e_perm), buff, bp);
+    return;
+  }
+
+  safe_integer(dequeue_semaphores(thing, aname, count, all, 0), buff, bp);
+}
+
+static int
+fun_ps_helper(dbref executor, dbref thing, BQUE *qptr, char *buff, char **bp,
+             int count) {
+  BQUE *tmp;
+
+  for (tmp = qptr; tmp; tmp = tmp->next) {
+    if (GoodObject(tmp->player)) {
+      if (Owner(tmp->player) == thing) {
+        if (count)
+          safe_chr(' ', buff, bp);
+        safe_integer(tmp->qid, buff, bp);
+        count++;
+      }
+    }
+  }
+
+  return count;
+}
+
+FUNCTION(fun_ps) {
+  dbref thing = executor;
+  int count;
+
+  if (nargs >= 1) {
+    if (!args[0] || !*args[0]) {
+      safe_str(T("INVALID ARGUMENT"), buff, bp);
+      return;
+    }
+    thing = match_result(executor, args[0], NOTYPE, MAT_EVERYTHING);
+    if (thing == NOTHING) {
+      safe_str(T(e_match), buff, bp);
+      return;
+    } else if (thing == AMBIGUOUS) {
+      safe_str(T("#-1 AMBIGUOUS MATCH"), buff, bp);
+      return;
+    }
+    if (!CanSeeQ(executor, thing)) {
+      safe_str(T(e_perm), buff, bp);
+      return;
+    }
+  }
+
+  if (nargs >= 2 && args[1] && *args[1]) {
+    if (string_prefix("player", args[1])) {
+      (void) fun_ps_helper(executor, thing, qfirst, buff, bp, 0);
+    } else if (string_prefix("object", args[1])) {
+      (void) fun_ps_helper(executor, thing, qlfirst, buff, bp, 0);
+    } else if (string_prefix("wait", args[1])) {
+      (void) fun_ps_helper(executor, thing, qwait, buff, bp, 0);
+    } else if (string_prefix("semaphore", args[1])) {
+      (void) fun_ps_helper(executor, thing, qsemfirst, buff, bp, 0);
+    } else if (string_prefix("all", args[1])) {
+      count = fun_ps_helper(executor, thing, qfirst, buff, bp, 0);
+      count += fun_ps_helper(executor, thing, qlfirst, buff, bp, count);
+      count += fun_ps_helper(executor, thing, qwait, buff, bp, count);
+      (void) fun_ps_helper(executor, thing, qsemfirst, buff, bp, count);
+    } else {
+      safe_str(T("#-1 INVALID ARGUMENT"), buff, bp);
+      return;
+    }
+  } else {
+    count = fun_ps_helper(executor, thing, qfirst, buff, bp, 0);
+    count += fun_ps_helper(executor, thing, qlfirst, buff, bp, count);
+    count += fun_ps_helper(executor, thing, qwait, buff, bp, count);
+    (void) fun_ps_helper(executor, thing, qsemfirst, buff, bp, count);
+  }
+}
+
+FUNCTION(fun_psinfo) {
+  int qid;
+  BQUE *tmp;
+  const char *type;
+
+  if (!args[0] || !*args[0] || !is_integer(args[0])) {
+    safe_str(T(e_uint), buff, bp);
+    return;
+  }
+
+  qid = parse_integer(args[0]);
+  if (qid < 0) {
+    safe_str(T(e_uint), buff, bp);
+    return;
+  } else if (qid > qid_cnt || qid_table[qid] == QID_FALSE) {
+    safe_str(T("#-1 INVALID QID"), buff, bp);
+    return;
+  }
+
+  type = "player";
+  for (tmp = qfirst; tmp; tmp = tmp->next)
+    if (tmp->qid == qid)
+      break;
+
+  type = "object";
+  if (!tmp) {
+    for (tmp = qlfirst; tmp; tmp = tmp->next)
+      if (tmp->qid == qid)
+        break;
+  }
+
+  type = "wait";
+  if (!tmp) {
+    for (tmp = qwait; tmp; tmp = tmp->next)
+      if (tmp->qid == qid)
+        break;
+  }
+
+  type = "semaphore";
+  if (!tmp) {
+    for (tmp = qsemfirst; tmp; tmp = tmp->next)
+      if (tmp->qid == qid)
+        break;
+  }
+
+  if (!tmp) {
+    safe_str(T("#-1 INVALID QID"), buff, bp);
+    return;
+  }
+
+  if (!CanSeeQ(executor, tmp->player)) {
+    safe_str(T(e_perm), buff, bp);
+    return;
+  }
+
+  safe_format(buff, bp, "%d %s %s %s", qid, type, unparse_dbref(tmp->player),
+             tmp->comm);
+}
+
 FUNCTION(fun_wait) {
-       char tbuf[BUFFER_LEN], *tbp;
-       const char *p;
-
-       if(!args[0] || !*args[0] || !args[1] || !*args[1])
-               safe_str("#-1", buff, bp);
-       else if(!command_check_byname(executor, "@wait"))
-               safe_str("#-1 PERMISSION DENIED", buff, bp);
-       else  {
-               tbp = tbuf;
-               p = args[0];
-               process_expression(tbuf, &tbp, &p, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info);
-               *tbp = '\0';
-               safe_integer(do_wait(executor, caller, tbuf, args[1], 0, 1), buff, bp);
-       }
+  char tbuf[BUFFER_LEN];
+  char *tbp;
+  const char *p;
+
+  if (!args[0] || !*args[0] || !args[1] || !*args[1])
+    safe_str("#-1", buff, bp);
+  else if (!command_check_byname(executor, "@wait"))
+    safe_str("#-1 PERMISSION DENIED", buff, bp);
+  else {
+    tbp = tbuf;
+    p = args[0];
+    process_expression(tbuf, &tbp, &p, executor, caller, enactor, PE_DEFAULT,
+                      PT_DEFAULT, pe_info);
+    *tbp = '\0';
+    safe_integer(do_wait(executor, caller, tbuf, args[1], 0, 1), buff, bp);
+  }
+}
+
+FUNCTION(fun_signal) {
+  enum qid_flags qsig = QID_FALSE;
+  int qtime, signal_r;
+
+  if (!*args[0] || !*args[1]) {
+    safe_str(T("#-1 INVALID SIGNAL"), buff, bp);
+    return;
+  }
+
+  /* find out which signal we're using */
+  if (string_prefix("kill", args[1]))
+    qsig = QID_KILL;
+  else if (string_prefix("freeze", args[1]))
+    qsig = QID_FREEZE;
+  else if (string_prefix("continue", args[1]))
+    qsig = QID_CONT;
+  else if (string_prefix("time", args[1]))
+    qsig = QID_TIME;
+  else if (string_prefix("query_t", args[1]))
+    qsig = QID_QUERY_T;
+
+  if (qsig == QID_FALSE) {
+    safe_str(T("#-1 INVALID SIGNAL"), buff, bp);
+    return;
+  }
+
+  if (qsig == QID_TIME) {
+    if (nargs < 3 || !args[2] || !*args[2]) {
+      safe_str(T(e_uint), buff, bp);
+      return;
+    }
+    qtime = parse_integer(args[2]);
+    if (qtime < 0) {
+      safe_str(T(e_uint), buff, bp);
+      return;
+    }
+  } else {
+    qtime = -1;
+  }
+
+  signal_r = do_signal_qid(executor, atoi(args[0]), qsig, qtime);
+  switch (signal_r) {
+  case 0:
+    safe_str(T("#-1 INVALID TIME ARGUMENT"), buff, bp);
+    break;
+  case -1:
+    safe_str(T("#-1 INVALID QID"), buff, bp);
+    break;
+  case -2: /* we shouldn't be getting this */
+    safe_str(T("#-1 INVALID SIGNAL"), buff, bp);
+    break;
+  case -3:
+    safe_str(T(e_perm), buff, bp);
+    break;
+  default:
+    safe_integer(signal_r > -1 ? signal_r : 0, buff, bp);
+    break;
+  }
+}
+
+FUNCTION(fun_trigger) {
+  if (!args[0] || !*args[0]) {
+    safe_str(T("#-1 INVALID ARGUMENTS"), buff, bp);
+    return;
+  }
+
+  if (!command_check_byname(executor, "@trigger")){
+    safe_str(T(e_perm), buff, bp);
+    return;
+  }
+
+  do_trigger(executor, args[0], args);
 }
index 035a35186008a919906f58b1b457acc7e28a5ecd..0b70bd3c0526c510760d1452f6dca752de4c5941 100644 (file)
@@ -358,6 +358,7 @@ FUNTAB flist[] = {
   {"DIST3D", fun_dist3d, 6, 6, FN_REG},
   {"DIV", fun_div, 2, 2, FN_REG},
   {"DOING", fun_doing, 1, 1, FN_REG},
+  {"DRAIN", fun_drain, 1, 3, FN_REG},
   {"EDEFAULT", fun_edefault, 2, 2, FN_NOPARSE},
   {"EDIT", fun_edit, 3, INT_MAX, FN_REG},
   {"ELEMENT", fun_element, 3, 3, FN_REG},
@@ -512,6 +513,7 @@ FUNTAB flist[] = {
   {"NCHILDREN", fun_lsearch, 1, 1, FN_REG},
   {"NCON", fun_dbwalker, 1, 1, FN_REG},
   {"NEXITS", fun_dbwalker, 1, 1, FN_REG},
+  {"NOTIFY", fun_notify, 1, 3, FN_REG},
   {"NPLAYERS", fun_dbwalker, 1, 1, FN_REG},
   {"NTHINGS", fun_dbwalker, 1, 1, FN_REG},
   {"NVCON", fun_dbwalker, 1, 1, FN_REG},
@@ -568,6 +570,8 @@ FUNTAB flist[] = {
   {"PRIMARYDIVISION", fun_primary_division, 1, 1, FN_REG},
   {"PROGRAM", fun_prog, 3, 5, FN_REG},
   {"PROMPT", fun_prompt, 1, 2, FN_REG},
+  {"PS", fun_ps, 0, 2, FN_REG},
+  {"PSINFO", fun_psinfo, 1, 1, FN_REG},
   {"PUEBLO", fun_pueblo, 1, 1, FN_REG},
   {"QUITPROG", fun_quitprog, 1, 1, FN_REG},
   {"QUOTA", fun_quota, 1, 1, FN_REG},
index 53db28d643a4e3b9ac927bb6638ebd63220ecf78..9fb1a4b23f42df7f5fedc88358c292689e8da669 100644 (file)
@@ -704,63 +704,3 @@ FUNCTION(fun_allof)
             caller, enactor, pe_info);
 }
 
-/* Signal Shit */
-FUNCTION(fun_signal) {
-       enum qid_flags qsig = QID_FALSE;
-       int signal_r;
-
-       if(!*args[0] || !*args[1])
-               return;
-       /* find out which signal we're using */
-       if(string_prefix("kill", args[1]))
-               qsig = QID_KILL;
-       else if(string_prefix("freeze", args[1]))
-               qsig = QID_FREEZE;
-       else if(string_prefix("continue", args[1]))
-               qsig = QID_CONT;
-       else if(string_prefix("time", args[1]))
-               qsig = QID_TIME;
-       else if(string_prefix("query_t", args[1]))
-               qsig = QID_QUERY_T;
-       if(qsig == QID_FALSE) {
-               safe_str("#-1 INVALID SIGNAL", buff, bp);
-               return;
-       } else if(qsig == QID_TIME && (!args[2] || !*args[2] ||
-                                      atoi(args[2]) < 0)) {
-               safe_str("#-1 INVALID TIME ARGUMENT", buff, bp);
-               return;
-       }
-
-       switch((signal_r = do_signal_qid(executor, atoi(args[0]), qsig, qsig == QID_TIME ? atoi(args[2]) : -1))) {
-               case 0:
-                       safe_str("#-1 INVALID TIME ARGUMENT", buff, bp);
-                       break;
-               case -1:
-                       safe_str("#-1 INVALID QID", buff, bp);
-                       break;
-               case -2: /* we shouldn't be getting this */
-                       safe_str("#-1 INVALID SIGNAL", buff, bp);
-                       break;
-               case -3:
-                       safe_str("#-1 PERMISSION DENIED", buff, bp);
-               default:
-                       safe_integer(signal_r > -1 ? signal_r : 0, buff, bp);
-                       break;
-       }
-               
-}
-
-FUNCTION(fun_trigger) {
-
-       if(!args[0] || !*args[0]) {
-               safe_str("#-1 INVALID ARGUMENTS", buff, bp);
-               return;
-       }
-       if(!command_check_byname(executor, "@trigger")){
-               safe_str("#-1 PERMISSION DENIED", buff, bp);
-               return;
-       }
-
-       do_trigger(executor, args[0], args);
-}
-