mux2.4/game/data/
mux2.4/src/tools/
// game.cpp
//
// $Id: game.cpp,v 1.74 2005/10/16 20:48:14 sdennis Exp $
//
#include "copyright.h"
#include "autoconf.h"
#include "config.h"
#include "externs.h"

#include <sys/stat.h>
#include <signal.h>

#include "attrs.h"
#include "comsys.h"
#include "file_c.h"
#include "mguests.h"
#include "muxcli.h"
#include "pcre.h"
#include "powers.h"
#include "help.h"
#ifdef REALITY_LVLS
#include "levels.h"
#endif /* REALITY_LVLS */

extern void init_attrtab(void);
extern void init_cmdtab(void);
extern void cf_init(void);
extern void pcache_init(void);
extern int  cf_read(void);
extern void ValidateConfigurationDbrefs(void);
extern void init_functab(void);
extern void close_sockets(bool emergency, char *message);
extern void build_version(void);
extern void init_version(void);
extern void init_logout_cmdtab(void);
extern void raw_notify(dbref, const char *);
extern void do_dbck(dbref executor, dbref caller, dbref enactor, int);
extern void boot_slave(dbref executor, dbref caller, dbref enactor, int key);

void fork_and_dump(int);
void pcache_sync(void);
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
static void init_rlimit(void);
#endif // HAVE_SETRLIMIT RLIMIT_NOFILE

#ifdef WIN32
extern CRITICAL_SECTION csDescriptorList;      // for thread synchronisation
#endif // WIN32

void do_dump(dbref executor, dbref caller, dbref enactor, int key)
{
#ifndef WIN32
    if (mudstate.dumping)
    {
        notify(executor, "Dumping in progress. Try again later.");
        return;
    }
#endif
    notify(executor, "Dumping...");
    fork_and_dump(key);
}

// print out stuff into error file
//
void report(void)
{
    STARTLOG(LOG_BUGS, "BUG", "INFO");
    log_text("Command: '");
    log_text(mudstate.debug_cmd);
    log_text("'");
    ENDLOG;
    if (Good_obj(mudstate.curr_executor))
    {
        STARTLOG(LOG_BUGS, "BUG", "INFO");
        log_text("Player: ");
        log_name_and_loc(mudstate.curr_executor);
        if (  mudstate.curr_enactor != mudstate.curr_executor
           && Good_obj(mudstate.curr_enactor))
        {
            log_text(" Enactor: ");
            log_name_and_loc(mudstate.curr_enactor);
        }
        ENDLOG;
    }
}

/* ----------------------------------------------------------------------
 * regexp_match: Load a regular expression match and insert it into
 * registers.
 */

bool regexp_match
(
    char *pattern,
    char *str,
    int case_opt,
    char *args[],
    int nargs
)
{
    int matches;
    int i;
    const char *errptr;
    int erroffset;

    /*
     * Load the regexp pattern. This allocates memory which must be
     * later freed. A free() of the regexp does free all structures
     * under it.
     */

    pcre *re;
    if (  MuxAlarm.bAlarmed
       || (re = pcre_compile(pattern, case_opt, &errptr, &erroffset, NULL)) == NULL)
    {
        /*
         * This is a matching error. We have an error message in
         * regexp_errbuf that we can ignore, since we're doing
         * command-matching.
         */
        return false;
    }

    // To capture N substrings, you need space for 3(N+1) offsets in the
    // offset vector. We'll allow 2N-1 substrings and possibly ignore some.
    //
    const int ovecsize = 6 * nargs;
    int *ovec = new int[ovecsize];

    /*
     * Now we try to match the pattern. The relevant fields will
     * automatically be filled in by this.
     */
    matches = pcre_exec(re, NULL, str, strlen(str), 0, 0, ovec, ovecsize);
    if (matches < 0)
    {
        delete ovec;
        MEMFREE(re);
        return false;
    }

    if (matches == 0)
    {
        // There were too many substring matches. See docs for
        // pcre_copy_substring().
        //
        matches = ovecsize / 3;
    }

    /*
     * Now we fill in our args vector. Note that in regexp matching,
     * 0 is the entire string matched, and the parenthesized strings
     * go from 1 to 9. We DO PRESERVE THIS PARADIGM, for consistency
     * with other languages.
     */

    for (i = 0; i < nargs; ++i)
    {
        args[i] = alloc_lbuf("regexp_match");
        if (pcre_copy_substring(str, ovec, matches, i,
                                args[i], LBUF_SIZE) < 0)
        {
            free_lbuf(args[i]);
            args[i] = NULL;
        }
    }

    delete ovec;
    MEMFREE(re);
    return true;
}

/* ----------------------------------------------------------------------
 * atr_match: Check attribute list for wild card matches and queue them.
 */

static int atr_match1
(
    dbref thing,
    dbref parent,
    dbref player,
    char  type,
    char  *str,
    char  *raw_str,
    int   check_exclude,
    int   hash_insert
)
{
    // See if we can do it.  Silently fail if we can't.
    //
    if (!could_doit(player, parent, A_LUSE))
    {
        return -1;
    }

    int match = 0;
    if (  AMATCH_CMD == type
       && mudstate.bfNoCommands.IsSet(parent))
    {
        return match;
    }
    else if ( AMATCH_LISTEN == type
            && mudstate.bfNoListens.IsSet(parent))
    {
        return match;
    }

    bool bFoundCommands = false;
    bool bFoundListens  = false;

    int atr;
    char *as;
    atr_push();
    for (atr = atr_head(parent, &as); atr; atr = atr_next(&as))
    {
        ATTR *ap = atr_num(atr);

        // Never check NOPROG attributes.
        //
        if (  !ap
           || (ap->flags & AF_NOPROG))
        {
            continue;
        }

        // We need to grab the attribute even before we know whether we'll use
        // it or not in order to maintain cached knowledge about ^-Commands
        // and $-Commands.
        //
        dbref aowner;
        int   aflags;
        char buff[LBUF_SIZE];
        atr_get_str(buff, parent, atr, &aowner, &aflags);

        if (!(aflags & AF_NOPROG))
        {
            switch (buff[0])
            {
            case AMATCH_CMD:
                bFoundCommands = true;
                break;

            case AMATCH_LISTEN:
                bFoundListens = true;
                break;
            }
        }

        // If we aren't the bottom level check if we saw this attr
        // before. Also exclude it if the attribute type is PRIVATE.
        //
        if (  check_exclude
           && (  (ap->flags & AF_PRIVATE)
              || (aflags & AF_PRIVATE)
              || hashfindLEN(&(ap->number), sizeof(ap->number), &mudstate.parent_htab)))
        {
            continue;
        }

        // If we aren't the top level remember this attr so we
        // exclude it from now on.
        //
        if (hash_insert)
        {
            hashaddLEN(&(ap->number), sizeof(ap->number), &atr, &mudstate.parent_htab);
        }

        // Check for the leadin character after excluding the attrib.
        // This lets non-command attribs on the child block commands
        // on the parent.
        //
        if (  buff[0] != type
           || (aflags & AF_NOPROG))
        {
            continue;
        }

        // Decode it: search for first unescaped :
        //
        char *s = strchr(buff+1, ':');
        if (!s)
        {
            continue;
        }
        *s++ = '\0';
        char *args[NUM_ENV_VARS];
        if (  (  0 != (aflags & AF_REGEXP)
            && regexp_match(buff + 1, (aflags & AF_NOPARSE) ? raw_str : str,
                ((aflags & AF_CASE) ? 0 : PCRE_CASELESS), args, NUM_ENV_VARS))
           || (  0 == (aflags & AF_REGEXP)
              && wild(buff + 1, (aflags & AF_NOPARSE) ? raw_str : str,
                args, NUM_ENV_VARS)))
        {
            match = 1;
            CLinearTimeAbsolute lta;
            wait_que(thing, player, player, false, lta, NOTHING, 0, s,
                args, NUM_ENV_VARS, mudstate.global_regs);

            for (int i = 0; i < NUM_ENV_VARS; i++)
            {
                if (args[i])
                {
                    free_lbuf(args[i]);
                }
            }
        }
    }
    atr_pop();

    if (bFoundCommands)
    {
        mudstate.bfNoCommands.Clear(parent);
        mudstate.bfCommands.Set(parent);
    }
    else
    {
        mudstate.bfCommands.Clear(parent);
        mudstate.bfNoCommands.Set(parent);
    }

    if (bFoundListens)
    {
        mudstate.bfNoListens.Clear(parent);
        mudstate.bfListens.Set(parent);
    }
    else
    {
        mudstate.bfListens.Clear(parent);
        mudstate.bfNoListens.Set(parent);
    }
    return match;
}

bool atr_match
(
    dbref thing,
    dbref player,
    char  type,
    char  *str,
    char  *raw_str,
    bool check_parents
)
{
    int lev, result;
    bool exclude, insert;
    dbref parent;

    // If thing is halted or we are matching $-commands on a NO_COMMAND
    // object, don't check anything
    //
    if (  Halted(thing)
       || (  AMATCH_CMD == type
          && No_Command(thing)))
    {
        return false;
    }

    // If we're matching ^-commands, strip ANSI
    //
    if (AMATCH_LISTEN == type)
    {
        // Remember, strip_ansi returns a pointer to a static buffer
        // within itself.
        //
        size_t junk;
        str = strip_ansi(str, &junk);
    }

    // If not checking parents, just check the thing
    //
    bool match = false;
    if (!check_parents)
    {
        return (atr_match1(thing, thing, player, type, str, raw_str, false, false) > 0);
    }

    // Check parents, ignoring halted objects
    //
    exclude = false;
    insert = true;
    hashflush(&mudstate.parent_htab);
    ITER_PARENTS(thing, parent, lev)
    {
        if (!Good_obj(Parent(parent)))
        {
            insert = false;
        }
        result = atr_match1(thing, parent, player, type, str, raw_str,
            exclude, insert);
        if (result > 0)
        {
            match = true;
        }
        else if (result < 0)
        {
            return match;
        }
        exclude = true;
    }
    return match;
}

/* ---------------------------------------------------------------------------
 * notify_check: notifies the object #target of the message msg, and
 * optionally notify the contents, neighbors, and location also.
 */

