mux2.0/
mux2.0/game/bin/
mux2.0/game/data/
mux2.0/src/tools/
//
// walkdb.cpp -- Support for commands that walk the entire db.
//
// $Id: walkdb.cpp,v 1.8 2000/08/28 07:52:08 sdennis Exp $ 
//

#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"

#include "mudconf.h"
#include "db.h"
#include "interface.h"
#include "match.h"
#include "command.h"
#include "flags.h"
#include "powers.h"
#include "misc.h"
#include "alloc.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 player, dbref cause, char *action,
                           char *argstr, char *cargs[], int ncargs,
                           int number)
{
    // Allocated by replace_string.
    //
    char *command, *command2;

    command = replace_string(BOUND_VAR, argstr, action);
    command2 = replace_string(LISTPLACE_VAR, Tiny_ltoa_t(number), command);
    wait_que(player, cause, 0, NOTHING, 0, command2, cargs, ncargs,
             mudstate.global_regs);
    free_lbuf(command);
    free_lbuf(command2);
}

//
// 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 player, dbref cause, int key, char *list, char *command,
               char *cargs[], int ncargs)
{
    char *curr, *objstring, delimiter = ' ';
    int number = 0;

    if (!list || *list == '\0')
    {
        notify(player, "That's terrific, but what should I do with the list?");
        return;
    }
    curr = list;

    if (key == DOLIST_DELIMIT)
    {
        char *tempstr = parse_to(&curr, ' ', EV_STRIP_CURLY);
        if (strlen(tempstr) > 1)
        {
            notify(player, "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(player, cause, command, objstring, cargs, ncargs,
                           number);
        }
    }
}

//
// Regular @find command 
//
void do_find(dbref player, dbref cause, int key, char *name)
{
    dbref i, low_bound, high_bound;
    char *buff;

    if (!payfor(player, mudconf.searchcost))
    {
        buff = tprintf("You don't have enough %s.", mudconf.many_coins);
        notify_quiet(player, buff);
        return;
    }
    parse_range(&name, &low_bound, &high_bound);
    for (i = low_bound; i <= high_bound; i++)
    {
        if (  (Typeof(i) != TYPE_EXIT)
           && controls(player, i)
           && (!*name || string_match(PureName(i), name)))
        {
            buff = unparse_object(player, i, 0);
            notify(player, buff);
            free_lbuf(buff);
        }
    }
    notify(player, "***End of List***");
}

// ---------------------------------------------------------------------------
// get_stats, do_stats: Get counts of items in the db.
//
int get_stats(dbref player, dbref who, STATS *info)
{
    dbref i;

    info->s_total = 0;
    info->s_rooms = 0;
    info->s_exits = 0;
    info->s_things = 0;
    info->s_players = 0;
    info->s_garbage = 0;

    // Do we have permission?
    //
    if (Good_obj(who) && !Controls(player, who) && !Stat_Any(player))
    {
        notify(player, "Permission denied.");
        return 0;
    }

    // Can we afford it? 
    //
    if (!payfor(player, mudconf.searchcost))
    {
        notify(player, tprintf("You don't have enough %s.",
               mudconf.many_coins));
        return 0;
    }
    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 1;
}

// Reworked by R'nice 
//
void do_stats(dbref player, dbref cause, int key, char *name)
{
    dbref owner;
    STATS statinfo;
    char *buff;

    switch (key)
    {
    case STAT_ALL:

        owner = NOTHING;
        break;

    case STAT_ME:

        owner = Owner(player);
        break;

    case STAT_PLAYER:

        if (!(name && *name))
        {
            int nNextFree = mudstate.freelist;
            if (mudstate.freelist == NOTHING)
            {
                nNextFree = mudstate.db_top;
            }
            notify(player, tprintf("The universe contains %d objects (next free is #%d).",
            mudstate.db_top, nNextFree));
            return;
        }
        owner = lookup_player(player, name, 1);
        if (owner == NOTHING)
        {
            notify(player, "Not found.");
            return;
        }
        break;

    default:

        notify(player, "Illegal combination of switches.");
        return;
    }

    if (!get_stats(player, owner, &statinfo))
    {
        return;
    }
    buff = 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);
    notify(player, buff);
}

