// walkdb.cpp -- Support for commands that walk the entire db.
//
// $Id: walkdb.cpp,v 1.11 2004/08/16 05:14:07 sdennis Exp $
//
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"
#include "misc.h"
#include "attrs.h"
// Bind occurances of the universal var in ACTION to ARG, then run ACTION.
// Cmds run in low-prio Q after a 1 sec delay for the first one.
//
static void bind_and_queue(dbref executor, dbref caller, dbref enactor,
char *action, char *argstr, char *cargs[],
int ncargs, int number)
{
char *command = replace_tokens(action, argstr, mux_ltoa_t(number), NULL);
CLinearTimeAbsolute lta;
wait_que(executor, caller, enactor, false, lta, NOTHING, 0, command,
cargs, ncargs, mudstate.global_regs);
free_lbuf(command);
}
// New @dolist. i.e.:
// @dolist #12 #34 #45 #123 #34644=@emit [name(##)]
//
// New switches added 12/92, /space (default) delimits list using spaces,
// and /delimit allows specification of a delimiter.
//
void do_dolist(dbref executor, dbref caller, dbref enactor, int key,
char *list, char *command, char *cargs[], int ncargs)
{
if (!list || *list == '\0')
{
notify(executor, "That's terrific, but what should I do with the list?");
return;
}
char *objstring, delimiter = ' ';
int number = 0;
char *curr = list;
if (key & DOLIST_DELIMIT)
{
char *tempstr = parse_to(&curr, ' ', EV_STRIP_CURLY);
if (strlen(tempstr) > 1)
{
notify(executor, "The delimiter must be a single character!");
return;
}
delimiter = *tempstr;
}
while (curr && *curr)
{
while (*curr == delimiter)
{
curr++;
}
if (*curr)
{
number++;
objstring = parse_to(&curr, delimiter, EV_STRIP_CURLY);
bind_and_queue(executor, caller, enactor, command, objstring,
cargs, ncargs, number);
}
}
if (key & DOLIST_NOTIFY)
{
char *tbuf = alloc_lbuf("dolist.notify_cmd");
strcpy(tbuf, "@notify/quiet me");
CLinearTimeAbsolute lta;
wait_que(executor, caller, enactor, false, lta, NOTHING, A_SEMAPHORE,
tbuf, cargs, ncargs, mudstate.global_regs);
free_lbuf(tbuf);
}
}
// Regular @find command
//
void do_find(dbref executor, dbref caller, dbref enactor, int key, char *name)
{
char *buff;
if (!payfor(executor, mudconf.searchcost))
{
buff = tprintf("You don't have enough %s.", mudconf.many_coins);
notify_quiet(executor, buff);
return;
}
dbref i, low_bound, high_bound;
parse_range(&name, &low_bound, &high_bound);
for (i = low_bound; i <= high_bound; i++)
{
if ( (Typeof(i) != TYPE_EXIT)
&& Controls(executor, i)
&& (!*name || string_match(PureName(i), name)))
{
buff = unparse_object(executor, i, false);
notify(executor, buff);
free_lbuf(buff);
}
}
notify(executor, "***End of List***");
}
// ---------------------------------------------------------------------------
// get_stats, do_stats: Get counts of items in the db.
//
bool get_stats(dbref player, dbref who, STATS *info)
{
// Do we have permission?
//
if (Good_obj(who) && !Controls(player, who) && !Stat_Any(player))
{
notify(player, NOPERM_MESSAGE);
return false;
}
// Can we afford it?
//
if (!payfor(player, mudconf.searchcost))
{
notify(player, tprintf("You don't have enough %s.", mudconf.many_coins));
return false;
}
info->s_total = 0;
info->s_rooms = 0;
info->s_exits = 0;
info->s_things = 0;
info->s_players = 0;
info->s_garbage = 0;
dbref i;
DO_WHOLE_DB(i)
{
if ((who == NOTHING) || (who == Owner(i)))
{
info->s_total++;
if (Going(i) && (Typeof(i) != TYPE_ROOM))
{
info->s_garbage++;
continue;
}
switch (Typeof(i))
{
case TYPE_ROOM:
info->s_rooms++;
break;
case TYPE_EXIT:
info->s_exits++;
break;
case TYPE_THING:
info->s_things++;
break;
case TYPE_PLAYER:
info->s_players++;
break;
default:
info->s_garbage++;
}
}
}
return true;
}
// Reworked by R'nice
//
void do_stats(dbref executor, dbref caller, dbref enactor, int key, char *name)
{
dbref owner;
switch (key)
{
case STAT_ALL:
owner = NOTHING;
break;
case STAT_ME:
owner = Owner(executor);
break;
case STAT_PLAYER:
if (!(name && *name))
{
int nNextFree = mudstate.freelist;
if (mudstate.freelist == NOTHING)
{
nNextFree = mudstate.db_top;
}
notify(executor, tprintf("The universe contains %d objects (next free is #%d).",
mudstate.db_top, nNextFree));
return;
}
owner = lookup_player(executor, name, true);
if (owner == NOTHING)
{
notify(executor, "Not found.");
return;
}
break;
default:
notify(executor, "Illegal combination of switches.");
return;
}
STATS statinfo;
if (!get_stats(executor, owner, &statinfo))
{
return;
}
notify(executor, tprintf(
"%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)",
statinfo.s_total, statinfo.s_rooms, statinfo.s_exits,
statinfo.s_things, statinfo.s_players,
statinfo.s_garbage));
}
int chown_all(dbref from_player, dbref to_player, dbref acting_player, int key)
{
if (!isPlayer(from_player))
{
from_player = Owner(from_player);
}
if (!isPlayer(to_player))
{
to_player = Owner(to_player);
}
int count = 0;
if ( God(from_player)
&& !God(acting_player))
{
notify(acting_player, "Permission denied.");
}
else
{
int i;
int quota_out = 0;
int quota_in = 0;
DO_WHOLE_DB(i)
{
if ( Owner(i) == from_player
&& Owner(i) != i)
{
switch (Typeof(i))
{
case TYPE_PLAYER:
s_Owner(i, i);
quota_out += mudconf.player_quota;
break;
case TYPE_THING:
s_Owner(i, to_player);
quota_out += mudconf.thing_quota;
quota_in -= mudconf.thing_quota;
break;
case TYPE_ROOM:
s_Owner(i, to_player);
quota_out += mudconf.room_quota;
quota_in -= mudconf.room_quota;
break;
case TYPE_EXIT:
s_Owner(i, to_player);
quota_out += mudconf.exit_quota;
quota_in -= mudconf.exit_quota;
break;
default:
s_Owner(i, to_player);
}
s_Flags(i, FLAG_WORD1,
(Flags(i) & ~(CHOWN_OK | INHERIT)) | HALT);
if (key & CHOWN_NOZONE)
{
s_Zone(i, NOTHING);
}
count++;
}
}
add_quota(from_player, quota_out);
add_quota(to_player, quota_in);
}
return count;
}
void do_chownall
(
dbref executor,
dbref caller,
dbref enactor,
int key,
int nargs,
char *from,
char *to
)
{
int count;
dbref victim, recipient;
init_match(executor, from, TYPE_PLAYER);
match_neighbor();
match_absolute();
match_player();
if ((victim = noisy_match_result()) == NOTHING)
{
return;
}
if ((to != NULL) && *to)
{
init_match(executor, to, TYPE_PLAYER);
match_neighbor();
match_absolute();
match_player();
if ((recipient = noisy_match_result()) == NOTHING)
{
return;
}
}
else
{
recipient = executor;
}
count = chown_all(victim, recipient, executor, key);
if (!Quiet(executor))
{
notify(executor, tprintf("%d objects @chowned.", count));
}
}
#define ANY_OWNER -2
void er_mark_disabled(dbref player)
{
notify(player,
"The mark commands are not allowed while DB cleaning is enabled.");
notify(player,
"Use the '@disable cleaning' command to disable automatic cleaning.");
notify(player,
"Remember to '@unmark_all' before re-enabling automatic cleaning.");
}
// ---------------------------------------------------------------------------
// do_search: Walk the db reporting various things (or setting/clearing mark
// bits)
//
bool search_setup(dbref player, char *searchfor, SEARCH *parm)
{
// Crack arg into <pname> <type>=<targ>,<low>,<high>
//
char *pname = parse_to(&searchfor, '=', EV_STRIP_TS);
if (!pname || !*pname)
{
pname = "me";
}
else
{
mux_strlwr(pname);
}
char *searchtype;
if (searchfor && *searchfor)
{
searchtype = strrchr(pname, ' ');
if (searchtype)
{
*searchtype++ = '\0';
}
else
{
searchtype = pname;
pname = "";
}
}
else
{
searchtype = "";
}
// If the player name is quoted, strip the quotes.
//
if (*pname == '\"')
{
size_t k = strlen(pname) - 1;
if (pname[k] == '"')
{
pname[k] = '\0';
pname++;
}
}
// Strip any range arguments.
//
parse_range(&searchfor, &parm->low_bound, &parm->high_bound);
// Set limits on who we search.
//
parm->s_owner = Owner(player);
parm->s_wizard = Search(player);
parm->s_rst_owner = NOTHING;
if (!*pname)
{
parm->s_rst_owner = parm->s_wizard ? ANY_OWNER : player;
}
else if (pname[0] == '#')
{
parm->s_rst_owner = mux_atol(&pname[1]);
if (!Good_obj(parm->s_rst_owner))
{
parm->s_rst_owner = NOTHING;
}
else if (Typeof(parm->s_rst_owner) != TYPE_PLAYER)
{
parm->s_rst_owner = NOTHING;
}
}
else if (strcmp(pname, "me") == 0)
{
parm->s_rst_owner = player;
}
else
{
parm->s_rst_owner = lookup_player(player, pname, true);
}
if (parm->s_rst_owner == NOTHING)
{
notify(player, tprintf("%s: No such player", pname));
return false;
}
// Set limits on what we search for.
//
int err = 0;
parm->s_rst_name = NULL;
parm->s_rst_eval = NULL;
parm->s_rst_type = NOTYPE;
parm->s_parent = NOTHING;
parm->s_zone = NOTHING;
for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++)
{
parm->s_fset.word[i] = 0;
}
parm->s_pset.word1 = 0;
parm->s_pset.word2 = 0;
switch (searchtype[0])
{
case '\0':
// The no class requested class :)
//
break;
case 'e':
if (string_prefix("exits", searchtype))
{
parm->s_rst_name = searchfor;
parm->s_rst_type = TYPE_EXIT;
}
else if (string_prefix("evaluate", searchtype))
{
parm->s_rst_eval = searchfor;
}
else if (string_prefix("eplayer", searchtype))
{
parm->s_rst_type = TYPE_PLAYER;
parm->s_rst_eval = searchfor;
}
else if (string_prefix("eroom", searchtype))
{
parm->s_rst_type = TYPE_ROOM;
parm->s_rst_eval = searchfor;
}
else if (string_prefix("eobject", searchtype))
{
parm->s_rst_type = TYPE_THING;
parm->s_rst_eval = searchfor;
}
else if (string_prefix("ething", searchtype))
{
parm->s_rst_type = TYPE_THING;
parm->s_rst_eval = searchfor;
}
else if (string_prefix("eexit", searchtype))
{
parm->s_rst_type = TYPE_EXIT;
parm->s_rst_eval = searchfor;
}
else
{
err = 1;
}
break;
case 'f':
if (string_prefix("flags", searchtype))
{
// convert_flags ignores previous values of flag_mask and
// s_rst_type while setting them.
//
if ( !convert_flags( player, searchfor, &parm->s_fset,
&parm->s_rst_type) )
{
return false;
}
}
else
{
err = 1;
}
break;
case 'n':
if (string_prefix("name", searchtype))
{
parm->s_rst_name = searchfor;
}
else
{
err = 1;
}
break;
case 'o':
if (string_prefix("objects", searchtype))
{
parm->s_rst_name = searchfor;
parm->s_rst_type = TYPE_THING;
}
else
{
err = 1;
}
break;
case 'p':
if (string_prefix("players", searchtype))
{
parm->s_rst_name = searchfor;
parm->s_rst_type = TYPE_PLAYER;
if (!*pname)
{
parm->s_rst_owner = ANY_OWNER;
}
}
else if (string_prefix("parent", searchtype))
{
parm->s_parent = match_controlled(player, searchfor);
if (!Good_obj(parm->s_parent))
{
return false;
}
if (!*pname)
{
parm->s_rst_owner = ANY_OWNER;
}
}
else if (string_prefix("power", searchtype))
{
if (!decode_power(player, searchfor, &parm->s_pset))
{
return false;
}
}
else
{
err = 1;
}
break;
case 'r':
if (string_prefix("rooms", searchtype))
{
parm->s_rst_name = searchfor;
parm->s_rst_type = TYPE_ROOM;
}
else
{
err = 1;
}
break;
case 't':
if (string_prefix("type", searchtype))
{
if (searchfor[0] == '\0')
{
break;
}
if (string_prefix("rooms", searchfor))
{
parm->s_rst_type = TYPE_ROOM;
}
else if (string_prefix("exits", searchfor))
{
parm->s_rst_type = TYPE_EXIT;
}
else if (string_prefix("objects", searchfor))
{
parm->s_rst_type = TYPE_THING;
}
else if (string_prefix("things", searchfor))
{
parm->s_rst_type = TYPE_THING;
}
else if (string_prefix("garbage", searchfor))
{
parm->s_rst_type = TYPE_GARBAGE;
}
else if (string_prefix("players", searchfor))
{
parm->s_rst_type = TYPE_PLAYER;
if (!*pname)
{
parm->s_rst_owner = ANY_OWNER;
}
}
else
{
notify(player, tprintf("%s: unknown type", searchfor));
return false;
}
}
else if (string_prefix("things", searchtype))
{
parm->s_rst_name = searchfor;
parm->s_rst_type = TYPE_THING;
}
else
{
err = 1;
}
break;
case 'z':
if (string_prefix("zone", searchtype))
{
parm->s_zone = match_controlled(player, searchfor);
if (!Good_obj(parm->s_zone))
{
return false;
}
if (!*pname)
{
parm->s_rst_owner = ANY_OWNER;
}
}
else
{
err = 1;
}
break;
default:
err = 1;
}
if (err)
{
notify(player, tprintf("%s: unknown class", searchtype));
return false;
}
// Make sure player is authorized to do the search.
//
if ( !parm->s_wizard
&& (parm->s_rst_type != TYPE_PLAYER)
&& (parm->s_rst_owner != player)
&& (parm->s_rst_owner != ANY_OWNER))
{
notify(player, "You need a search warrant to do that!");
return false;
}
// Make sure player has money to do the search.
//
if (!payfor(player, mudconf.searchcost))
{
notify(player,
tprintf("You don't have enough %s to search. (You need %d)",
mudconf.many_coins, mudconf.searchcost));
return false;
}
return true;
}
void search_perform(dbref executor, dbref caller, dbref enactor, SEARCH *parm)
{
POWER thing1powers, thing2powers;
char *result, *bp, *str;
char *buff = alloc_sbuf("search_perform.num");
int save_invk_ctr = mudstate.func_invk_ctr;
dbref thing;
for (thing = parm->low_bound; thing <= parm->high_bound; thing++)
{
mudstate.func_invk_ctr = save_invk_ctr;
// Check for matching type.
//
if ( (parm->s_rst_type != NOTYPE)
&& (parm->s_rst_type != Typeof(thing)))
{
continue;
}
// Check for matching owner.
//
if ( (parm->s_rst_owner != ANY_OWNER)
&& (parm->s_rst_owner != Owner(thing)))
{
continue;
}
// Toss out destroyed things.
//
if (Going(thing))
{
continue;
}
// Check for matching parent.
//
if ( (parm->s_parent != NOTHING)
&& (parm->s_parent != Parent(thing)))
{
continue;
}
// Check for matching zone.
//
if ( (parm->s_zone != NOTHING)
&& (parm->s_zone != Zone(thing)))
{
continue;
}
// Check for matching flags.
//
bool b = false;
for (int i = FLAG_WORD1; i <= FLAG_WORD3; i++)
{
FLAG f = parm->s_fset.word[i];
if ((db[thing].fs.word[i] & f) != f)
{
b = true;
break;
}
}
if (b)
{
continue;
}
// Check for matching power.
//
thing1powers = Powers(thing);
thing2powers = Powers2(thing);
if ((thing1powers & parm->s_pset.word1) != parm->s_pset.word1)
{
continue;
}
if ((thing2powers & parm->s_pset.word2) != parm->s_pset.word2)
{
continue;
}
// Check for matching name.
//
if (parm->s_rst_name != NULL)
{
if (!string_prefix(PureName(thing), parm->s_rst_name))
continue;
}
// Check for successful evaluation.
//
if (parm->s_rst_eval != NULL)
{
buff[0] = '#';
mux_ltoa(thing, buff+1);
char *buff2 = replace_tokens(parm->s_rst_eval, buff, NULL, NULL);
result = bp = alloc_lbuf("search_perform");
str = buff2;
mux_exec(result, &bp, executor, caller, enactor,
EV_FCHECK | EV_EVAL | EV_NOTRACE, &str, (char **)NULL, 0);
*bp = '\0';
free_lbuf(buff2);
if (!*result || !xlate(result))
{
free_lbuf(result);
continue;
}
free_lbuf(result);
}
// It passed everything. Amazing.
//
olist_add(thing);
}
free_sbuf(buff);
mudstate.func_invk_ctr = save_invk_ctr;
}
static void search_mark(dbref player, int key)
{
dbref thing;
bool is_marked;
int nchanged = 0;
for (thing = olist_first(); thing != NOTHING; thing = olist_next())
{
is_marked = Marked(thing);
// Don't bother checking if marking and already marked (or if
// unmarking and not marked)
//
if ( ((key == SRCH_MARK) && is_marked)
|| ((key == SRCH_UNMARK) && !is_marked))
{
continue;
}
// Toggle the mark bit and update the counters.
//
if (key == SRCH_MARK)
{
Mark(thing);
nchanged++;
}
else
{
Unmark(thing);
nchanged++;
}
}
notify( player, tprintf("%d objects %smarked", nchanged,
((key == SRCH_MARK) ? "" : "un")) );
return;
}
void do_search(dbref executor, dbref caller, dbref enactor, int key, char *arg)
{
char *buff, *outbuf, *bp;
dbref thing, from, to;
SEARCH searchparm;
if ((key != SRCH_SEARCH) && (mudconf.control_flags & CF_DBCHECK))
{
er_mark_disabled(executor);
return;
}
if (!search_setup(executor, arg, &searchparm))
{
return;
}
olist_push();
search_perform(executor, caller, enactor, &searchparm);
bool destitute = true;
bool flag;
// If we are doing a @mark command, handle that here.
//
if (key != SRCH_SEARCH)
{
search_mark(executor, key);
olist_pop();
return;
}
outbuf = alloc_lbuf("do_search.outbuf");
int rcount = 0;
int ecount = 0;
int tcount = 0;
int pcount = 0;
// Room search.
//
if ( searchparm.s_rst_type == TYPE_ROOM
|| searchparm.s_rst_type == NOTYPE)
{
flag = true;
for (thing = olist_first(); thing != NOTHING; thing = olist_next())
{
if (Typeof(thing) != TYPE_ROOM)
{
continue;
}
if (flag)
{
flag = false;
destitute = false;
notify(executor, "\nROOMS:");
}
buff = unparse_object(executor, thing, false);
notify(executor, buff);
free_lbuf(buff);
rcount++;
}
}
// Exit search.
//
if ( searchparm.s_rst_type == TYPE_EXIT
|| searchparm.s_rst_type == NOTYPE)
{
flag = true;
for (thing = olist_first(); thing != NOTHING; thing = olist_next())
{
if (Typeof(thing) != TYPE_EXIT)
{
continue;
}
if (flag)
{
flag = false;
destitute = false;
notify(executor, "\nEXITS:");
}
from = Exits(thing);
to = Location(thing);
bp = outbuf;
buff = unparse_object(executor, thing, false);
safe_str(buff, outbuf, &bp);
free_lbuf(buff);
safe_str(" [from ", outbuf, &bp);
buff = unparse_object(executor, from, false);
safe_str(((from == NOTHING) ? "NOWHERE" : buff), outbuf, &bp);
free_lbuf(buff);
safe_str(" to ", outbuf, &bp);
buff = unparse_object(executor, to, false);
safe_str(((to == NOTHING) ? "NOWHERE" : buff), outbuf, &bp);
free_lbuf(buff);
safe_chr(']', outbuf, &bp);
*bp = '\0';
notify(executor, outbuf);
ecount++;
}
}
// Object search
//
if ( searchparm.s_rst_type == TYPE_THING
|| searchparm.s_rst_type == NOTYPE)
{
flag = true;
for (thing = olist_first(); thing != NOTHING; thing = olist_next())
{
if (Typeof(thing) != TYPE_THING)
{
continue;
}
if (flag)
{
flag = false;
destitute = false;
notify(executor, "\nOBJECTS:");
}
bp = outbuf;
buff = unparse_object(executor, thing, false);
safe_str(buff, outbuf, &bp);
free_lbuf(buff);
safe_str(" [owner: ", outbuf, &bp);
buff = unparse_object(executor, Owner(thing), false);
safe_str(buff, outbuf, &bp);
free_lbuf(buff);
safe_chr(']', outbuf, &bp);
*bp = '\0';
notify(executor, outbuf);
tcount++;
}
}
// Player search
//
if ( searchparm.s_rst_type == TYPE_PLAYER
|| searchparm.s_rst_type == NOTYPE)
{
flag = true;
for (thing = olist_first(); thing != NOTHING; thing = olist_next())
{
if (Typeof(thing) != TYPE_PLAYER)
{
continue;
}
if (flag)
{
flag = false;
destitute = false;
notify(executor, "\nPLAYERS:");
}
bp = outbuf;
buff = unparse_object(executor, thing, 0);
safe_str(buff, outbuf, &bp);
free_lbuf(buff);
if (searchparm.s_wizard)
{
safe_str(" [location: ", outbuf, &bp);
buff = unparse_object(executor, Location(thing), false);
safe_str(buff, outbuf, &bp);
free_lbuf(buff);
safe_chr(']', outbuf, &bp);
}
*bp = '\0';
notify(executor, outbuf);
pcount++;
}
}
// If nothing found matching search criteria.
//
if (destitute)
{
notify(executor, "Nothing found.");
}
else
{
sprintf(outbuf,
"\nFound: Rooms...%d Exits...%d Objects...%d Players...%d",
rcount, ecount, tcount, pcount);
notify(executor, outbuf);
}
free_lbuf(outbuf);
olist_pop();
}
// ---------------------------------------------------------------------------
// do_markall: set or clear the mark bits of all objects in the db.
//
void do_markall(dbref executor, dbref caller, dbref enactor, int key)
{
int i;
if (mudconf.control_flags & CF_DBCHECK)
{
er_mark_disabled(executor);
return;
}
if (key == MARK_SET)
{
Mark_all(i);
}
else if (key == MARK_CLEAR)
{
Unmark_all(i);
}
if (!Quiet(executor))
{
notify(executor, "Done.");
}
}
// ---------------------------------------------------------------------------
// do_apply_marked: Perform a command for each marked obj in the db.
//
void do_apply_marked( dbref executor, dbref caller, dbref enactor, int key,
char *command, char *cargs[], int ncargs)
{
if (mudconf.control_flags & CF_DBCHECK)
{
er_mark_disabled(executor);
return;
}
char *buff = alloc_sbuf("do_apply_marked");
int i;
int number = 0;
DO_WHOLE_DB(i)
{
if (Marked(i))
{
buff[0] = '#';
mux_ltoa(i, buff+1);
number++;
bind_and_queue(executor, caller, enactor, command, buff,
cargs, ncargs, number);
}
}
free_sbuf(buff);
if (!Quiet(executor))
{
notify(executor, "Done.");
}
}
// ---------------------------------------------------------------------------
// Object list management routines: olist_push, olist_pop, olist_add,
// olist_first, olist_next
//
// olist_push: Create a new object list at the top of the object list stack.
//
void olist_push(void)
{
OLSTK *ol = (OLSTK *)MEMALLOC(sizeof(OLSTK));
ISOUTOFMEMORY(ol);
ol->next = mudstate.olist;
mudstate.olist = ol;
ol->head = NULL;
ol->tail = NULL;
ol->cblock = NULL;
ol->count = 0;
ol->citm = 0;
}
// olist_pop: Pop one entire list off the object list stack.
//
void olist_pop(void)
{
OLSTK *ol = mudstate.olist->next;
OBLOCK *op, *onext;
for (op = mudstate.olist->head; op != NULL; op = onext)
{
onext = op->next;
free_lbuf(op);
}
MEMFREE(mudstate.olist);
mudstate.olist = ol;
}
// olist_add: Add an entry to the object list.
//
void olist_add(dbref item)
{
OBLOCK *op;
if (!mudstate.olist->head)
{
op = (OBLOCK *) alloc_lbuf("olist_add.first");
mudstate.olist->head = mudstate.olist->tail = op;
mudstate.olist->count = 0;
op->next = NULL;
}
else if (mudstate.olist->count >= OBLOCK_SIZE)
{
op = (OBLOCK *) alloc_lbuf("olist_add.next");
mudstate.olist->tail->next = op;
mudstate.olist->tail = op;
mudstate.olist->count = 0;
op->next = NULL;
}
else
{
op = mudstate.olist->tail;
}
op->data[mudstate.olist->count++] = item;
}
// olist_first: Return the first entry in the object list.
//
dbref olist_first(void)
{
if (!mudstate.olist->head)
{
return NOTHING;
}
if ( (mudstate.olist->head == mudstate.olist->tail)
&& (mudstate.olist->count == 0))
{
return NOTHING;
}
mudstate.olist->cblock = mudstate.olist->head;
mudstate.olist->citm = 0;
return mudstate.olist->cblock->data[mudstate.olist->citm++];
}
dbref olist_next(void)
{
if (!mudstate.olist->cblock)
{
return NOTHING;
}
if ( (mudstate.olist->cblock == mudstate.olist->tail)
&& (mudstate.olist->citm >= mudstate.olist->count))
{
return NOTHING;
}
dbref thing = mudstate.olist->cblock->data[mudstate.olist->citm++];
if (mudstate.olist->citm >= OBLOCK_SIZE)
{
mudstate.olist->cblock = mudstate.olist->cblock->next;
mudstate.olist->citm = 0;
}
return thing;
}