bool check_filter(dbref object, dbref player, int filter, const char *msg)
{
    int aflags;
    dbref aowner;
    char *buf, *nbuf, *cp, *dp, *str;

    buf = atr_pget(object, filter, &aowner, &aflags);
    if (!*buf)
    {
        free_lbuf(buf);
        return true;
    }
    char **preserve = NULL;
    int *preserve_len = NULL;
    preserve = PushPointers(MAX_GLOBAL_REGS);
    preserve_len = PushIntegers(MAX_GLOBAL_REGS);
    save_global_regs("check_filter_save", preserve, preserve_len);
    nbuf = dp = alloc_lbuf("check_filter");
    str = buf;
    mux_exec(nbuf, &dp, object, player, player,
             EV_FIGNORE | EV_EVAL | EV_TOP, &str, (char **)NULL, 0);
    *dp = '\0';
    dp = nbuf;
    free_lbuf(buf);
    restore_global_regs("check_filter_restore", preserve, preserve_len);
    PopIntegers(preserve_len, MAX_GLOBAL_REGS);
    PopPointers(preserve, MAX_GLOBAL_REGS);

    if (!(aflags & AF_REGEXP))
    {
        do
        {
            cp = parse_to(&dp, ',', EV_STRIP_CURLY);
            mudstate.wild_invk_ctr = 0;
            if (  MuxAlarm.bAlarmed
               || quick_wild(cp, msg))
            {
                free_lbuf(nbuf);
                return false;
            }
        } while (dp != NULL);
    }
    else
    {
        int case_opt = (aflags & AF_CASE) ? 0 : PCRE_CASELESS;
        do
        {
            int erroffset;
            const char *errptr;
            cp = parse_to(&dp, ',', EV_STRIP_CURLY);
            pcre *re;
            if (  !MuxAlarm.bAlarmed
               && (re = pcre_compile(cp, case_opt, &errptr, &erroffset, NULL)) != NULL)
            {
                const int ovecsize = 33;
                int ovec[ovecsize];
                int matches = pcre_exec(re, NULL, msg, strlen(msg), 0, 0,
                    ovec, ovecsize);
                if (0 <= matches)
                {
                    MEMFREE(re);
                    free_lbuf(nbuf);
                    return false;
                }
                MEMFREE(re);
            }
        } while (dp != NULL);
    }
    free_lbuf(nbuf);
    return true;
}

static char *add_prefix(dbref object, dbref player, int prefix,
                        const char *msg, const char *dflt)
{
    int aflags;
    dbref aowner;
    char *buf, *nbuf, *cp, *str;

    buf = atr_pget(object, prefix, &aowner, &aflags);
    if (!*buf)
    {
        cp = buf;
        safe_str(dflt, buf, &cp);
    }
    else
    {
        char **preserve = NULL;
        int *preserve_len = NULL;
        preserve = PushPointers(MAX_GLOBAL_REGS);
        preserve_len = PushIntegers(MAX_GLOBAL_REGS);
        save_global_regs("add_prefix_save", preserve, preserve_len);

        nbuf = cp = alloc_lbuf("add_prefix");
        str = buf;
        mux_exec(nbuf, &cp, object, player, player,
                 EV_FIGNORE | EV_EVAL | EV_TOP, &str, (char **)NULL, 0);
        free_lbuf(buf);

        restore_global_regs("add_prefix_restore", preserve, preserve_len);
        PopIntegers(preserve_len, MAX_GLOBAL_REGS);
        PopPointers(preserve, MAX_GLOBAL_REGS);

        buf = nbuf;
    }
    if (cp != buf)
    {
        safe_chr(' ', buf, &cp);
    }
    safe_str(msg, buf, &cp);
    *cp = '\0';
    return buf;
}

static char *dflt_from_msg(dbref sender, dbref sendloc)
{
    char *tp, *tbuff;

    tp = tbuff = alloc_lbuf("notify_check.fwdlist");
    safe_str("From ", tbuff, &tp);
    if (Good_obj(sendloc))
    {
        safe_str(Name(sendloc), tbuff, &tp);
    }
    else
    {
        safe_str(Name(sender), tbuff, &tp);
    }
    safe_chr(',', tbuff, &tp);
    *tp = '\0';
    return tbuff;
}

/* Do HTML escaping, converting < to &lt;, etc.  'dest' needs to be
 * allocated & freed by the caller.
 *
 * If you're using this to append to a string, you can pass in the
 * safe_{str|chr} (char **) so we can just do the append directly,
 * saving you an alloc_lbuf()...free_lbuf().  If you want us to append
 * from the start of 'dest', just pass in a 0 for 'destp'.
 *
 * Returns 0 if the copy succeeded, 1 if it failed.
 */
bool html_escape(const char *src, char *dest, char **destp)
{
    const char *msg_orig;
    bool ret = false;

    if (destp == 0)
    {
        char *temp = dest;
        destp = &temp;
    }

    for (msg_orig = src; msg_orig && *msg_orig && !ret; msg_orig++)
    {
        char *p = *destp;
        switch (*msg_orig)
        {
        case '<':
            safe_str("&lt;", dest, destp);
            break;

        case '>':
            safe_str("&gt;", dest, destp);
            break;

        case '&':
            safe_str("&amp;", dest, destp);
            break;

        case '\"':
            safe_str("&quot;", dest, destp);
            break;

        default:
            safe_chr(*msg_orig, dest, destp);
            break;
        }

        // For <>&\, this may cause an extra loop around before it figures out that we are
        // out of buffer, but no harm is done in this, and the common case is a single character.
        //
        if (p == *destp)
        {
            ret = true;
        }
    }
    **destp = 0;
    return ret;
}

void notify_check(dbref target, dbref sender, const char *msg, int key)
{
    // If speaker is invalid or message is empty, just exit.
    //
    if (  !Good_obj(target)
       || !msg
       || !*msg)
    {
        return;
    }

#ifdef WOD_REALMS
    if ((key & MSG_OOC) == 0)
    {
        if ((key & MSG_SAYPOSE) != 0)
        {
            if (REALM_DO_HIDDEN_FROM_YOU == DoThingToThingVisibility(target, sender, ACTION_IS_TALKING))
            {
                return;
            }
        }
        else
        {
            if (REALM_DO_HIDDEN_FROM_YOU == DoThingToThingVisibility(target, sender, ACTION_IS_MOVING))
            {
                return;
            }
        }
    }
#endif // WOD_REALMS

    // Enforce a recursion limit
    //
    mudstate.ntfy_nest_lev++;
    if (mudconf.ntfy_nest_lim <= mudstate.ntfy_nest_lev)
    {
        mudstate.ntfy_nest_lev--;
        return;
    }

    char *msg_ns, *mp, *tbuff, *tp, *buff;
    char *args[NUM_ENV_VARS];
    dbref aowner,  recip, obj;
    int i, nargs, aflags;
    FWDLIST *fp;

    // If we want NOSPOOF output, generate it.  It is only needed if we are
    // sending the message to the target object.
    //
    if (key & MSG_ME)
    {
        mp = msg_ns = alloc_lbuf("notify_check");
        if (  Nospoof(target)
           && target != sender
           && target != mudstate.curr_enactor
           && target != mudstate.curr_executor)
        {
            // I'd really like to use tprintf here but I can't because the
            // caller may have.  notify(target, tprintf(...)) is quite common
            // in the code.
            //
            tbuff = alloc_sbuf("notify_check.nospoof");
            safe_chr('[', msg_ns, &mp);
            safe_str(Name(sender), msg_ns, &mp);
            sprintf(tbuff, "(#%d)", sender);
            safe_str(tbuff, msg_ns, &mp);

            if (sender != Owner(sender))
            {
                safe_chr('{', msg_ns, &mp);
                safe_str(Name(Owner(sender)), msg_ns, &mp);
                safe_chr('}', msg_ns, &mp);
            }
            if (sender != mudstate.curr_enactor)
            {
                sprintf(tbuff, "<-(#%d)", mudstate.curr_enactor);
                safe_str(tbuff, msg_ns, &mp);
            }
            safe_str("] ", msg_ns, &mp);
            free_sbuf(tbuff);
        }
        safe_str(msg, msg_ns, &mp);
        *mp = '\0';
    }
    else
    {
        msg_ns = NULL;
    }

    // msg contains the raw message, msg_ns contains the NOSPOOFed msg.
    //
    bool check_listens = !Halted(target);
    switch (Typeof(target))
    {
    case TYPE_PLAYER:
        if (key & MSG_ME)
        {
            if (key & MSG_HTML)
            {
                raw_notify_html(target, msg_ns);
            }
            else
            {
                if (Html(target))
                {
                    char *msg_ns_escaped;

                    msg_ns_escaped = alloc_lbuf("notify_check_escape");
                    html_escape(msg_ns, msg_ns_escaped, 0);
                    raw_notify(target, msg_ns_escaped);
                    free_lbuf(msg_ns_escaped);
                }
                else
                {
                    raw_notify(target, msg_ns);
                }
            }
        }
        if (!mudconf.player_listen)
        {
            check_listens = false;
        }

        // FALLTHROUGH

    case TYPE_THING:
    case TYPE_ROOM:

        // If we're in a pipe, objects can receive raw_notify if
        // they're not a player. (players were already notified
        // above.
        //
        if (  mudstate.inpipe
           && !isPlayer(target))
        {
            raw_notify(target, msg_ns);
        }

        // Forward puppet message if it is for me.
        //
        bool has_neighbors = Has_location(target);
        dbref targetloc = where_is(target);
        bool is_audible = Audible(target);

        if ( (key & MSG_ME)
           && Puppet(target)
           && (target != Owner(target))
           && (  (key & MSG_PUP_ALWAYS)
              || (  targetloc != Location(Owner(target))
                 && targetloc != Owner(target))))
        {
            tp = tbuff = alloc_lbuf("notify_check.puppet");
            safe_str(Name(target), tbuff, &tp);
            safe_str("> ", tbuff, &tp);
            safe_str(msg_ns, tbuff, &tp);
            *tp = '\0';
            raw_notify(Owner(target), tbuff);
            free_lbuf(tbuff);
        }

        // Check for @Listen match if it will be useful.
        //
        bool pass_listen = false;
        nargs = 0;
        if (  check_listens
           && (key & (MSG_ME | MSG_INV_L))
           && H_Listen(target))
        {
            tp = atr_get(target, A_LISTEN, &aowner, &aflags);
            if (*tp && wild(tp, (char *)msg, args, NUM_ENV_VARS))
            {
                for (nargs = NUM_ENV_VARS; nargs && (!args[nargs - 1] || !(*args[nargs - 1])); nargs--)
                {
                    ; // Nothing
                }
                pass_listen = true;
            }
            free_lbuf(tp);
        }

        // If we matched the @listen or are monitoring, check the
        // USE lock.
        //
        bool pass_uselock = false;
        if (  (key & MSG_ME)
           && check_listens
           && (  pass_listen
              || Monitor(target)))
        {
            pass_uselock = could_doit(sender, target, A_LUSE);
        }

        // Process AxHEAR if we pass LISTEN, USElock and it's for me.
        //
        if (  (key & MSG_ME)
           && pass_listen
           && pass_uselock
           && mudstate.nHearNest <= 2)
        {
            mudstate.nHearNest++;
            if (sender != target)
            {
                did_it(sender, target, 0, NULL, 0, NULL, A_AHEAR, args, nargs);
            }
            else
            {
                did_it(sender, target, 0, NULL, 0, NULL, A_AMHEAR, args,
                    nargs);
            }
            did_it(sender, target, 0, NULL, 0, NULL, A_AAHEAR, args, nargs);
            mudstate.nHearNest--;
        }

        // Get rid of match arguments. We don't need them anymore.
        //
        if (pass_listen)
        {
            for (i = 0; i < nargs; i++)
            {
                if (args[i] != NULL)
                {
                    free_lbuf(args[i]);
                }
            }
        }

        // Process ^-listens if for me, MONITOR, and we pass USElock.
        //
        if (  (key & MSG_ME)
           && pass_uselock
           && sender != target
           && Monitor(target))
        {
            atr_match(target, sender, AMATCH_LISTEN, (char *)msg, (char *)msg,
                false);
        }

        // Deliver message to forwardlist members.
        //
        if ( (key & MSG_FWDLIST)
           && is_audible
           && check_filter(target, sender, A_FILTER, msg))
        {
            tbuff = dflt_from_msg(sender, target);
            buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
            free_lbuf(tbuff);

            fp = fwdlist_get(target);
            if (fp)
            {
                for (i = 0; i < fp->count; i++)
                {
                    recip = fp->data[i];
                    if (  !Good_obj(recip)
                       || recip == target)
                    {
                        continue;
                    }
                    notify_check(recip, sender, buff,
                             MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE);
                }
            }
            free_lbuf(buff);
        }

        // Deliver message through audible exits.
        //
        if (key & MSG_INV_EXITS)
        {
            DOLIST(obj, Exits(target))
            {
                recip = Location(obj);
                if (  Audible(obj)
                   && (  recip != target
                      && check_filter(obj, sender, A_FILTER, msg)))
                {
                    buff = add_prefix(obj, target, A_PREFIX, msg,
                        "From a distance,");
                    notify_check(recip, sender, buff,
                        MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE);
                    free_lbuf(buff);
                }
            }
        }

        // Deliver message through neighboring audible exits.
        //
        if (  has_neighbors
           && (  (key & MSG_NBR_EXITS)
              || (  (key & MSG_NBR_EXITS_A)
                 && is_audible)))
        {
            // If from inside, we have to add the prefix string of
            // the container.
            //
            if (key & MSG_S_INSIDE)
            {
                tbuff = dflt_from_msg(sender, target);
                buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
                free_lbuf(tbuff);
            }
            else
            {
                buff = (char *)msg;
            }

            DOLIST(obj, Exits(Location(target)))
            {
                recip = Location(obj);
                if (  Good_obj(recip)
                   && Audible(obj)
                   && recip != targetloc
                   && recip != target
                   && check_filter(obj, sender, A_FILTER, msg))
                {
                    tbuff = add_prefix(obj, target, A_PREFIX, buff,
                        "From a distance,");
                    notify_check(recip, sender, tbuff,
                        MSG_ME | MSG_F_UP | MSG_F_CONTENTS | MSG_S_INSIDE);
                    free_lbuf(tbuff);
                }
            }
            if (key & MSG_S_INSIDE)
            {
                free_lbuf(buff);
            }
        }

        // Deliver message to contents.
        //
        if (  (  (key & MSG_INV)
              || (  (key & MSG_INV_L)
                 && pass_listen))
           && check_filter(target, sender, A_INFILTER, msg))
        {
            // Don't prefix the message if we were given the MSG_NOPREFIX key.
            //
            if (key & MSG_S_OUTSIDE)
            {
                buff = add_prefix(target, sender, A_INPREFIX, msg, "");
            }
            else
            {
                buff = (char *)msg;
            }
            DOLIST(obj, Contents(target))
            {
                if (obj != target)
                {
                    notify_check(obj, sender, buff,
                        MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | key & MSG_HTML);
                }
            }
            if (key & MSG_S_OUTSIDE)
            {
                free_lbuf(buff);
            }
        }

        // Deliver message to neighbors.
        //
        if (  has_neighbors
           && (  (key & MSG_NBR)
              || (  (key & MSG_NBR_A)
                 && is_audible
                 && check_filter(target, sender, A_FILTER, msg))))
        {
            if (key & MSG_S_INSIDE)
            {
                tbuff = dflt_from_msg(sender, target);
                buff = add_prefix(target, sender, A_PREFIX, msg, "");
                free_lbuf(tbuff);
            }
            else
            {
                buff = (char *)msg;
            }
            DOLIST(obj, Contents(targetloc))
            {
                if (  obj != target
                   && obj != targetloc)
                {
                    notify_check(obj, sender, buff,
                    MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE);
                }
            }
            if (key & MSG_S_INSIDE)
            {
                free_lbuf(buff);
            }
        }

        // Deliver message to container.
        //
        if (  has_neighbors
           && (  (key & MSG_LOC)
              || ( (key & MSG_LOC_A)
                 && is_audible
                 && check_filter(target, sender, A_FILTER, msg))))
        {
            if (key & MSG_S_INSIDE)
            {
                tbuff = dflt_from_msg(sender, target);
                buff = add_prefix(target, sender, A_PREFIX, msg, tbuff);
                free_lbuf(tbuff);
            }
            else
            {
                buff = (char *)msg;
            }
            notify_check(targetloc, sender, buff,
                MSG_ME | MSG_F_UP | MSG_S_INSIDE);
            if (key & MSG_S_INSIDE)
            {
                free_lbuf(buff);
            }
        }
    }
    if (msg_ns)
    {
        free_lbuf(msg_ns);
    }
    mudstate.ntfy_nest_lev--;
}