int chown_all(dbref from_player, dbref to_player, dbref acting_player, int key)
{
    int i, count, quota_out, quota_in;

    if (Typeof(from_player) != TYPE_PLAYER)
    {
        from_player = Owner(from_player);
    }
    if (Typeof(to_player) != TYPE_PLAYER)
    {
        to_player = Owner(to_player);
    }
    count = 0;
    quota_out = 0;
    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, (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 player, dbref cause, int key, char *from, char *to)
{
    int count;
    dbref victim, recipient;

    init_match(player, from, TYPE_PLAYER);
    match_neighbor();
    match_absolute();
    match_player();
    if ((victim = noisy_match_result()) == NOTHING)
    {
        return;
    }

    if ((to != NULL) && *to)
    {
        init_match(player, to, TYPE_PLAYER);
        match_neighbor();
        match_absolute();
        match_player();
        if ((recipient = noisy_match_result()) == NOTHING)
        {
            return;
        }
    }
    else
    {
        recipient = player;
    }

    count = chown_all(victim, recipient, player, key);
    if (!Quiet(player))
    {
        notify(player, 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)
//
int search_setup(dbref player, char *searchfor, SEARCH *parm)
{
    char *pname, *searchtype;
    int err;

    // Crack arg into <pname> <type>=<targ>,<low>,<high> 
    //
    pname = parse_to(&searchfor, '=', EV_STRIP_TS);
    if (!pname || !*pname)
    {
        pname = (char *)"me";
    }
    else
    {
        _strlwr(pname);
    }

    if (searchfor && *searchfor)
    {
        searchtype = (char *)strrchr(pname, ' ');
        if (searchtype)
        {
            *searchtype++ = '\0';
        }
        else
        {
            searchtype = pname;
            pname = (char *)"";
        }
    }
    else
    {
        searchtype = (char *)"";
    }

    // If the player name is quoted, strip the quotes.
    //
    if (*pname == '\"')
    {
        err = strlen(pname) - 1;
        if (pname[err] == '"')
        {
            pname[err] = '\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 = Tiny_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, 1);
    }

    if (parm->s_rst_owner == NOTHING)
    {
        notify(player, tprintf("%s: No such player", pname));
        return 0;
    }

    // Set limits on what we search for.
    //
    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;
    parm->s_fset.word1 = 0;
    parm->s_fset.word2 = 0;
    parm->s_fset.word3 = 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 0;
            }
        }
        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 0;
            }
            if (!*pname)
            {
                parm->s_rst_owner = ANY_OWNER;
            }
        }
        else if (string_prefix("power", searchtype))
        {
            if (!decode_power(player, searchfor, &parm->s_pset))
            {
                return 0;
            }
        }
        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 0;
            }
        }
        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 0;
            }
            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 0;
    }

    // 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 0;
    }

    // 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 0;
    }
    return 1;
}

