/*
* cque.c -- commands and functions for manipulating the command queue
*/
#include "copyright.h"
#include "config.h"
#include <signal.h>
#include "mudconf.h"
#include "config.h"
#include "db.h"
#include "htab.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "attrs.h"
#include "flags.h"
#include "powers.h"
#include "command.h"
#include "alloc.h"
#include "functions.h"
#include "cque.h"
#include "mmdb.h"
extern int a_Queue(dbref, int);
extern void s_Queue(dbref, int);
extern int QueueMax(dbref);
static rbtree obq = NULL;
static int objqe_compare(dbref left, dbref right, void *arg)
{
return (right - left);
}
int cque_init()
{
obq = rb_init((void *) objqe_compare, NULL);
return 1;
};
static OBJQE *cque_find(dbref player)
{
OBJQE *tmp = NULL;
if(obq == NULL) {
cque_init();
}
tmp = rb_find(obq, (void *) player);
if(!tmp && Good_obj(player)) {
tmp = malloc(sizeof(OBJQE));
tmp->obj = player;
tmp->cque = NULL;
tmp->ctail = NULL;
tmp->next = NULL;
tmp->queued = 0;
tmp->wait_que = NULL;
tmp->pending_que = NULL;
rb_insert(obq, (void *) player, tmp);
}
return tmp;
}
static BQUE *cque_peek(dbref player)
{
OBJQE *tmp;
tmp = cque_find(player);
return tmp->cque;
}
static BQUE *cque_deque(dbref player)
{
OBJQE *tmp;
BQUE *cmd;
tmp = cque_find(player);
if(!tmp)
return NULL;
dassert(tmp);
if(!tmp->cque)
return NULL;
cmd = tmp->cque;
if(!cmd->next) {
tmp->cque = tmp->ctail = NULL;
} else {
tmp->cque = cmd->next;
}
return cmd;
}
static void cque_enqueue(dbref player, BQUE * cmd)
{
BQUE *point, *trail;
OBJQE *current, *blocker;
struct timeval tv;
OBJQE *tmp;
cmd->next = NULL;
tv.tv_sec = cmd->waittime - mudstate.now;
tv.tv_usec = 0;
if(cmd->sem == NOTHING) {
/*
* No semaphore, put on wait queue if wait value specified.
* Otherwise put on the normal queue.
*/
if(cmd->waittime <= mudstate.now) {
cmd->waittime = 0;
tmp = cque_find(player);
dassert(tmp);
if(!tmp->ctail) {
tmp->cque = tmp->ctail = cmd;
cmd->next = NULL;
} else {
tmp->ctail->next = cmd;
tmp->ctail = cmd;
tmp->ctail->next = NULL;
}
if(!tmp->queued) {
if(!mudstate.qhead) {
mudstate.qhead = mudstate.qtail = tmp;
tmp->next = NULL;
} else {
mudstate.qtail->next = tmp;
mudstate.qtail = tmp;
mudstate.qtail->next = NULL;
}
tmp->queued = 1;
}
} else {
evtimer_add(&cmd->ev, &tv);
for(point = mudstate.qwait, trail = NULL;
point && point->waittime <= cmd->waittime;
point = point->next) {
trail = point;
}
cmd->next = point;
if(trail != NULL)
trail->next = cmd;
else
mudstate.qwait = cmd;
}
} else {
cmd->next = NULL;
if(mudstate.qsemlast != NULL)
mudstate.qsemlast->next = cmd;
else
mudstate.qsemfirst = cmd;
mudstate.qsemlast = cmd;
}
}
static void wakeup_wait_que(int fd, short event, void *arg)
{
BQUE *pending = (BQUE *) arg;
BQUE *point, trail;
if(mudstate.qwait == pending) {
mudstate.qwait = pending->next;
} else {
for(point = mudstate.qwait; point; point = point->next) {
if(point->next == pending) {
point->next = point->next->next;
break;
}
}
}
pending->waittime = 0;
cque_enqueue(pending->player, pending);
}
static int dump_bqe(struct mmdb_t *mmdb, BQUE *bqe) {
if(bqe == NULL) {
mmdb_write_uint32(mmdb, 0);
return 1;
}
mmdb_write_uint32(mmdb, 1);
mmdb_write_uint32(mmdb, bqe->player);
mmdb_write_uint32(mmdb, bqe->cause);
mmdb_write_uint32(mmdb, bqe->sem);
mmdb_write_uint32(mmdb, bqe->waittime-mudstate.now);
mmdb_write_uint32(mmdb, bqe->attr);
mmdb_write_string(mmdb, bqe->text);
mmdb_write_string(mmdb, bqe->comm);
mmdb_write_uint32(mmdb, NUM_ENV_VARS);
for(int i = 0; i < NUM_ENV_VARS; i++) {
mmdb_write_string(mmdb, bqe->env[i]);
}
mmdb_write_uint32(mmdb, NUM_ENV_VARS);
for(int i = 0; i < NUM_ENV_VARS; i++) {
mmdb_write_string(mmdb, bqe->scr[i]);
}
mmdb_write_uint32(mmdb, bqe->nargs);
dump_bqe(mmdb, bqe->next);
return 1;
}
static int dump_objqe(void *key, void *data, int depth, void *arg) {
struct mmdb_t *mmdb = (struct mmdb_t *)arg;
OBJQE *coq = (OBJQE *)data;
mmdb_write_uint32(mmdb, coq->obj);
dump_bqe(mmdb, coq->cque);
return 1;
}
void cque_dump_restart(struct mmdb_t *mmdb) {
if(obq == NULL) {
cque_init();
}
mmdb_write_uint32(mmdb, rb_size(obq));
if(rb_size(obq) > 0) {
rb_walk(obq, WALK_INORDER, dump_objqe, mmdb);
}
dump_bqe(mmdb, mudstate.qwait);
dump_bqe(mmdb, mudstate.qsemfirst);
}
static void load_bqe(struct mmdb_t *mmdb) {
int exists, count;
struct timeval tv;
BQUE *tmp;
exists = mmdb_read_uint32(mmdb);
if(!exists)
return;
tmp = malloc(sizeof(BQUE));
memset(tmp, 0, sizeof(BQUE));
evtimer_set(&tmp->ev, wakeup_wait_que, tmp);
tmp->player = mmdb_read_uint32(mmdb);
tmp->cause = mmdb_read_uint32(mmdb);
tmp->sem = mmdb_read_uint32(mmdb);
tmp->waittime = mudstate.now + mmdb_read_uint32(mmdb);
tmp->attr = mmdb_read_uint32(mmdb);
tmp->text = mmdb_read_string(mmdb);
tmp->comm = mmdb_read_string(mmdb);
count = mmdb_read_uint32(mmdb);
if(count != NUM_ENV_VARS)
printk("brain damage, count(%d) != NUM_ENV_VARS(%d)", count, NUM_ENV_VARS);
for(int i = 0; i < count; i++) {
if(i < NUM_ENV_VARS)
tmp->env[i] = mmdb_read_string(mmdb);
else
free(mmdb_read_string(mmdb));
}
count = mmdb_read_uint32(mmdb);
if(count != NUM_ENV_VARS)
printk("brain damage, count(%d) != NUM_ENV_VARS(%d)", count, NUM_ENV_VARS);
for(int i = 0; i < count; i++) {
if(i < NUM_ENV_VARS)
tmp->scr[i] = mmdb_read_string(mmdb);
else
free(mmdb_read_string(mmdb));
}
tmp->nargs = mmdb_read_uint32(mmdb);
cque_enqueue(tmp->player, tmp);
load_bqe(mmdb);
}
static void load_objqe(struct mmdb_t *mmdb) {
int object;
OBJQE *coq;
object = mmdb_read_uint32(mmdb);
coq = cque_find(object);
load_bqe(mmdb);
}
void cque_load_restart(struct mmdb_t *mmdb) {
int count;
count = mmdb_read_uint32(mmdb);
for(int i = 0; i < count; i++) {
load_objqe(mmdb);
}
load_bqe(mmdb); // wait q
load_bqe(mmdb); // sem q
}
#if 0
void cque_dump_restart(FILE *f) {
OBJQE *coq;
BQUE *bqe;
if(!mudstate.qhead) {
fprintf(f, "%d\n", 0);
return;
}
for(coq = mudstate.qhead; coq != NULL; coq = coq->next) {
fprintf("%d\n", coq->obj);
for(bqe = coq->cque; bqe != NULL; bqe = bqe->next) {
fprintf(f, "1\n");
fprintf(f, "%d\n%d\n%d\n", bqe->player, bqe->cause, bqe->sem);
fprintf(f, "%d\n%d\n", bqe->waittime - mudstate.now, bqe->attr);
fprintf(f, "");
}
}
#endif
/*
* ---------------------------------------------------------------------------
* * add_to: Adjust an object's queue or semaphore count.
*/
static int add_to(dbref player, int am, int attrnum)
{
int num, aflags;
dbref aowner;
char buff[20];
char *atr_gotten;
num = atoi(atr_gotten = atr_get(player, attrnum, &aowner, &aflags));
free_lbuf(atr_gotten);
num += am;
if(num)
sprintf(buff, "%d", num);
else
*buff = '\0';
atr_add_raw(player, attrnum, buff);
return (num);
}
/*
* ---------------------------------------------------------------------------
* * que_want: Do we want this queue entry?
*/
static int que_want(BQUE * entry, dbref ptarg, dbref otarg)
{
if((ptarg != NOTHING) && (ptarg != Owner(entry->player)))
return 0;
if((otarg != NOTHING) && (otarg != entry->player))
return 0;
return 1;
}
/*
* ---------------------------------------------------------------------------
* * halt_que: Remove all queued commands from a certain player
*/
int halt_que(dbref player, dbref object)
{
BQUE *trail, *point, *next;
OBJQE *pque;
int numhalted;
numhalted = 0;
/* Player's que */
// XXX: nuke queu
pque = cque_find(player);
if(pque && pque->cque) {
while ((point = cque_deque(player)) != NULL) {
free(point->text);
point->text = NULL;
free_qentry(point);
point = NULL;
numhalted++;
}
}
pque = cque_find(object);
if(pque && pque->cque) {
while ((point = cque_deque(object)) != NULL) {
free(point->text);
point->text = NULL;
free_qentry(point);
point = NULL;
numhalted++;
}
}
/*
* Wait queue
*/
for(point = mudstate.qwait, trail = NULL; point; point = next)
if(que_want(point, player, object)) {
numhalted++;
if(trail)
trail->next = next = point->next;
else
mudstate.qwait = next = point->next;
if(evtimer_pending(&point->ev, NULL))
evtimer_del(&point->ev);
free(point->text);
free_qentry(point);
} else
next = (trail = point)->next;
/*
* Semaphore queue
*/
for(point = mudstate.qsemfirst, trail = NULL; point; point = next)
if(que_want(point, player, object)) {
numhalted++;
if(trail)
trail->next = next = point->next;
else
mudstate.qsemfirst = next = point->next;
if(point == mudstate.qsemlast)
mudstate.qsemlast = trail;
add_to(point->sem, -1, point->attr);
free(point->text);
free_qentry(point);
} else
next = (trail = point)->next;
if(player == NOTHING)
player = Owner(object);
giveto(player, (mudconf.waitcost * numhalted));
if(object == NOTHING)
s_Queue(player, 0);
else
a_Queue(player, -numhalted);
return numhalted;
}
/*
* ---------------------------------------------------------------------------
* * do_halt: Command interface to halt_que.
*/
void do_halt(dbref player, dbref cause, int key, char *target)
{
dbref player_targ, obj_targ;
int numhalted;
if((key & HALT_ALL) && !(Can_Halt(player))) {
notify(player, "Permission denied.");
return;
}
/*
* Figure out what to halt
*/
if(!target || !*target) {
obj_targ = NOTHING;
if(key & HALT_ALL) {
player_targ = NOTHING;
} else {
player_targ = Owner(player);
if(Typeof(player) != TYPE_PLAYER)
obj_targ = player;
}
} else {
if(Can_Halt(player))
obj_targ = match_thing(player, target);
else
obj_targ = match_controlled(player, target);
if(obj_targ == NOTHING)
return;
if(key & HALT_ALL) {
notify(player, "Can't specify a target and /all");
return;
}
if(Typeof(obj_targ) == TYPE_PLAYER) {
player_targ = obj_targ;
obj_targ = NOTHING;
} else {
player_targ = NOTHING;
}
}
numhalted = halt_que(player_targ, obj_targ);
if(Quiet(player))
return;
if(numhalted == 1)
notify(Owner(player), "1 queue entries removed.");
else
notify_printf(Owner(player), "%d queue entries removed.", numhalted);
}
/*
* ---------------------------------------------------------------------------
* * nfy_que: Notify commands from the queue and perform or discard them.
*/
int nfy_que(dbref sem, int attr, int key, int count)
{
BQUE *point, *trail, *next;
int num, aflags;
dbref aowner;
char *str;
if(attr) {
str = atr_get(sem, attr, &aowner, &aflags);
num = atoi(str);
free_lbuf(str);
} else {
num = 1;
}
if(num > 0) {
num = 0;
for(point = mudstate.qsemfirst, trail = NULL; point; point = next) {
if((point->sem == sem) && ((point->attr == attr) || !attr)) {
num++;
if(trail)
trail->next = next = point->next;
else
mudstate.qsemfirst = next = point->next;
if(point == mudstate.qsemlast)
mudstate.qsemlast = trail;
/*
* Either run or discard the command
*/
if(key != NFY_DRAIN) {
point->sem = NOTHING;
point->waittime = 0;
cque_enqueue(point->player, point);
} else {
giveto(point->player, mudconf.waitcost);
a_Queue(Owner(point->player), -1);
free(point->text);
free_qentry(point);
}
} else {
next = (trail = point)->next;
}
/*
* If we've notified enough, exit
*/
if((key == NFY_NFY) && (num >= count))
next = NULL;
}
} else {
num = 0;
}
/*
* Update the sem waiters count
*/
if(key == NFY_NFY)
add_to(sem, -count, attr);
else
atr_clr(sem, attr);
return num;
}
/*
* ---------------------------------------------------------------------------
* * do_notify: Command interface to nfy_que
*/
void do_notify(dbref player, dbref cause, int key, char *what, char *count)
{
dbref thing, aowner;
int loccount, attr = -1, aflags;
ATTR *ap;
char *obj;
obj = parse_to(&what, '/', 0);
init_match(player, obj, NOTYPE);
match_everything(0);
if((thing = noisy_match_result()) < 0) {
notify(player, "No match.");
} else if(!controls(player, thing) && !Link_ok(thing)) {
notify(player, "Permission denied.");
} else {
if(!what || !*what) {
ap = NULL;
} else {
ap = atr_str(what);
}
if(!ap) {
attr = A_SEMAPHORE;
} else {
/* Do they have permission to set this attribute? */
atr_pget_info(thing, ap->number, &aowner, &aflags);
if(Set_attr(player, thing, ap, aflags)) {
attr = ap->number;
} else {
notify_quiet(player, "Permission denied.");
return;
}
}
if(count && *count)
loccount = atoi(count);
else
loccount = 1;
if(loccount > 0) {
nfy_que(thing, attr, key, loccount);
if(!(Quiet(player) || Quiet(thing))) {
if(key == NFY_DRAIN)
notify_quiet(player, "Drained.");
else
notify_quiet(player, "Notified.");
}
}
}
}
/*
* ---------------------------------------------------------------------------
* * setup_que: Set up a queue entry.
*/
static BQUE *setup_que(dbref player, dbref cause, char *command, char *args[],
int nargs, char *sargs[])
{
int a, tlen;
BQUE *tmp;
char *tptr;
/*
* Can we run commands at all?
*/
if(Halted(player))
return NULL;
/*
* make sure player can afford to do it
*/
a = mudconf.waitcost;
if(mudconf.machinecost && ((random() % mudconf.machinecost) == 0))
a++;
if(!payfor(player, a)) {
notify(Owner(player), "Not enough money to queue command.");
return NULL;
}
/*
* Wizards and their objs may queue up to db_top+1 cmds. Players are
* * * * * * * limited to QUEUE_QUOTA. -mnp
*/
a = QueueMax(Owner(player));
if(a_Queue(Owner(player), 1) > a) {
notify(Owner(player),
"Run away objects: too many commands queued. Halted.");
halt_que(Owner(player), NOTHING);
/*
* halt also means no command execution allowed
*/
s_Halted(player);
return NULL;
}
/*
* We passed all the tests
*/
/*
* Calculate the length of the save string
*/
tlen = 0;
if(command)
tlen = strlen(command) + 1;
if(nargs > NUM_ENV_VARS)
nargs = NUM_ENV_VARS;
for(a = 0; a < nargs; a++) {
if(args[a])
tlen += (strlen(args[a]) + 1);
}
if(sargs) {
for(a = 0; a < NUM_ENV_VARS; a++) {
if(sargs[a])
tlen += (strlen(sargs[a]) + 1);
}
}
/*
* Create the qeue entry and load the save string
*/
tmp = malloc(sizeof(BQUE));
memset(tmp, 0, sizeof(BQUE));
tmp->comm = NULL;
for(a = 0; a < NUM_ENV_VARS; a++) {
tmp->env[a] = NULL;
}
for(a = 0; a < MAX_GLOBAL_REGS; a++) {
tmp->scr[a] = NULL;
}
tptr = tmp->text = (char *) malloc(tlen);
if(command) {
StringCopy(tptr, command);
tmp->comm = tptr;
tptr += (strlen(command) + 1);
}
for(a = 0; a < nargs; a++) {
if(args[a]) {
StringCopy(tptr, args[a]);
tmp->env[a] = tptr;
tptr += (strlen(args[a]) + 1);
}
}
if(sargs) {
for(a = 0; a < MAX_GLOBAL_REGS; a++) {
if(sargs[a]) {
StringCopy(tptr, sargs[a]);
tmp->scr[a] = tptr;
tptr += (strlen(sargs[a]) + 1);
}
}
}
/*
* Load the rest of the queue block
*/
evtimer_set(&tmp->ev, wakeup_wait_que, tmp);
tmp->player = player;
tmp->waittime = 0;
tmp->next = NULL;
tmp->sem = NOTHING;
tmp->attr = 0;
tmp->cause = cause;
tmp->nargs = nargs;
return tmp;
}
/*
* ---------------------------------------------------------------------------
* * wait_que: Add commands to the wait or semaphore queues.
*/
void wait_que(dbref player, dbref cause, int wait, dbref sem, int attr,
char *command, char *args[], int nargs, char *sargs[])
{
BQUE *cmd;
if(mudconf.control_flags & CF_INTERP)
cmd = setup_que(player, cause, command, args, nargs, sargs);
else
cmd = NULL;
if(cmd == NULL) {
return;
}
if(wait > 0) {
cmd->waittime = mudstate.now + wait;
} else {
cmd->waittime = 0;
}
cmd->sem = sem;
cmd->attr = attr;
cque_enqueue(player, cmd);
}
/*
* ---------------------------------------------------------------------------
* * do_wait: Command interface to wait_que
*/
void do_wait(dbref player, dbref cause, int key, char *event, char *cmd,
char *cargs[], int ncargs)
{
dbref thing, aowner;
int howlong, num, attr, aflags;
char *what;
ATTR *ap;
/*
* If arg1 is all numeric, do simple (non-sem) timed wait.
*/
if(is_number(event)) {
howlong = atoi(event);
wait_que(player, cause, howlong, NOTHING, 0, cmd, cargs, ncargs,
mudstate.global_regs);
return;
}
/*
* Semaphore wait with optional timeout
*/
what = parse_to(&event, '/', 0);
init_match(player, what, NOTYPE);
match_everything(0);
thing = noisy_match_result();
if(!Good_obj(thing)) {
notify(player, "No match.");
} else if(!controls(player, thing) && !Link_ok(thing)) {
notify(player, "Permission denied.");
} else {
/*
* Get timeout, default 0
*/
if(event && *event && is_number(event)) {
attr = A_SEMAPHORE;
howlong = atoi(event);
} else {
attr = A_SEMAPHORE;
howlong = 0;
}
if(event && *event && !is_number(event)) {
ap = atr_str(event);
if(!ap) {
attr = mkattr(event);
if(attr <= 0) {
notify_quiet(player, "Invalid attribute.");
return;
}
ap = atr_num(attr);
}
atr_pget_info(thing, ap->number, &aowner, &aflags);
if(attr && Set_attr(player, thing, ap, aflags)) {
attr = ap->number;
howlong = 0;
} else {
notify_quiet(player, "Permission denied.");
return;
}
}
num = add_to(thing, 1, attr);
if(num <= 0) {
/*
* thing over-notified, run the command immediately
*/
thing = NOTHING;
howlong = 0;
}
wait_que(player, cause, howlong, thing, attr, cmd, cargs, ncargs,
mudstate.global_regs);
}
}
/*
* ---------------------------------------------------------------------------
* * do_second: Check the wait and semaphore queues for commands to remove.
*/
void do_second(void)
{
BQUE *trail, *point, *next;
char *cmdsave;
/*
* move contents of low priority queue onto end of normal one this
* helps to keep objects from getting out of control since
* its affects on other objects happen only after one
* second this should allow @halt to be type before
* getting blown away by scrolling text
*/
if((mudconf.control_flags & CF_DEQUEUE) == 0)
return;
cmdsave = mudstate.debug_cmd;
mudstate.debug_cmd = (char *) "< do_second >";
/*
* Note: the point->waittime test would be 0 except the command is
* being put in the low priority queue to be done in one
* second anyways
*/
/*
* Check the semaphore queue for expired timed-waits
*/
for(point = mudstate.qsemfirst, trail = NULL; point; point = next) {
if(point->waittime == 0) {
next = (trail = point)->next;
continue; /*
* Skip if not timed-wait
*/
}
if(point->waittime <= mudstate.now) {
if(trail != NULL)
trail->next = next = point->next;
else
mudstate.qsemfirst = next = point->next;
if(point == mudstate.qsemlast)
mudstate.qsemlast = trail;
add_to(point->sem, -1, point->attr);
point->sem = NOTHING;
point->waittime = 0;
printk("promoting, %d/%s", point->player, point->comm);
cque_enqueue(point->player, point);
} else
next = (trail = point)->next;
}
mudstate.debug_cmd = cmdsave;
return;
}
/*
* ---------------------------------------------------------------------------
* * do_top: Execute the command at the top of the queue
*/
int do_top(int ncmds)
{
BQUE *tmp, *walk;
OBJQE *current_object;
dbref object, player, last_player;
int count, i;
char *command, *cp, *cmdsave;
if((mudconf.control_flags & CF_DEQUEUE) == 0)
return 0;
cmdsave = mudstate.debug_cmd;
mudstate.debug_cmd = (char *) "< do_top >";
if(!mudstate.qhead)
return 0;
current_object = mudstate.qhead;
count = 0;
while (count < ncmds && mudstate.qhead) {
if(!mudstate.qhead)
break;
object = mudstate.qhead->obj;
tmp = cque_deque(object);
if(!mudstate.qhead->cque) {
mudstate.qhead->queued = 0;
mudstate.qhead = mudstate.qhead->next;
if(mudstate.qhead == NULL)
mudstate.qtail = NULL;
} else {
mudstate.qtail->next = mudstate.qhead;
mudstate.qtail = mudstate.qtail->next;
mudstate.qhead = mudstate.qhead->next;
mudstate.qtail->next = NULL;
}
if(!tmp)
continue;
dassert(tmp);
count++;
if((object >= 0) && !Going(object)) {
giveto(object, mudconf.waitcost);
mudstate.curr_enactor = tmp->cause;
mudstate.curr_player = object;
a_Queue(Owner(object), -1);
if(!Halted(object)) {
for(i = 0; i < MAX_GLOBAL_REGS; i++) {
if(tmp->scr[i]) {
StringCopy(mudstate.global_regs[i], tmp->scr[i]);
} else {
*mudstate.global_regs[i] = '\0';
}
}
command = tmp->comm;
if(command) {
if(isPlayer(object) && Connected(object))
choke_player(object);
while (command) {
cp = parse_to(&command, ';', 0);
if(cp && *cp) {
while (command && (*command == '|')) {
command++;
mudstate.inpipe = 1;
mudstate.poutnew =
alloc_lbuf("process_command.pipe");
mudstate.poutbufc = mudstate.poutnew;
mudstate.poutobj = object;
process_command(object, tmp->cause, 0, cp,
tmp->env, tmp->nargs);
if(mudstate.pout) {
free_lbuf(mudstate.pout);
mudstate.pout = NULL;
}
*mudstate.poutbufc = '\0';
mudstate.pout = mudstate.poutnew;
cp = parse_to(&command, ';', 0);
}
mudstate.inpipe = 0;
process_command(object, tmp->cause, 0,
cp, tmp->env, tmp->nargs);
if(mudstate.pout) {
free_lbuf(mudstate.pout);
mudstate.pout = NULL;
}
}
}
if(isPlayer(object) && Connected(object))
release_player(object);
}
}
}
free(tmp->text);
free_qentry(tmp);
}
for(i = 0; i < MAX_GLOBAL_REGS; i++)
*mudstate.global_regs[i] = '\0';
mudstate.debug_cmd = cmdsave;
return count;
}
/*
* ---------------------------------------------------------------------------
* * do_ps: tell player what commands they have pending in the queue
*/
static void show_que(dbref player, int key, BQUE * queue, int *qent,
const char *header)
{
BQUE *tmp;
char *bp, *bufp;
int i;
for(tmp = queue; tmp; tmp = tmp->next) {
(*qent)++;
if(key == PS_SUMM)
continue;
if(*qent == 1)
notify_printf(player, "----- %s Queue -----", header);
bufp = unparse_object(player, tmp->player, 0);
if((tmp->waittime > 0) && (Good_obj(tmp->sem)))
notify_printf(player, "[#%d/%d]%s:%s", tmp->sem,
tmp->waittime-mudstate.now, bufp, tmp->comm);
else if(tmp->waittime > 0)
notify_printf(player, "[%d]%s:%s", tmp->waittime-mudstate.now,
bufp, tmp->comm);
else if(Good_obj(tmp->sem))
notify_printf(player, "[#%d]%s:%s", tmp->sem, bufp, tmp->comm);
else
notify_printf(player, "%s:%s", bufp, tmp->comm);
bp = bufp;
if(key == PS_LONG) {
for(i = 0; i < (tmp->nargs); i++) {
if(tmp->env[i] != NULL) {
safe_str((char *) "; Arg", bufp, &bp);
safe_chr(i + '0', bufp, &bp);
safe_str((char *) "='", bufp, &bp);
safe_str(tmp->env[i], bufp, &bp);
safe_chr('\'', bufp, &bp);
}
}
*bp = '\0';
bp = unparse_object(player, tmp->cause, 0);
notify_printf(player, " Enactor: %s%s", bp, bufp);
free_lbuf(bp);
}
free_lbuf(bufp);
}
return;
}
void do_ps(dbref player, dbref cause, int key, char *target)
{
char *bufp;
dbref player_targ, obj_targ;
int pqent, pqtot, pqdel, oqent, oqtot, oqdel, wqent, wqtot, sqent,
sqtot, i;
OBJQE *objq;
/*
* Figure out what to list the queue for
*/
if((key & PS_ALL) && !(See_Queue(player))) {
notify(player, "Permission denied.");
return;
}
if(!target || !*target) {
obj_targ = NOTHING;
if(key & PS_ALL) {
player_targ = NOTHING;
} else {
player_targ = Owner(player);
if(Typeof(player) != TYPE_PLAYER)
obj_targ = player;
}
} else {
player_targ = Owner(player);
obj_targ = match_controlled(player, target);
if(obj_targ == NOTHING)
return;
if(key & PS_ALL) {
notify(player, "Can't specify a target and /all");
return;
}
if(Typeof(obj_targ) == TYPE_PLAYER) {
player_targ = obj_targ;
obj_targ = NOTHING;
}
}
key = key & ~PS_ALL;
switch (key) {
case PS_BRIEF:
case PS_SUMM:
case PS_LONG:
break;
default:
notify(player, "Illegal combination of switches.");
return;
}
/*
* Go do it
*/
pqtot = 0;
if(player_targ == NOTHING) {
objq = mudstate.qhead;
while (objq && (objq = objq->next) != NULL) {
pqent = 0;
show_que(player, key, objq->cque, &pqent, "PLAYAH");
pqtot += pqent;
}
} else {
pqent = 0;
objq = cque_find(player_targ);
if(objq) {
show_que(player, key, objq->cque, &pqent, "PLAYAH");
}
}
wqent = 0;
sqent = 0;
wqtot = 0;
sqtot = 0;
show_que(player, key, mudstate.qwait, &wqent, "Wait");
show_que(player, key, mudstate.qsemfirst, &sqent, "Semaphore");
/*
* Display stats
*/
if(See_Queue(player))
notify_printf(player,
"Totals: Player...%d/%d Wait...%d/%d Semaphore...%d/%d",
pqent, pqtot, wqent, wqtot, sqent, sqtot);
else
notify_printf(player,
"Totals: Player...%d/%d Wait...%d/%d Semaphore...%d/%d",
pqent, pqtot, wqent, wqtot, sqent, sqtot);
}
/*
* ---------------------------------------------------------------------------
* * do_queue: Queue management
*/
void do_queue(dbref player, dbref cause, int key, char *arg)
{
BQUE *point;
int i, ncmds, was_disabled;
dprintk("WTF?");
was_disabled = 0;
if(key == QUEUE_KICK) {
i = atoi(arg);
if((mudconf.control_flags & CF_DEQUEUE) == 0) {
was_disabled = 1;
mudconf.control_flags |= CF_DEQUEUE;
notify(player, "Warning: automatic dequeueing is disabled.");
}
ncmds = do_top(i);
if(was_disabled)
mudconf.control_flags &= ~CF_DEQUEUE;
if(!Quiet(player))
notify_printf(player, "%d commands processed.", ncmds);
} else if(key == QUEUE_WARP) {
i = atoi(arg);
if((mudconf.control_flags & CF_DEQUEUE) == 0) {
was_disabled = 1;
mudconf.control_flags |= CF_DEQUEUE;
notify(player, "Warning: automatic dequeueing is disabled.");
}
/*
* Handle the semaphore queue
*/
for(point = mudstate.qsemfirst; point; point = point->next) {
if(point->waittime > 0) {
point->waittime -= i;
if(point->waittime <= 0)
point->waittime = -1;
}
}
do_second();
if(was_disabled)
mudconf.control_flags &= ~CF_DEQUEUE;
if(Quiet(player))
return;
if(i > 0)
notify_printf(player, "WaitQ timer advanced %d seconds.", i);
else if(i < 0)
notify_printf(player, "WaitQ timer set back %d seconds.", i);
else
notify(player, "Object queue appended to player queue.");
}
}