void notify_except(dbref loc, dbref player, dbref exception, const char *msg, int key)
{
    dbref first;

    if (loc != exception)
    {
        notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A | key));
    }
    DOLIST(first, Contents(loc))
    {
        if (first != exception)
        {
            notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE | key));
        }
    }
}

void notify_except2(dbref loc, dbref player, dbref exc1, dbref exc2, const char *msg)
{
    dbref first;

    if (  loc != exc1
       && loc != exc2)
    {
        notify_check(loc, player, msg, (MSG_ME_ALL | MSG_F_UP | MSG_S_INSIDE | MSG_NBR_EXITS_A));
    }
    DOLIST(first, Contents(loc))
    {
        if (  first != exc1
           && first != exc2)
        {
            notify_check(first, player, msg, (MSG_ME | MSG_F_DOWN | MSG_S_OUTSIDE));
        }
    }
}

/* ----------------------------------------------------------------------
 * Reporting of CPU information.
 */

static void report_timecheck
(
    dbref player,
    bool yes_screen,
    bool yes_log,
    bool yes_clear
)
{
    int thing, obj_counted;
    CLinearTimeDelta ltdPeriod, ltdTotal;
    CLinearTimeAbsolute ltaNow;
    ltaNow.GetUTC();
    ltdPeriod = ltaNow - mudstate.cpu_count_from;

    if (  yes_log
       && (LOG_TIMEUSE & mudconf.log_options))
    {
        start_log("OBJ", "CPU");
        log_name(player);
        log_text(" checks object time use over ");
        log_number(ltdPeriod.ReturnSeconds());
        log_text(" seconds" ENDLINE);
    }
    else
    {
        yes_log = false;
        STARTLOG(LOG_ALWAYS, "WIZ", "TIMECHECK");
        log_name(player);
        log_text(" checks object time use over ");
        log_number(ltdPeriod.ReturnSeconds());
        log_text(" seconds");
        ENDLOG;
    }

    obj_counted = 0;
    ltdTotal.Set100ns(0);

    // Step through the db. Care only about the ones that are nonzero.
    //
    DO_WHOLE_DB(thing)
    {
        CLinearTimeDelta &ltd = db[thing].cpu_time_used;
        if (ltd.Return100ns())
        {
            ltdTotal += ltd;
            long used_msecs = ltd.ReturnMilliseconds();
            obj_counted++;
            if (yes_log)
            {
                Log.tinyprintf("#%d\t%ld" ENDLINE, thing, used_msecs);
            }
            if (yes_screen)
            {
                raw_notify(player, tprintf("#%d\t%ld", thing, used_msecs));
            }
            if (yes_clear)
            {
                ltd.Set100ns(0);
            }
        }
    }

    if (yes_screen)
    {
        raw_notify(player,
            tprintf("Counted %d objects using %ld msecs over %d seconds.",
            obj_counted, ltdTotal.ReturnMilliseconds(), ltdPeriod.ReturnSeconds()));
    }

    if (yes_log)
    {
        Log.tinyprintf("Counted %d objects using %ld msecs over %d seconds.",
            obj_counted, ltdTotal.ReturnMilliseconds(), ltdPeriod.ReturnSeconds());
        end_log();
    }

    if (yes_clear)
    {
        mudstate.cpu_count_from = ltaNow;
    }
}

void do_timecheck(dbref executor, dbref caller, dbref enactor, int key)
{
    bool yes_screen, yes_log, yes_clear;

    yes_screen = yes_log = yes_clear = false;

    if (key == 0)
    {
        // No switches, default to printing to screen and clearing counters.
        //
        yes_screen = true;
        yes_clear = true;
    }
    else
    {
        if (key & TIMECHK_RESET)
        {
            yes_clear = true;
        }
        if (key & TIMECHK_SCREEN)
        {
            yes_screen = true;
        }
        if (key & TIMECHK_LOG)
        {
            yes_log = true;
        }
    }
    report_timecheck(executor, yes_screen, yes_log, yes_clear);
}

void do_shutdown(dbref executor, dbref caller, dbref enactor, int key, char *message)
{
    if (!Can_SiteAdmin(executor))
    {
        notify(executor, NOPERM_MESSAGE);
        return;
    }

    raw_broadcast(0, "GAME: Shutdown by %s", Name(Owner(executor)));
    STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN");
    log_text("Shutdown by ");
    log_name(executor);
    ENDLOG;

    STARTLOG(LOG_ALWAYS, "WIZ", "SHTDN");
    log_text("Shutdown status: ");
    log_text(message);
    ENDLOG;

    int fd = open(mudconf.status_file, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0600);
    if (fd != -1)
    {
        write(fd, message, strlen(message));
        write(fd, ENDLINE, sizeof(ENDLINE)-1);
        DebugTotalFiles++;
        if (close(fd) == 0)
        {
            DebugTotalFiles--;
        }
    }

    // Do we perform a normal or an emergency shutdown? Normal
    // shutdown is handled by exiting the main loop in shovechars,
    // emergency shutdown is done here.
    //
    if (key & SHUTDN_PANIC)
    {
        // Close down the network interface.
        //
        emergency_shutdown();

        // Close the attribute text db and dump the header db.
        //

#ifndef MEMORY_BASED
        // Save cached modified attribute list
        //
        al_store();
#endif // MEMORY_BASED

        pcache_sync();
        SYNC;
        CLOSE;

        STARTLOG(LOG_ALWAYS, "DMP", "PANIC");
        log_text("Panic dump: ");
        log_text(mudconf.crashdb);
        ENDLOG;
        dump_database_internal(DUMP_I_PANIC);
        STARTLOG(LOG_ALWAYS, "DMP", "DONE");
        log_text("Panic dump complete: ");
        log_text(mudconf.crashdb);
        ENDLOG;
    }

    // Set up for normal shutdown.
    //
    mudstate.shutdown_flag = true;
}