void search_perform(dbref player, dbref cause, SEARCH *parm)
{
    FLAG thing1flags, thing2flags, thing3flags;
    POWER thing1powers, thing2powers;
    dbref thing;
    char *buff, *buff2, *result, *bp, *str;
    int save_invk_ctr;

    buff = alloc_sbuf("search_perform.num");
    save_invk_ctr = mudstate.func_invk_ctr;

    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.
        //
        thing1flags = Flags(thing);
        if ((Typeof(thing) == TYPE_THING) && (thing1flags & GOING))
            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.
        //
        thing3flags = Flags3(thing);
        thing2flags = Flags2(thing);
        if ((thing1flags & parm->s_fset.word1) != parm->s_fset.word1)
        {
            continue;
        }
        if ((thing2flags & parm->s_fset.word2) != parm->s_fset.word2)
        {
            continue;
        }
        if ((thing3flags & parm->s_fset.word3) != parm->s_fset.word3)
        {
            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((char *)PureName(thing), parm->s_rst_name))
                continue;
        }
        /*
         * Check for successful evaluation 
         */

        if (parm->s_rst_eval != NULL)
        {
            buff[0] = '#';
            Tiny_ltoa(thing, buff+1);
            buff2 = replace_string(BOUND_VAR, buff, parm->s_rst_eval);
            result = bp = alloc_lbuf("search_perform");
            str = buff2;
            TinyExec(result, &bp, 0, player, cause,
                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;
    int nchanged, is_marked;

    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 player, dbref cause, int key, char *arg)
{
    int flag, destitute;
    char *buff, *outbuf, *bp;
    dbref thing, from, to;
    SEARCH searchparm;

    if ((key != SRCH_SEARCH) && (mudconf.control_flags & CF_DBCHECK))
    {
        er_mark_disabled(player);
        return;
    }
    if (!search_setup(player, arg, &searchparm))
    {
        return;
    }
    olist_push();
    search_perform(player, cause, &searchparm);
    destitute = 1;

    // If we are doing a @mark command, handle that here.
    //
    if (key != SRCH_SEARCH)
    {
        search_mark(player, key);
        olist_pop();
        return;
    }
    outbuf = alloc_lbuf("do_search.outbuf");

    int rcount = 0;
    int ecount = 0;
    int tcount = 0;
    int pcount = 0;
    int gcount = 0;

    // Room search.
    //
    if (  searchparm.s_rst_type == TYPE_ROOM
       || searchparm.s_rst_type == NOTYPE)
    {
        flag = 1;
        for (thing = olist_first(); thing != NOTHING; thing = olist_next())
        {
            if (Typeof(thing) != TYPE_ROOM)
            {
                continue;
            }
            if (flag)
            {
                flag = 0;
                destitute = 0;
                notify(player, "\nROOMS:");
            }
            buff = unparse_object(player, thing, 0);
            notify(player, buff);
            free_lbuf(buff);
            rcount++;
        }
    }

    // Exit search.
    //
    if (  searchparm.s_rst_type == TYPE_EXIT
       || searchparm.s_rst_type == NOTYPE)
    {
        flag = 1;
        for (thing = olist_first(); thing != NOTHING; thing = olist_next())
        {
            if (Typeof(thing) != TYPE_EXIT)
            {
                continue;
            }
            if (flag)
            {
                flag = 0;
                destitute = 0;
                notify(player, "\nEXITS:");
            }
            from = Exits(thing);
            to = Location(thing);

            bp = outbuf;
            buff = unparse_object(player, thing, 0);
            safe_str(buff, outbuf, &bp);
            free_lbuf(buff);

            safe_str((char *)" [from ", outbuf, &bp);
            buff = unparse_object(player, from, 0);
            safe_str(((from == NOTHING) ? "NOWHERE" : buff), outbuf, &bp);
            free_lbuf(buff);

            safe_str((char *)" to ", outbuf, &bp);
            buff = unparse_object(player, to, 0);
            safe_str(((to == NOTHING) ? "NOWHERE" : buff), outbuf, &bp);
            free_lbuf(buff);

            safe_chr(']', outbuf, &bp);
            *bp = '\0';
            notify(player, outbuf);
            ecount++;
        }
    }

    // Object search
    //
    if (  searchparm.s_rst_type == TYPE_THING
       || searchparm.s_rst_type == NOTYPE)
    {
        flag = 1;
        for (thing = olist_first(); thing != NOTHING; thing = olist_next())
        {
            if (Typeof(thing) != TYPE_THING)
            {
                continue;
            }
            if (flag)
            {
                flag = 0;
                destitute = 0;
                notify(player, "\nOBJECTS:");
            }
            bp = outbuf;
            buff = unparse_object(player, thing, 0);
            safe_str(buff, outbuf, &bp);
            free_lbuf(buff);

            safe_str((char *)" [owner: ", outbuf, &bp);
            buff = unparse_object(player, Owner(thing), 0);
            safe_str(buff, outbuf, &bp);
            free_lbuf(buff);

            safe_chr(']', outbuf, &bp);
            *bp = '\0';
            notify(player, outbuf);
            tcount++;
        }
    }

    // Garbage search
    //
    if (  searchparm.s_rst_type == TYPE_GARBAGE
       || searchparm.s_rst_type == NOTYPE)
    {
        flag = 1;
        for (thing = olist_first(); thing != NOTHING; thing = olist_next())
        {
            if (Typeof(thing) != TYPE_GARBAGE)
            {
                continue;
            }
            if (flag)
            {
                flag = 0;
                destitute = 0;
                notify(player, "\nGARBAGE:");
            }
            bp = outbuf;
            buff = unparse_object(player, thing, 0);
            safe_str(buff, outbuf, &bp);
            free_lbuf(buff);

            safe_str((char *)" [owner: ", outbuf, &bp);
            buff = unparse_object(player, Owner(thing), 0);
            safe_str(buff, outbuf, &bp);
            free_lbuf(buff);

            safe_chr(']', outbuf, &bp);
            *bp = '\0';
            notify(player, outbuf);
            gcount++;
        }
    }

    // Player search 
    //
    if (  searchparm.s_rst_type == TYPE_PLAYER
       || searchparm.s_rst_type == NOTYPE)
    {
        flag = 1;
        for (thing = olist_first(); thing != NOTHING; thing = olist_next())
        {
            if (Typeof(thing) != TYPE_PLAYER)
            {
                continue;
            }
            if (flag)
            {
                flag = 0;
                destitute = 0;
                notify(player, "\nPLAYERS:");
            }
            bp = outbuf;
            buff = unparse_object(player, thing, 0);
            safe_str(buff, outbuf, &bp);
            free_lbuf(buff);
            if (searchparm.s_wizard)
            {
                safe_str((char *)" [location: ", outbuf, &bp);
                buff = unparse_object(player, Location(thing), 0);
                safe_str(buff, outbuf, &bp);
                free_lbuf(buff);
                safe_chr(']', outbuf, &bp);
            }
            *bp = '\0';
            notify(player, outbuf);
            pcount++;
        }
    }

    // If nothing found matching search criteria.
    //
    if (destitute)
    {
        notify(player, "Nothing found.");
    }
    else
    {
        sprintf(outbuf,
            "\nFound:  Rooms...%d  Exits...%d  Objects...%d  Players...%d  Garbage...%d",
            rcount, ecount, tcount, pcount, gcount);
        notify(player, outbuf);
    }
    free_lbuf(outbuf);
    olist_pop();
}

// ---------------------------------------------------------------------------
// do_markall: set or clear the mark bits of all objects in the db.
//
void do_markall(dbref player, dbref cause, int key)
{
    int i;

    if (mudconf.control_flags & CF_DBCHECK)
    {
        er_mark_disabled(player);
        return;
    }
    if (key == MARK_SET)
    {
        Mark_all(i);
    }
    else if (key == MARK_CLEAR)
    {
        Unmark_all(i);
    }
    if (!Quiet(player))
    {
        notify(player, "Done.");
    }
}

// ---------------------------------------------------------------------------
// do_apply_marked: Perform a command for each marked obj in the db.
//
void do_apply_marked( dbref player, dbref cause, int key, char *command,
                      char *cargs[], int ncargs)
{
    char *buff;
    int i;
    int number = 0;

    if (mudconf.control_flags & CF_DBCHECK)
    {
        er_mark_disabled(player);
        return;
    }
    buff = alloc_sbuf("do_apply_marked");
    DO_WHOLE_DB(i)
    {
        if (Marked(i))
        {
            buff[0] = '#';
            Tiny_ltoa(i, buff+1);
            number++;
            bind_and_queue(player, cause, command, buff, cargs, ncargs, number);
        }
    }
    free_sbuf(buff);
    if (!Quiet(player))
    {
        notify(player, "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;
    
    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)
{
    dbref thing;
    
    if (!mudstate.olist->cblock)
    {
        return NOTHING;
    }
    if (  (mudstate.olist->cblock == mudstate.olist->tail)
       && (mudstate.olist->citm >= mudstate.olist->count))
    {
        return NOTHING;
    }
    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;
}