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>])
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()
/** 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;
/* Update bookkeeping */
count--;
+ affected++;
add_to_sem(entry->sem, -1, entry->semattr);
/* Dispose of the entry as appropriate: discard if @drain, or put
* @notify/any or @notify/all. */
if (!drain && aname && !all && count > 0)
add_to_sem(thing, -count, aname);
+
+ return affected;
}
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."));
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);
}
{"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},
{"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},
{"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},