// There are several types of dumps:
//
// Type 0 - Normal   mudstate.dumping controlled
// Type 1 - Panic    uncontrolled but only one of these happening at a time.
// Type 2 - Restart  mudstate.dumping controlled.
// Type 3 - FLAT     mudstate.dumping controlled.
// Type 4 - signal   uncontrolled and if we fault twice, the game ends --
//                   see check_panicking.
//
// When changing this function and to keep forking dumps safe, keep in mind
// that the following combinations can be occuring at the same time. Don't
// touch each other's files.
//
// Type 0 and 2 are allowed to touch each other's files. Type 1 and 4 should not
// touch files used in Type 0 or Type 2.
//
typedef struct
{
    char **ppszOutputBase;
    char szOutputSuffix[14];
    bool bUseTemporary;
    int  fType;
    char *pszErrorMessage;
} DUMP_PROCEDURE;

DUMP_PROCEDURE DumpProcedures[NUM_DUMP_TYPES] =
{
    { 0,                ""       , false, 0,                             "" }, // 0 -- Handled specially.
    { &mudconf.crashdb, ""       , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening crash file" }, // 1
    { &mudconf.indb,    ""       , true,  OUTPUT_VERSION | OUTPUT_FLAGS, "Opening input file" }, // 2
    { &mudconf.indb,   ".FLAT"   , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening flatfile"   }, // 3
    { &mudconf.indb,   ".SIG"    , false, UNLOAD_VERSION | UNLOAD_FLAGS, "Opening signalled flatfile"}  // 4
};

#ifdef WIN32
#define POPEN_READ_OP "rb"
#define POPEN_WRITE_OP "wb"
#else // WIN32
#define POPEN_READ_OP "r"
#define POPEN_WRITE_OP "w"
#endif // WIN32

void dump_database_internal(int dump_type)
{
    char tmpfile[SIZEOF_PATHNAME+32];
    char outfn[SIZEOF_PATHNAME+32];
    char prevfile[SIZEOF_PATHNAME+32];
    FILE *f;

    if (  dump_type < 0
       || NUM_DUMP_TYPES <= dump_type)
    {
        return;
    }

    bool bPotentialConflicts = false;
#ifndef WIN32
    // If we are already dumping for some reason, and suddenly get a type 1 or
    // type 4 dump, basically don't touch mail and comsys files. The other
    // dump will take care of them as well as can be expected for now, and if
    // we try to, we'll just step on them.
    //
    if (  mudstate.dumping
       && (  dump_type == DUMP_I_PANIC
          || dump_type == DUMP_I_SIGNAL))
    {
        bPotentialConflicts = true;
    }
#endif

    // Call the local dump function only if another dump is not already
    // in progress.
    //
    local_dump_database(dump_type);

    if (0 < dump_type)
    {
        DUMP_PROCEDURE *dp = &DumpProcedures[dump_type];

        sprintf(outfn, "%s%s", *(dp->ppszOutputBase), dp->szOutputSuffix);
        if (dp->bUseTemporary)
        {
            sprintf(tmpfile, "%s.#%d#", outfn, mudstate.epoch);
            RemoveFile(tmpfile);
            f = fopen(tmpfile, "wb");
        }
        else
        {
            RemoveFile(outfn);
            f = fopen(outfn, "wb");
        }

        if (f)
        {
            DebugTotalFiles++;
            setvbuf(f, NULL, _IOFBF, 16384);
            db_write(f, F_MUX, dp->fType);
            if (fclose(f) == 0)
            {
                DebugTotalFiles--;
            }

            if (dp->bUseTemporary)
            {
                ReplaceFile(tmpfile, outfn);
            }
        }
        else
        {
            log_perror("DMP", "FAIL", dp->pszErrorMessage, outfn);
        }

        if (!bPotentialConflicts)
        {
            if (mudconf.have_mailer)
            {
                f = fopen(mudconf.mail_db, "wb");
                if (f)
                {
                    DebugTotalFiles++;
                    dump_mail(f);
                    if (fclose(f) == 0)
                    {
                        DebugTotalFiles--;
                    }
                }
            }
            if (mudconf.have_comsys)
            {
                save_comsys(mudconf.comsys_db);
            }
        }
        return;
    }

    // Nuke our predecessor
    //
    if (mudconf.compress_db)
    {
        sprintf(prevfile, "%s.prev.gz", mudconf.outdb);
        sprintf(tmpfile, "%s.#%d#.gz", mudconf.outdb, mudstate.epoch - 1);
        RemoveFile(tmpfile);
        sprintf(tmpfile, "%s.#%d#.gz", mudconf.outdb, mudstate.epoch);
        strcpy(outfn, mudconf.outdb);
        strcat(outfn, ".gz");

        f = popen(tprintf("%s > %s", mudconf.compress, tmpfile), POPEN_WRITE_OP);
        if (f)
        {
            DebugTotalFiles++;
            setvbuf(f, NULL, _IOFBF, 16384);
            db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS);
            if (pclose(f) != -1)
            {
                DebugTotalFiles--;
            }
            ReplaceFile(outfn, prevfile);
            if (ReplaceFile(tmpfile, outfn) < 0)
            {
                log_perror("SAV", "FAIL", "Renaming output file to DB file", tmpfile);
            }
        }
        else
        {
            log_perror("SAV", "FAIL", "Opening", tmpfile);
        }
    }
    else
    {
        sprintf(prevfile, "%s.prev", mudconf.outdb);
        sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch - 1);
        RemoveFile(tmpfile);
        sprintf(tmpfile, "%s.#%d#", mudconf.outdb, mudstate.epoch);

        f = fopen(tmpfile, "wb");
        if (f)
        {
            DebugTotalFiles++;
            setvbuf(f, NULL, _IOFBF, 16384);
            db_write(f, F_MUX, OUTPUT_VERSION | OUTPUT_FLAGS);
            if (fclose(f) == 0)
            {
                DebugTotalFiles--;
            }
            ReplaceFile(mudconf.outdb, prevfile);
            if (ReplaceFile(tmpfile, mudconf.outdb) < 0)
            {
                log_perror("SAV", "FAIL", "Renaming output file to DB file", tmpfile);
            }
        }
        else
        {
            log_perror("SAV", "FAIL", "Opening", tmpfile);
        }
    }

    if (mudconf.have_mailer)
    {
        f = fopen(mudconf.mail_db, "wb");
        if (f)
        {
            DebugTotalFiles++;
            dump_mail(f);
            if (fclose(f) == 0)
            {
                DebugTotalFiles--;
            }
        }
    }

    if (mudconf.have_comsys)
    {
        save_comsys(mudconf.comsys_db);
    }
}

void dump_database(void)
{
    char *buff;

    mudstate.epoch++;

#ifndef WIN32
    if (mudstate.dumping)
    {
        STARTLOG(LOG_DBSAVES, "DMP", "DUMP");
        log_text("Waiting on previously-forked child before dumping... ");
        ENDLOG;

        while (mudstate.dumping)
        {
            // We have a forked dump in progress, so we will wait until the
            // child exits.
            //
            MuxAlarm.Sleep(time_1s);
        }
    }
    mudstate.dumping = true;
#endif
    buff = alloc_mbuf("dump_database");
    sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch);

    STARTLOG(LOG_DBSAVES, "DMP", "DUMP");
    log_text("Dumping: ");
    log_text(buff);
    ENDLOG;

#ifndef MEMORY_BASED
    // Save cached modified attribute list
    //
    al_store();
#endif // MEMORY_BASED

    pcache_sync();

    dump_database_internal(DUMP_I_NORMAL);
    SYNC;

    STARTLOG(LOG_DBSAVES, "DMP", "DONE")
    log_text("Dump complete: ");
    log_text(buff);
    ENDLOG;
    free_mbuf(buff);

#ifndef WIN32
    // This doesn't matter. We are about the stop the game. However,
    // leave it in.
    //
    mudstate.dumping = false;
#endif
}

void fork_and_dump(int key)
{
#ifndef WIN32
    static volatile bool bRequestAccepted = false;

    // fork_and_dump is never called with mudstate.dumping true, but we'll
    // ensure that assertion now.
    //
    if (  bRequestAccepted
       || mudstate.dumping)
    {
        return;
    }
    bRequestAccepted = true;
#endif

    // If no options were given, then it means DUMP_TEXT+DUMP_STRUCT.
    //
    if (key == 0)
    {
        key = DUMP_TEXT+DUMP_STRUCT;
    }

    if (*mudconf.dump_msg)
    {
        raw_broadcast(0, "%s", mudconf.dump_msg);
    }
    check_mail_expiration();
    char *buff = alloc_lbuf("fork_and_dump");
    if (key & (DUMP_TEXT|DUMP_STRUCT))
    {
        STARTLOG(LOG_DBSAVES, "DMP", "CHKPT");
        if (key & DUMP_TEXT)
        {
            log_text("SYNCing");
            if (key & DUMP_STRUCT)
            {
                log_text(" and ");
            }
        }
        if (key & DUMP_STRUCT)
        {
            mudstate.epoch++;
            sprintf(buff, "%s.#%d#", mudconf.outdb, mudstate.epoch);
            log_text("Checkpointing: ");
            log_text(buff);
        }
        ENDLOG;
    }
    if (key & DUMP_FLATFILE)
    {
        STARTLOG(LOG_DBSAVES, "DMP", "FLAT");
        log_text("Creating flatfile: ");
        sprintf(buff, "%s.FLAT", mudconf.outdb);
        log_text(buff);
        ENDLOG;
    }
    free_lbuf(buff);

#ifndef MEMORY_BASED
    // Save cached modified attribute list
    //
    al_store();
#endif // MEMORY_BASED

    pcache_sync();
    SYNC;

#ifndef WIN32
    mudstate.write_protect = true;
    int child = 0;
    bool bChildExists = false;
    mudstate.dumping = true;
    bool bAttemptFork = mudconf.fork_dump;
#if !defined(HAVE_PREAD) \
 || !defined(HAVE_PWRITE)
    if (key & DUMP_FLATFILE)
    {
        // Don't attempt a fork()'ed @dump/flat without pread()/pwrite()
        // support.
        //
        bAttemptFork = false;
    }
#endif // !HAVE_PREAD !HAVE_PWRITE
#endif // WIN32
    if (key & (DUMP_STRUCT|DUMP_FLATFILE))
    {
#ifndef WIN32
        if (bAttemptFork)
        {
            child = fork();
        }
        if (child == 0)
        {
#endif
            if (key & DUMP_STRUCT)
            {
                dump_database_internal(DUMP_I_NORMAL);
            }
            if (key & DUMP_FLATFILE)
            {
                dump_database_internal(DUMP_I_FLAT);
            }
#ifndef WIN32
            if (mudconf.fork_dump)
            {
                _exit(0);
            }
        }
        else if (child < 0)
        {
            log_perror("DMP", "FORK", NULL, "fork()");
        }
        else if (child != mudstate.dumper)
        {
            mudstate.dumper = child;
            bChildExists = true;
        }
        else if (child == mudstate.dumper)
        {
            // The child process executed and exited before fork() returned to
            // the parent process.  Without a process id, the parent's SIGCHLD
            // handler could not be certain that the pid of the exiting
            // process would match the pid of this child.
            //
            // However, at the this point, we can be sure.  But, there's
            // nothing much left to do.
            //
            // See SIGCHLD handler in bsd.cpp.
            //
            mudstate.dumper = 0;

            // There is no child (bChildExists == false), we aren't dumping
            // (mudstate.dumping == false) and there is no outstanding dumper
            // process (mudstate.dumper == 0).
        }
#endif
    }

#ifndef WIN32
    mudstate.write_protect = false;
    if (!bChildExists)
    {
        // We have the ability to fork children, but we are not configured to
        // use it; or, we tried to fork a child and failed; or, we didn't
        // need to dump the structure or a flatfile; or, the child has finished
        // dumping already.
        //
        mudstate.dumping = false;
        mudstate.dumper = 0;
    }
    bRequestAccepted = false;
#endif

    if (*mudconf.postdump_msg)
    {
        raw_broadcast(0, "%s", mudconf.postdump_msg);
    }
}

#define LOAD_GAME_SUCCESS           0
#define LOAD_GAME_NO_INPUT_DB     (-1)
#define LOAD_GAME_CANNOT_OPEN     (-2)
#define LOAD_GAME_LOADING_PROBLEM (-3)

#ifdef MEMORY_BASED
static int load_game(void)
#else // MEMORY_BASED
static int load_game(int ccPageFile)
#endif // MEMORY_BASED
{
    FILE *f = NULL;
    char infile[SIZEOF_PATHNAME+8];
    struct stat statbuf;
    int db_format, db_version, db_flags;

    bool compressed = false;

    if (mudconf.compress_db)
    {
        strcpy(infile, mudconf.indb);
        strcat(infile, ".gz");
        if (stat(infile, &statbuf) == 0)
        {
            f = popen(tprintf(" %s < %s", mudconf.uncompress, infile), POPEN_READ_OP);
            if (f != NULL)
            {
                DebugTotalFiles++;
                compressed = true;
            }
        }
    }

    if (!compressed)
    {
        strcpy(infile, mudconf.indb);
        if (stat(infile, &statbuf) != 0)
        {
            // Indicate that we couldn't load because the input db didn't
            // exist.
            //
            return LOAD_GAME_NO_INPUT_DB;
        }
        if ((f = fopen(infile, "rb")) == NULL)
        {
            return LOAD_GAME_CANNOT_OPEN;
        }
        DebugTotalFiles++;
        setvbuf(f, NULL, _IOFBF, 16384);
    }

    // Ok, read it in.
    //
    STARTLOG(LOG_STARTUP, "INI", "LOAD")
    log_text("Loading: ");
    log_text(infile);
    ENDLOG
    if (db_read(f, &db_format, &db_version, &db_flags) < 0)
    {
        // Everything is not ok.
        //
        if (compressed)
        {
            if (pclose(f) != -1)
            {
                DebugTotalFiles--;
            }
        }
        else
        {
            if (fclose(f) == 0)
            {
                DebugTotalFiles--;
            }
        }
        f = 0;

        STARTLOG(LOG_ALWAYS, "INI", "FATAL")
        log_text("Error loading ");
        log_text(infile);
        ENDLOG
        return LOAD_GAME_LOADING_PROBLEM;
    }

    // Everything is ok.
    //
    if (compressed)
    {
        if (pclose(f) != -1)
        {
            DebugTotalFiles--;
        }
    }
    else
    {
        if (fclose(f) == 0)
        {
            DebugTotalFiles--;
        }
    }
    f = 0;

#ifndef MEMORY_BASED
    if (db_flags & V_DATABASE)
    {
        // It loaded an output file.
        //
        if (ccPageFile == HF_OPEN_STATUS_NEW)
        {
            STARTLOG(LOG_STARTUP, "INI", "LOAD");
            log_text("Attributes are not present in either the input file or the attribute database.");
            ENDLOG;
        }
    }
    else
    {
        // It loaded a flatfile.
        //
        if (ccPageFile == HF_OPEN_STATUS_OLD)
        {
            STARTLOG(LOG_STARTUP, "INI", "LOAD");
            log_text("Attributes present in both the input file and the attribute database.");
            ENDLOG;
        }
    }
#endif // !MEMORY_BASED

    if (mudconf.have_comsys)
    {
        load_comsys(mudconf.comsys_db);
    }

    if (mudconf.have_mailer)
    {
        f = fopen(mudconf.mail_db, "rb");
        if (f)
        {
            DebugTotalFiles++;
            setvbuf(f, NULL, _IOFBF, 16384);
            Log.tinyprintf("LOADING: %s" ENDLINE, mudconf.mail_db);
            load_mail(f);
            Log.tinyprintf("LOADING: %s (done)" ENDLINE, mudconf.mail_db);
            if (fclose(f) == 0)
            {
                DebugTotalFiles--;
            }
            f = 0;
        }
    }
    STARTLOG(LOG_STARTUP, "INI", "LOAD");
    log_text("Load complete.");
    ENDLOG;

    return LOAD_GAME_SUCCESS;
}


/*
 * match a list of things, using the no_command flag
 *
 * This seems to be always called with type == AMATCH_CMD...
 * So the fact that ansi_strip is done within atr_match only
 * brings about a if () performance hit...
 *
 */

bool list_check
(
    dbref thing,
    dbref player,
    char  type,
    char  *str,
    char  *raw_str,
    bool check_parent
)
{
    bool bMatch = false;

    int limit = mudstate.db_top;
    while (NOTHING != thing)
    {
#ifdef REALITY_LVLS
        if ((thing != player)
           && (!(No_Command(thing)))
           && IsReal(thing, player))
#else
        if (  thing != player
           && !No_Command(thing))
#endif /* REALITY_LVLS */
        {
            bMatch |= atr_match(thing, player, type, str, raw_str, check_parent);
        }

        // Non-authoritative test of circular reference.
        //
        dbref next;
        if (  thing == (next = Next(thing))
           || --limit < 0
           || MuxAlarm.bAlarmed)
        {
            break;
        }
        thing = next;
    }
    return bMatch;
}

bool Hearer(dbref thing)
{
    if (  mudstate.inpipe
       && thing == mudstate.poutobj)
    {
        return true;
    }

    if (  Connected(thing)
       || Puppet(thing)
       || H_Listen(thing))
    {
        return true;
    }

    if (mudstate.bfNoListens.IsSet(thing))
    {
        return false;
    }
    else if (mudstate.bfListens.IsSet(thing))
    {
        return true;
    }

    bool bFoundCommands = false;
    bool bFoundListens  = false;

    if (Monitor(thing))
    {
        char *as, *buff, *s;
        dbref aowner;
        int atr, aflags;
        ATTR *ap;

        buff = alloc_lbuf("Hearer");
        atr_push();
        for (atr = atr_head(thing, &as); atr; atr = atr_next(&as))
        {
            ap = atr_num(atr);
            if (  !ap
               || (ap->flags & AF_NOPROG))
            {
                continue;
            }

            atr_get_str(buff, thing, atr, &aowner, &aflags);
            if (!(aflags & AF_NOPROG))
            {
                switch (buff[0])
                {
                case AMATCH_CMD:
                    bFoundCommands = true;
                    break;

                case AMATCH_LISTEN:
                    bFoundListens = true;
                    break;
                }
            }

            // Make sure we can execute it.
            //
            if (  buff[0] != AMATCH_LISTEN
               || (aflags & AF_NOPROG))
            {
                continue;
            }

            // Make sure there's a : in it.
            //
            for (s = buff + 1; *s && *s != ':'; s++)
            {
                ; // Nothing
            }
            if (s)
            {
                free_lbuf(buff);
                atr_pop();
                mudstate.bfListens.Set(thing);
                return true;
            }
        }
        free_lbuf(buff);
        atr_pop();

        mudstate.bfNoListens.Set(thing);

        if (bFoundCommands)
        {
            mudstate.bfNoCommands.Clear(thing);
            mudstate.bfCommands.Set(thing);
        }
        else
        {
            mudstate.bfCommands.Clear(thing);
            mudstate.bfNoCommands.Set(thing);
        }
    }
    return false;
}

void do_readcache(dbref executor, dbref caller, dbref enactor, int key)
{
    helpindex_load(executor);
    fcache_load(executor);
}

static void process_preload(void)
{
    dbref thing, parent, aowner;
    int aflags, lev, i;
    char *tstr;
    FWDLIST *fp;

    fp = (FWDLIST *) alloc_lbuf("process_preload.fwdlist");
    tstr = alloc_lbuf("process_preload.string");
    i = 0;
    DO_WHOLE_DB(thing)
    {
        // Ignore GOING objects.
        //
        if (Going(thing))
        {
            continue;
        }

        scheduler.RunTasks(10);

        // Look for a STARTUP attribute in parents.
        //
        if (mudconf.run_startup)
        {
            ITER_PARENTS(thing, parent, lev)
            {
                if (Flags(thing) & HAS_STARTUP)
                {
                    did_it(Owner(thing), thing, 0, NULL, 0, NULL, A_STARTUP,
                        (char **)NULL, 0);

                    // Process queue entries as we add them.
                    //
                    scheduler.RunTasks(10);
                    break;
                 }
            }
        }

        // Look for a FORWARDLIST attribute.
        //
        if (H_Fwdlist(thing))
        {
            atr_get_str(tstr, thing, A_FORWARDLIST, &aowner, &aflags);
            if (*tstr)
            {
                fwdlist_load(fp, GOD, tstr);
                if (fp->count > 0)
                {
                    fwdlist_set(thing, fp);
                }
            }
        }
    }
    free_lbuf(fp);
    free_lbuf(tstr);
}

#ifndef MEMORY_BASED

/*
 * ---------------------------------------------------------------------------
 * * info: display info about the file being read or written.
 */

void info(int fmt, int flags, int ver)
{
    const char *cp;

    if (fmt == F_MUX)
    {
        cp = "MUX";
    }
    else
    {
        cp = "*unknown*";
    }
    Log.tinyprintf("%s version %d:", cp, ver);
    if ((flags & MANDFLAGS) != MANDFLAGS)
    {
        Log.WriteString(" Unsupported flags");
    }
    if (flags & V_DATABASE)
        Log.WriteString(" Database");
    if (flags & V_ATRNAME)
        Log.WriteString(" AtrName");
    if (flags & V_ATRKEY)
        Log.WriteString(" AtrKey");
    if (flags & V_ATRMONEY)
        Log.WriteString(" AtrMoney");
    Log.WriteString("\n");
}

char *standalone_infile = NULL;
char *standalone_outfile = NULL;
char *standalone_basename = NULL;
bool standalone_check = false;
bool standalone_load = false;
bool standalone_unload = false;

void dbconvert(void)
{
    int setflags, clrflags, ver;
    int db_ver, db_format, db_flags;

    Log.SetBasename("-");
    Log.StartLogging();

    SeedRandomNumberGenerator();

    pool_init(POOL_LBUF, LBUF_SIZE);
    pool_init(POOL_MBUF, MBUF_SIZE);
    pool_init(POOL_SBUF, SBUF_SIZE);
    pool_init(POOL_BOOL, sizeof(struct boolexp));

    cf_init();

    // Decide what conversions to do and how to format the output file.
    //
    setflags = clrflags = ver = 0;
    bool do_redirect = false;

    bool do_write = true;
    if (standalone_check)
    {
        do_write = false;
    }
    if (standalone_load)
    {
        clrflags = 0xffffffff;
        setflags = OUTPUT_FLAGS;
        ver = OUTPUT_VERSION;
        do_redirect = true;
    }
    else if (standalone_unload)
    {
        clrflags = 0xffffffff;
        setflags = UNLOAD_FLAGS;
        ver = UNLOAD_VERSION;
    }

    // Open the database
    //
    init_attrtab();

    char dirfile[SIZEOF_PATHNAME];
    char pagfile[SIZEOF_PATHNAME];
    strcpy(dirfile, standalone_basename);
    strcat(dirfile, ".dir");
    strcpy(pagfile, standalone_basename);
    strcat(pagfile, ".pag");

    int cc = init_dbfile(dirfile, pagfile, 650);
    if (cc == HF_OPEN_STATUS_ERROR)
    {
        Log.tinyprintf("Can't open database in (%s, %s) files\n", dirfile, pagfile);
        exit(1);
    }
    else if (cc == HF_OPEN_STATUS_OLD)
    {
        if (setflags == OUTPUT_FLAGS)
        {
            Log.tinyprintf("Would overwrite existing database (%s, %s)\n", dirfile, pagfile);
            CLOSE;
            exit(1);
        }
    }
    else if (cc == HF_OPEN_STATUS_NEW)
    {
        if (setflags == UNLOAD_FLAGS)
        {
            Log.tinyprintf("Database (%s, %s) is empty.\n", dirfile, pagfile);
            CLOSE;
            exit(1);
        }
    }

    FILE *fpIn = fopen(standalone_infile, "rb");
    if (!fpIn)
    {
        exit(1);
    }

    // Go do it.
    //
    if (do_redirect)
    {
        extern void cache_redirect(void);
        cache_redirect();
    }
    setvbuf(fpIn, NULL, _IOFBF, 16384);
    db_read(fpIn, &db_format, &db_ver, &db_flags);
    if (do_redirect)
    {
        extern void cache_pass2(void);
        cache_pass2();
    }
    Log.WriteString("Input: ");
    info(db_format, db_flags, db_ver);

    if (standalone_check)
    {
        do_dbck(NOTHING, NOTHING, NOTHING, DBCK_FULL);
    }
    fclose(fpIn);

    if (do_write)
    {
        FILE *fpOut = fopen(standalone_outfile, "wb");
        if (!fpOut)
        {
            exit(1);
        }

        db_flags = (db_flags & ~clrflags) | setflags;
        if (db_format != F_MUX)
        {
            db_ver = 3;
        }
        if (ver != 0)
        {
            db_ver = ver;
        }
        Log.WriteString("Output: ");
        info(F_MUX, db_flags, db_ver);
        setvbuf(fpOut, NULL, _IOFBF, 16384);
#ifndef MEMORY_BASED
        // Save cached modified attribute list
        //
        al_store();
#endif // MEMORY_BASED
        db_write(fpOut, F_MUX, db_ver | db_flags);
        fclose(fpOut);
    }
    CLOSE;
    db_free();
    exit(0);
}
#endif // MEMORY_BASED

void write_pidfile(const char *pFilename)
{
    FILE *fp = fopen(pFilename, "wb");
    if (fp)
    {
        fprintf(fp, "%d" ENDLINE, game_pid);
        fclose(fp);
    }
    else
    {
        STARTLOG(LOG_ALWAYS, "PID", "FAIL");
        Log.tinyprintf("Failed to write pidfile %s\n", pFilename);
        ENDLOG;
    }
}

long DebugTotalFiles = 3;
long DebugTotalSockets = 0;
#ifdef WIN32
long DebugTotalThreads = 1;
long DebugTotalSemaphores = 0;
#endif
#ifdef MEMORY_ACCOUNTING
long DebugTotalMemory = 0;
#endif

#define CLI_DO_CONFIG_FILE CLI_USER+0
#define CLI_DO_MINIMAL     CLI_USER+1
#define CLI_DO_VERSION     CLI_USER+2
#define CLI_DO_USAGE       CLI_USER+3
#define CLI_DO_INFILE      CLI_USER+4
#define CLI_DO_OUTFILE     CLI_USER+5
#define CLI_DO_CHECK       CLI_USER+6
#define CLI_DO_LOAD        CLI_USER+7
#define CLI_DO_UNLOAD      CLI_USER+8
#define CLI_DO_BASENAME    CLI_USER+9
#define CLI_DO_PID_FILE    CLI_USER+10
#define CLI_DO_ERRORPATH   CLI_USER+11

bool bMinDB = false;
bool bSyntaxError = false;
char *conffile = NULL;
bool bVersion = false;
char *pErrorBasename = "";
bool bServerOption = false;

#ifdef MEMORY_BASED
#define NUM_CLI_OPTIONS 6
#else
#define NUM_CLI_OPTIONS 12
#endif

CLI_OptionEntry OptionTable[NUM_CLI_OPTIONS] =
{
    { "c", CLI_REQUIRED, CLI_DO_CONFIG_FILE },
    { "s", CLI_NONE,     CLI_DO_MINIMAL     },
    { "v", CLI_NONE,     CLI_DO_VERSION     },
    { "h", CLI_NONE,     CLI_DO_USAGE       },
#ifndef MEMORY_BASED
    { "i", CLI_REQUIRED, CLI_DO_INFILE      },
    { "o", CLI_REQUIRED, CLI_DO_OUTFILE     },
    { "k", CLI_NONE,     CLI_DO_CHECK       },
    { "l", CLI_NONE,     CLI_DO_LOAD        },
    { "u", CLI_NONE,     CLI_DO_UNLOAD      },
    { "d", CLI_REQUIRED, CLI_DO_BASENAME    },
#endif // MEMORY_BASED
    { "p", CLI_REQUIRED, CLI_DO_PID_FILE    },
    { "e", CLI_REQUIRED, CLI_DO_ERRORPATH   }
};

void CLI_CallBack(CLI_OptionEntry *p, char *pValue)
{
    if (p)
    {
        switch (p->m_Unique)
        {
        case CLI_DO_PID_FILE:
            bServerOption = true;
            mudconf.pid_file = pValue;
            break;

        case CLI_DO_CONFIG_FILE:
            bServerOption = true;
            conffile = pValue;
            break;

        case CLI_DO_MINIMAL:
            bServerOption = true;
            bMinDB = true;
            break;

        case CLI_DO_VERSION:
            bServerOption = true;
            bVersion = true;
            break;

        case CLI_DO_ERRORPATH:
            bServerOption = true;
            pErrorBasename = pValue;
            break;

#ifndef MEMORY_BASED
        case CLI_DO_INFILE:
            mudstate.bStandAlone = true;
            standalone_infile = pValue;
            break;

        case CLI_DO_OUTFILE:
            mudstate.bStandAlone = true;
            standalone_outfile = pValue;
            break;

        case CLI_DO_CHECK:
            mudstate.bStandAlone = true;
            standalone_check = true;
            break;

        case CLI_DO_LOAD:
            mudstate.bStandAlone = true;
            standalone_load = true;
            break;

        case CLI_DO_UNLOAD:
            mudstate.bStandAlone = true;
            standalone_unload = true;
            break;

        case CLI_DO_BASENAME:
            mudstate.bStandAlone = true;
            standalone_basename = pValue;
            break;
#endif

        case CLI_DO_USAGE:
        default:
            bSyntaxError = true;
            break;
        }
    }
    else
    {
        bSyntaxError = true;
    }
}

#if defined(__INTEL_COMPILER)

extern "C" unsigned int __intel_cpu_indicator;

#define CPU_FD_ID 0x00200000UL

#define CPUID_0 0

// GenuineIntel
//
#define INTEL_MFGSTR0 'uneG'
#define INTEL_MFGSTR1 'letn'
#define INTEL_MFGSTR2 'Ieni'

// AuthenticAMD
//
#define AMD_MFGSTR0   'htuA'
#define AMD_MFGSTR1   'DMAc'
#define AMD_MFGSTR2   'itne'

#define CPUID_1 1

#define CPU_STEPPING(x)  ((x      ) & 0x00000000F)
#define CPU_MODEL(x)     ((x >>  4) & 0x00000000F)
#define CPU_FAMILY(x)    ((x >>  8) & 0x00000000F)
#define CPU_TYPE(x)      ((x >> 12) & 0x00000000F)
#define CPU_EXTMODEL(x)  ((x >> 16) & 0x00000000F)
#define CPU_EXTFAMILY(x) ((x >> 20) & 0x00000000F)

#define CPU_FEATURE_MMX  0x00800000UL
#define CPU_FEATURE_FSXR 0x01000000UL
#define CPU_FEATURE_SSE  0x02000000UL
#define CPU_FEATURE_SSE2 0x04000000UL
#define CPU_MSR_SSE3     0x00000001UL

// Indicators.
//
// OLDOS tags indicate that the CPU supports SSE[n], but the operating system
// will throw an exception when they are used.
//
//
#define CPU_TYPE_UNSPECIALIZED               0x00000001UL
#define CPU_TYPE_FAMILY_5                    0x00000002UL
#define CPU_TYPE_FAMILY_6                    0x00000004UL
#define CPU_TYPE_FAMILY_5_MMX                0x00000008UL
#define CPU_TYPE_FAMILY_6_MMX                0x00000010UL
#define CPU_TYPE_FAMILY_6_MMX_FSXR           0x00000020UL
#define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE_OLDOS 0x00000040UL
#define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE       0x00000080UL
#define CPU_TYPE_FAMILY_F_SSE2_OLDOS         0x00000100UL
#define CPU_TYPE_FAMILY_F_SSE2               0x00000200UL
#define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE2      0x00000400UL
#define CPU_TYPE_FAMILY_6_MMX_FSXR_SSE3      0x00000800UL
#define CPU_TYPE_FAMILY_F_SSE3               0x00000800UL

void cpu_init(void)
{
    UINT32 dwCPUID;

    // Determine whether CPUID instruction is supported.
    //
    __asm
    {
        // Obtain a copy of the flags register.
        //
        pushfd
        pop     eax
        mov     dwCPUID,eax

        // Attempt to flip the ID bit.
        //
        xor     eax,CPU_FD_ID
        push    eax
        popfd

        // Obtain a second copy of the flags register.
        //
        pushfd
        pop     eax
        xor     dwCPUID,eax
    }

    // If the ID bit didn't toggle, the CPUID instruction is not supported.
    //
    if (CPU_FD_ID != dwCPUID)
    {
        // CPUID instruction is not supported.
        //
        __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
        return;
    }

    UINT32 dwHighest;
    UINT32 dwMfgStr0;
    UINT32 dwMfgStr1;
    UINT32 dwMfgStr2;

    // CPUID is supported.
    //
    __asm
    {
        mov eax,CPUID_0
        cpuid
        mov dwHighest,eax
        mov dwMfgStr0,ebx
        mov dwMfgStr1,ecx
        mov dwMfgStr2,edx
    }

    if (0 == dwHighest)
    {
        // We can't decipher anything with only CPUID (EAX=$0) available.
        //
        __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
        return;
    }

    typedef enum
    {
        Intel = 0,
        AMD
    } CPUMaker;

    CPUMaker maker;
    if (  INTEL_MFGSTR0 == dwMfgStr0
       && INTEL_MFGSTR1 == dwMfgStr1
       && INTEL_MFGSTR2 == dwMfgStr2)
    {
        maker = Intel;
    }
    else if (  AMD_MFGSTR0 == dwMfgStr0
            && AMD_MFGSTR1 == dwMfgStr1
            && AMD_MFGSTR2 == dwMfgStr2)
    {
        maker = AMD;
    }
    else
    {
        // It's not Intel or AMD.
        //
        __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
        return;
    }

    UINT32 dwSignature;
    UINT32 dwBrand;
    UINT32 dwMSR;
    UINT32 dwFeatures;

    __asm
    {
        mov eax,CPUID_1
        cpuid
        mov dwSignature,eax
        mov dwBrand,ebx
        mov dwMSR,ecx
        mov dwFeatures,edx
    }

    // Develop 'Effective' Family and Model.
    //
    UINT32 dwEffFamily;
    if (CPU_FAMILY(dwSignature) == 0xF)
    {
        dwEffFamily = CPU_FAMILY(dwSignature) + CPU_EXTFAMILY(dwSignature);
    }
    else
    {
        dwEffFamily = CPU_FAMILY(dwSignature);
    }
    UINT32 dwEffModel;
    if (CPU_MODEL(dwSignature) == 0xF)
    {
        dwEffModel = CPU_MODEL(dwSignature) + (CPU_EXTMODEL(dwSignature) << 4);
    }
    else
    {
        dwEffModel = CPU_MODEL(dwSignature);
    }

#define ADVF_MMX  0x00000001UL
#define ADVF_FSXR 0x00000002UL
#define ADVF_SSE  0x00000004UL
#define ADVF_SSE2 0x00000008UL
#define ADVF_SSE3 0x00000010UL

    UINT32 dwAdvFeatures = 0;

    // Decode the features the chips claim to possess.
    //
    if (dwFeatures & CPU_FEATURE_MMX)
    {
        dwAdvFeatures |= ADVF_MMX;
    }
    if (dwFeatures & CPU_FEATURE_FSXR)
    {
        dwAdvFeatures |= ADVF_FSXR;
    }
    if (dwFeatures & CPU_FEATURE_SSE)
    {
        dwAdvFeatures |= ADVF_SSE;
    }
    if (dwFeatures & CPU_FEATURE_SSE2)
    {
        dwAdvFeatures |= ADVF_SSE2;
    }
    if (  dwEffFamily <= 5
       && dwMSR & CPU_MSR_SSE3)
    {
        dwAdvFeatures |= ADVF_SSE3;
    }

    // Test whether operating system will allow use of these extensions.
    //
    UINT32 dwUseable = dwAdvFeatures;
    if (dwUseable & ADVF_MMX)
    {
        try
        {
            __asm
            {
                // Let's try a MMX instruction.
                //
                emms
            }
        }
        catch (...)
        {
            dwUseable &= ~(ADVF_MMX|ADVF_SSE|ADVF_SSE2|ADVF_SSE3);
        }
    }

    if (dwUseable & ADVF_SSE)
    {
        try
        {
            __asm
            {
                // Let's try a SSE instruction.
                //
                xorps xmm0, xmm0
            }
        }
        catch (...)
        {
            dwUseable &= ~(ADVF_SSE|ADVF_SSE2|ADVF_SSE3);
        }
    }

    if (dwUseable & ADVF_SSE2)
    {
        try
        {
            __asm
            {
                // Let's try a SSE2 instruction.
                //
                xorpd xmm0, xmm0
            }
        }
        catch (...)
        {
            dwUseable &= ~(ADVF_SSE2|ADVF_SSE3);
        }
    }

    if (dwUseable & ADVF_SSE3)
    {
        try
        {
            __asm
            {
                // Let's try a SSE3 instruction.
                //
                haddpd xmm1,xmm2
            }
        }
        catch (...)
        {
            dwUseable &= ~(ADVF_SSE3);
        }
    }

    // Map tested features to an indicator for CPU dispatching.
    //
    if (dwEffFamily <= 4)
    {
        __intel_cpu_indicator = CPU_TYPE_UNSPECIALIZED;
    }
    else if (5 == dwEffFamily)
    {
        if (dwUseable & ADVF_MMX)
        {
            __intel_cpu_indicator = CPU_TYPE_FAMILY_5_MMX;
        }
        else
        {
            __intel_cpu_indicator = CPU_TYPE_FAMILY_5;
        }
    }
    else
    {
        if (dwUseable & ADVF_MMX)
        {
            if (dwUseable & ADVF_FSXR)
            {
                if (dwUseable & ADVF_SSE)
                {
                    if (dwUseable & ADVF_SSE2)
                    {
                        if (dwUseable & ADVF_SSE3)
                        {
                            if (dwEffFamily < 15)
                            {
                                __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE3;
                            }
                            else
                            {
                                __intel_cpu_indicator = CPU_TYPE_FAMILY_F_SSE3;
                            }
                        }
                        else
                        {
                            if (dwEffFamily < 15)
                            {
                                __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE2;
                            }
                            else
                            {
                                __intel_cpu_indicator = CPU_TYPE_FAMILY_F_SSE2;
                            }
                        }
                    }
                    else
                    {
                        __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR_SSE;
                    }
                }
                else
                {
                    __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX_FSXR;
                }
            }
            else
            {
                __intel_cpu_indicator = CPU_TYPE_FAMILY_6_MMX;
            }
        }
        else
        {
            __intel_cpu_indicator = CPU_TYPE_FAMILY_6;
        }
    }

    // Report findings to the log.
    //
    fprintf(stderr, "cpu_init: %s, Family %d, Model %d, %s%s%s%s%s" ENDLINE,
        (Intel == maker ? "Intel" : (AMD == maker ? "AMD" : "Unknown")),
        dwEffFamily,
        dwEffModel,
        (dwUseable & ADVF_MMX)  ? "MMX " : "",
        (dwUseable & ADVF_FSXR) ? "FSXR ": "",
        (dwUseable & ADVF_SSE)  ? "SSE ": "",
        (dwUseable & ADVF_SSE2) ? "SSE2 ": "",
        (dwUseable & ADVF_SSE3) ? "SSE3 ": "");

    if (dwUseable != dwAdvFeatures)
    {
        UINT32 dw = dwAdvFeatures & (~dwUseable);
        fprintf(stderr, "cpu_init: %s%s%s%s%s unsupported by OS." ENDLINE,
            (dw & ADVF_MMX)  ? "MMX ": "",
            (dw & ADVF_FSXR) ? "FSXR ": "",
            (dw & ADVF_SSE)  ? "SSE ": "",
            (dw & ADVF_SSE2) ? "SSE2 ": "",
            (dw & ADVF_SSE3) ? "SSE3 ": "");
    }
}

#endif

#define DBCONVERT_NAME1 "dbconvert"
#define DBCONVERT_NAME2 "dbconvert.exe"

int DCL_CDECL main(int argc, char *argv[])
{
#if defined(__INTEL_COMPILER)
    cpu_init();
#endif

    build_version();

    // Look for dbconvert[.exe] in the program name.
    //
    size_t nProg = strlen(argv[0]);
    const char *pProg = argv[0] + nProg - 1;
    while (  nProg
          && (  mux_isalpha(*pProg)
             || *pProg == '.'))
    {
        nProg--;
        pProg--;
    }
    pProg++;
    mudstate.bStandAlone = false;
    if (  mux_stricmp(pProg, DBCONVERT_NAME1) == 0
       || mux_stricmp(pProg, DBCONVERT_NAME2) == 0)
    {
        mudstate.bStandAlone = true;
    }

    mudconf.pid_file = "netmux.pid";

    // Parse the command line
    //
    CLI_Process(argc, argv, OptionTable,
        sizeof(OptionTable)/sizeof(CLI_OptionEntry), CLI_CallBack);

#ifndef MEMORY_BASED
    if (mudstate.bStandAlone)
    {
        int n = 0;
        if (standalone_check)
        {
            n++;
        }
        if (standalone_load)
        {
            n++;
        }
        if (standalone_unload)
        {
            n++;
        }
        if (  !standalone_basename
           || !standalone_infile
           || !standalone_outfile
           || n != 1
           || bServerOption)
        {
            bSyntaxError = true;
        }
        else
        {
            dbconvert();
            return 0;
        }
    }
    else
#endif // MEMORY_BASED

    if (bVersion)
    {
        fprintf(stderr, "Version: %s" ENDLINE, mudstate.version);
        return 1;
    }
    if (  bSyntaxError
       || conffile == NULL
       || !bServerOption)
    {
        fprintf(stderr, "Version: %s" ENDLINE, mudstate.version);
        if (mudstate.bStandAlone)
        {
            fprintf(stderr, "Usage: %s -d <dbname> -i <infile> [-o <outfile>] [-l|-u|-k]" ENDLINE, pProg);
            fprintf(stderr, "  -d  Basename." ENDLINE);
            fprintf(stderr, "  -i  Input file." ENDLINE);
            fprintf(stderr, "  -k  Check." ENDLINE);
            fprintf(stderr, "  -l  Load." ENDLINE);
            fprintf(stderr, "  -o  Output file." ENDLINE);
            fprintf(stderr, "  -u  Unload." ENDLINE);
        }
        else
        {
            fprintf(stderr, "Usage: %s [-c <filename>] [-p <filename>] [-h] [-s] [-v]" ENDLINE, pProg);
            fprintf(stderr, "  -c  Specify configuration file." ENDLINE);
            fprintf(stderr, "  -e  Specify logfile basename (or '-' for stderr)." ENDLINE);
            fprintf(stderr, "  -h  Display this help." ENDLINE);
            fprintf(stderr, "  -p  Specify process ID file." ENDLINE);
            fprintf(stderr, "  -s  Start with a minimal database." ENDLINE);
            fprintf(stderr, "  -v  Display version string." ENDLINE ENDLINE);
        }
        return 1;
    }

    mudstate.bStandAlone = false;

    FLOAT_Initialize();
    TIME_Initialize();
    SeedRandomNumberGenerator();

    Log.SetBasename(pErrorBasename);
    Log.StartLogging();
    game_pid = getpid();
    write_pidfile(mudconf.pid_file);

    BuildSignalNamesTable();

#ifdef MEMORY_ACCOUNTING
    extern CHashFile hfAllocData;
    extern CHashFile hfIdentData;
    extern bool bMemAccountingInitialized;
    hfAllocData.Open("svdptrs.dir", "svdptrs.pag", 40);
    hfIdentData.Open("svdlines.dir", "svdlines.pag", 40);
    bMemAccountingInitialized = true;
#endif

#ifdef WIN32
    // Find which version of Windows we are using - Completion ports do
    // not work with Windows 95/98

    OSVERSIONINFO VersionInformation;

    VersionInformation.dwOSVersionInfoSize = sizeof (VersionInformation);
    GetVersionEx(&VersionInformation);
    platform = VersionInformation.dwPlatformId;
    hGameProcess = GetCurrentProcess();
    if (platform == VER_PLATFORM_WIN32_NT)
    {
        Log.WriteString("Running under Windows NT" ENDLINE);

        // Get a handle to the kernel32 DLL
        //
        HINSTANCE hInstKernel32 = LoadLibrary("kernel32");
        if (!hInstKernel32)
        {
            Log.WriteString("LoadLibrary of kernel32 for a CancelIo entry point failed. Cannot continue." ENDLINE);
            return 1;
        }

        // Find the entry point for CancelIO so we can use it. This is done
        // dynamically because Windows 95/98 doesn't have a CancelIO entry
        // point. If it were done at load time, it would always fail on
        // Windows 95/98...even though we don't use it or depend on it in
        // that case.
        //
        fpCancelIo = (FCANCELIO *)GetProcAddress(hInstKernel32, "CancelIo");
        if (fpCancelIo == NULL)
        {
            Log.WriteString("GetProcAddress of _CancelIo failed. Cannot continue." ENDLINE);
            return 1;
        }
        fpGetProcessTimes = (FGETPROCESSTIMES *)GetProcAddress(hInstKernel32, "GetProcessTimes");
        if (fpGetProcessTimes == NULL)
        {
            Log.WriteString("GetProcAddress of GetProcessTimes failed. Cannot continue." ENDLINE);
            return 1;
        }
    }
    else
    {
        Log.WriteString("Running under Windows 95/98" ENDLINE);
    }

    // Initialize WinSock.
    //
    WORD wVersionRequested = MAKEWORD(2,2);
    WSADATA wsaData;
    if (WSAStartup(wVersionRequested, &wsaData) != 0)
    {
        Log.WriteString("ERROR: Could not initialize WinSock." ENDLINE);
        return 101;
    }

    if (  LOBYTE(wsaData.wVersion) != 2
       || HIBYTE(wsaData.wVersion) != 2)
    {
        // We can't run on this version of WinSock.
        //
        Log.tinyprintf("INFO: WinSock v%d.%d instead of v2.2." ENDLINE,
            LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
        //WSACleanup();
        //return 102;
    }
    if (!bCryptoAPI)
    {
        Log.WriteString("Crypto API unavailable.\r\n");
    }
#endif // WIN32

    mudstate.start_time.GetLocal();
    mudstate.cpu_count_from.GetUTC();
    pool_init(POOL_LBUF, LBUF_SIZE);
    pool_init(POOL_MBUF, MBUF_SIZE);
    pool_init(POOL_SBUF, SBUF_SIZE);
    pool_init(POOL_BOOL, sizeof(struct boolexp));

    pool_init(POOL_DESC, sizeof(DESC));
    pool_init(POOL_QENTRY, sizeof(BQUE));
    tcache_init();
    pcache_init();
    cf_init();
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
    init_rlimit();
#endif // HAVE_SETRLIMIT RLIMIT_NOFILE
    init_cmdtab();
    init_logout_cmdtab();
    init_flagtab();
    init_powertab();
    init_functab();
    init_attrtab();
    init_version();

    mudconf.config_file = StringClone(conffile);
    cf_read();

    fcache_init();
    helpindex_init();

#ifdef MEMORY_BASED
    db_free();
#else // MEMORY_BASED
    if (bMinDB)
    {
        RemoveFile(mudconf.game_dir);
        RemoveFile(mudconf.game_pag);
    }
    int ccPageFile = init_dbfile(mudconf.game_dir, mudconf.game_pag, mudconf.cache_pages);
    if (HF_OPEN_STATUS_ERROR == ccPageFile)
    {
        STARTLOG(LOG_ALWAYS, "INI", "LOAD");
        log_text("Couldn't load text database: ");
        log_text(mudconf.game_dir);
        log_text(mudconf.game_pag);
        ENDLOG;
        return 2;
    }
#endif // MEMORY_BASED

    mudstate.record_players = 0;

    if (bMinDB)
    {
        db_make_minimal();
    }
    else
    {
#ifdef MEMORY_BASED
        int ccInFile = load_game();
#else // MEMORY_BASED
        int ccInFile = load_game(ccPageFile);
#endif // MEMORY_BASED
        if (LOAD_GAME_NO_INPUT_DB == ccInFile)
        {
            // The input file didn't exist.
            //
#ifndef MEMORY_BASED
            if (HF_OPEN_STATUS_NEW == ccPageFile)
            {
                // Since the .db file didn't exist, and the .pag/.dir files
                // were newly created, just create a minimal DB.
                //
#endif // !MEMORY_BASED
                db_make_minimal();
                ccInFile = LOAD_GAME_SUCCESS;
#ifndef MEMORY_BASED
            }
#endif // !MEMORY_BASED
        }
        if (ccInFile != LOAD_GAME_SUCCESS)
        {
            STARTLOG(LOG_ALWAYS, "INI", "LOAD")
            log_text("Couldn't load: ");
            log_text(mudconf.indb);
            ENDLOG
            return 2;
        }
    }
    set_signals();
    Guest.StartUp();

    // Do a consistency check and set up the freelist
    //
    do_dbck(NOTHING, NOTHING, NOTHING, 0);

    // Reset all the hash stats
    //
    hashreset(&mudstate.command_htab);
    hashreset(&mudstate.channel_htab);
    hashreset(&mudstate.mail_htab);
    hashreset(&mudstate.logout_cmd_htab);
    hashreset(&mudstate.func_htab);
    hashreset(&mudstate.flags_htab);
    hashreset(&mudstate.attr_name_htab);
    hashreset(&mudstate.player_htab);
    hashreset(&mudstate.fwdlist_htab);
    hashreset(&mudstate.desc_htab);

    int i;
    for (i = 0; i < MAX_GLOBAL_REGS; i++)
    {
        mudstate.global_regs[i] = alloc_lbuf("main.global_reg");
        mudstate.glob_reg_len[i] = 0;
    }

    ValidateConfigurationDbrefs();
    process_preload();

#ifndef WIN32
    load_restart_db();
    if (!mudstate.restarting)
#endif // !WIN32
    {
        if (fclose(stdout) == 0)
        {
            DebugTotalFiles--;
        }
        if (fclose(stdin) == 0)
        {
            DebugTotalFiles--;
        }
    }
    SetupPorts(&nMainGamePorts, aMainGamePorts, &mudconf.ports);
    boot_slave(GOD, GOD, GOD, 0);

    // All intialization should be complete, allow the local
    // extensions to configure themselves.
    //
    local_startup();

    init_timer();

#ifdef WIN32
    if (platform == VER_PLATFORM_WIN32_NT)
    {
        process_output = process_outputNT;
        shovecharsNT(nMainGamePorts, aMainGamePorts);
    }
    else
    {
        process_output = process_output9x;
        shovechars9x(nMainGamePorts, aMainGamePorts);
    }
#else // WIN32
    shovechars(nMainGamePorts, aMainGamePorts);
#endif // WIN32

    close_sockets(false, "Going down - Bye");
    dump_database();

    // All shutdown, barring logfiles, should be done, shutdown the
    // local extensions.
    //
    local_shutdown();
    CLOSE;

#ifndef WIN32
    CleanUpSlaveSocket();
    CleanUpSlaveProcess();
#endif

    // Go ahead and explicitly free the memory for these things so
    // that it's easy to spot unintentional memory leaks.
    //
    for (i = 0; i < mudstate.nHelpDesc; i++)
    {
        helpindex_clean(i);
    }

    db_free();

#ifdef WIN32
    // critical section not needed any more
    if (platform == VER_PLATFORM_WIN32_NT)
    {
        DeleteCriticalSection(&csDescriptorList);
    }
    WSACleanup();
#endif // WIN32

    return 0;
}

#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
static void init_rlimit(void)
{
    struct rlimit *rlp;

    rlp = (struct rlimit *)alloc_lbuf("rlimit");

    if (getrlimit(RLIMIT_NOFILE, rlp))
    {
        log_perror("RLM", "FAIL", NULL, "getrlimit()");
        free_lbuf(rlp);
        return;
    }
    rlp->rlim_cur = rlp->rlim_max;
    if (setrlimit(RLIMIT_NOFILE, rlp))
    {
        log_perror("RLM", "FAIL", NULL, "setrlimit()");
    }
    free_lbuf(rlp);

}
#endif // HAVE_SETRLIMIT RLIMIT_NOFILE