mux2.0/
mux2.0/game/bin/
mux2.0/game/data/
mux2.0/src/tools/
// command.cpp - command parser and support routines.
// 
// $Id: command.cpp,v 1.22 2000/09/26 06:27:41 sdennis Exp $
//

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

#include "db.h"
#include "interface.h"
#include "mudconf.h"
#include "command.h"
#include "functions.h"
#include "match.h"
#include "attrs.h"
#include "flags.h"
#include "powers.h"
#include "alloc.h"
#include "vattr.h"
#include "mail.h"
#include "comsys.h"

extern void FDECL(list_cf_access, (dbref));
extern void FDECL(list_siteinfo, (dbref));
extern void logged_out0(dbref player, dbref cause, int key);
extern void logged_out1(dbref player, dbref cause, int key, char *arg);
extern void boot_slave(dbref, dbref, int);
extern void NDECL(vattr_clean_db);

#define SW_MULTIPLE   0x80000000    // This sw may be spec'd w/others.
#define SW_GOT_UNIQUE 0x40000000    // Already have a unique option.
#define SW_NOEVAL     0x20000000    // Don't parse args before calling
                                    // handler (typically controlled via
                                    // a switch).

// Switch tables for the various commands.
//
NAMETAB attrib_sw[] =
{
    {(char *)"access",  1,  CA_GOD,     ATTRIB_ACCESS},
    {(char *)"delete",  1,  CA_GOD,     ATTRIB_DELETE},
    {(char *)"rename",  1,  CA_GOD,     ATTRIB_RENAME},
    { NULL,         0,  0,      0}
};

NAMETAB boot_sw[] =
{
    {(char *)"port",    1,  CA_WIZARD,  BOOT_PORT|SW_MULTIPLE},
    {(char *)"quiet",   1,  CA_WIZARD,  BOOT_QUIET|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};

NAMETAB cemit_sw[] =
{
    {(char *)"noheader",    1,  CA_PUBLIC,  CEMIT_NOHEADER},
    { NULL,         0,  0,      0}
};

NAMETAB clone_sw[] =
{
    {(char *)"cost",    1,  CA_PUBLIC,  CLONE_SET_COST},
    {(char *)"inherit", 3,  CA_PUBLIC,  CLONE_INHERIT|SW_MULTIPLE},
    {(char *)"inventory",   3,  CA_PUBLIC,  CLONE_INVENTORY},
    {(char *)"location",    1,  CA_PUBLIC,  CLONE_LOCATION},
    {(char *)"parent",  2,  CA_PUBLIC,  CLONE_PARENT|SW_MULTIPLE},
    {(char *)"preserve",    2,  CA_WIZARD,  CLONE_PRESERVE|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};

NAMETAB clist_sw[] =
{
    {(char *)"full",        0,      CA_PUBLIC,      CLIST_FULL},
    { NULL,                 0,      0,              0}
};

NAMETAB cset_sw[] =
{
    {(char *)"anon",        1,      CA_PUBLIC,      CSET_SPOOF},
    {(char *)"list",        2,      CA_PUBLIC,      CSET_LIST},
    {(char *)"loud",        2,      CA_PUBLIC,      CSET_LOUD},
    {(char *)"mute",        1,      CA_PUBLIC,      CSET_QUIET},
    {(char *)"nospoof",     1,      CA_PUBLIC,      CSET_NOSPOOF},
    {(char *)"object",      1,      CA_PUBLIC,      CSET_OBJECT},
    {(char *)"private",     2,      CA_PUBLIC,      CSET_PRIVATE},
    {(char *)"public",      2,      CA_PUBLIC,      CSET_PUBLIC},
    {(char *)"quiet",       1,      CA_PUBLIC,      CSET_QUIET},
    {(char *)"spoof",       1,      CA_PUBLIC,      CSET_SPOOF},
    { NULL,                 0,      0,              0}
}; 

NAMETAB decomp_sw[] =
{
    {(char *)"dbref",   1,  CA_PUBLIC,  DECOMP_DBREF},
    { NULL,         0,  0,      0}
};

NAMETAB destroy_sw[] =
{
    {(char *)"override",    8,  CA_PUBLIC,  DEST_OVERRIDE},
    { NULL,         0,  0,      0}
};

NAMETAB dig_sw[] =
{
    {(char *)"teleport",    1,  CA_PUBLIC,  DIG_TELEPORT},
    { NULL,         0,  0,      0}
};

NAMETAB doing_sw[] =
{
    {(char *)"header",  1,  CA_PUBLIC,  DOING_HEADER},
    {(char *)"message", 1,  CA_PUBLIC,  DOING_MESSAGE},
    {(char *)"poll",    1,  CA_PUBLIC,  DOING_POLL},
    { NULL,         0,  0,      0}
};

NAMETAB dolist_sw[] =
{
    {(char *)"delimit",     1,      CA_PUBLIC,      DOLIST_DELIMIT},
    {(char *)"space",       1,      CA_PUBLIC,      DOLIST_SPACE},
    { NULL,                 0,      0,              0,}
};

NAMETAB drop_sw[] =
{
    {(char *)"quiet",   1,  CA_PUBLIC,  DROP_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB dump_sw[] =
{
    {(char *)"structure",   1,  CA_WIZARD,  DUMP_STRUCT|SW_MULTIPLE},
    {(char *)"text",        1,  CA_WIZARD,  DUMP_TEXT|SW_MULTIPLE},
    {(char *)"flatfile",    1,  CA_WIZARD,  DUMP_FLATFILE|SW_MULTIPLE},
    { NULL,                 0,  0,          0}
};

NAMETAB emit_sw[] =
{
    {(char *)"here",    2,  CA_PUBLIC,  SAY_HERE|SW_MULTIPLE},
    {(char *)"html",    2,  CA_PUBLIC,  SAY_HTML|SW_MULTIPLE},
    {(char *)"room",    1,  CA_PUBLIC,  SAY_ROOM|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};

NAMETAB enter_sw[] =
{
    {(char *)"quiet",   1,  CA_PUBLIC,  MOVE_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB examine_sw[] =
{
    {(char *)"brief",   1,  CA_PUBLIC,  EXAM_BRIEF},
    {(char *)"debug",   1,  CA_WIZARD,  EXAM_DEBUG},
    {(char *)"full",    1,  CA_PUBLIC,  EXAM_LONG},
    {(char *)"parent",  1,  CA_PUBLIC,  EXAM_PARENT},
    { NULL,         0,  0,      0}
};

NAMETAB femit_sw[] =
{
    {(char *)"here",    1,  CA_PUBLIC,  PEMIT_HERE|SW_MULTIPLE},
    {(char *)"room",    1,  CA_PUBLIC,  PEMIT_ROOM|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};

NAMETAB fixdb_sw[] =
{
    // {(char *)"add_pname",1,  CA_GOD,     FIXDB_ADD_PN},
    {(char *)"contents",    1,  CA_GOD,     FIXDB_CON},
    {(char *)"exits",   1,  CA_GOD,     FIXDB_EXITS},
    {(char *)"location",    1,  CA_GOD,     FIXDB_LOC},
    {(char *)"next",    1,  CA_GOD,     FIXDB_NEXT},
    {(char *)"owner",   1,  CA_GOD,     FIXDB_OWNER},
    {(char *)"pennies", 1,  CA_GOD,     FIXDB_PENNIES},
    {(char *)"rename",  1,  CA_GOD,     FIXDB_NAME},
    // {(char *)"rm_pname", 1,  CA_GOD,     FIXDB_DEL_PN},
    { NULL,         0,  0,      0}
};

NAMETAB fpose_sw[] =
{
    {(char *)"default", 1,  CA_PUBLIC,  0},
    {(char *)"nospace", 1,  CA_PUBLIC,  SAY_NOSPACE},
    { NULL,         0,  0,      0}
};

NAMETAB function_sw[] =
{
    {(char *)"list",        1,  CA_WIZARD,  FN_LIST},
    {(char *)"preserve",    3,  CA_WIZARD,  FN_PRES},
    {(char *)"privileged",  3,  CA_WIZARD,  FN_PRIV},
    { NULL,                 0,          0,        0}
};

NAMETAB get_sw[] =
{
    {(char *)"quiet",   1,  CA_PUBLIC,  GET_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB give_sw[] =
{
    {(char *)"quiet",   1,  CA_WIZARD,  GIVE_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB goto_sw[] =
{
    {(char *)"quiet",   1,  CA_PUBLIC,  MOVE_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB halt_sw[] =
{
    {(char *)"all",     1,  CA_PUBLIC,  HALT_ALL},
    { NULL,         0,  0,      0}
};

NAMETAB leave_sw[] =
{
    {(char *)"quiet",   1,  CA_PUBLIC,  MOVE_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB listmotd_sw[] =
{
    {(char *)"brief",   1,  CA_WIZARD,  MOTD_BRIEF},
    { NULL,         0,  0,      0}
};

NAMETAB lock_sw[] =
{
    {(char *)"defaultlock", 1,  CA_PUBLIC,  A_LOCK},
    {(char *)"droplock",    1,  CA_PUBLIC,  A_LDROP},
    {(char *)"enterlock",   1,  CA_PUBLIC,  A_LENTER},
    {(char *)"givelock",    1,  CA_PUBLIC,  A_LGIVE},
    {(char *)"leavelock",   2,  CA_PUBLIC,  A_LLEAVE},
    {(char *)"linklock",    2,  CA_PUBLIC,  A_LLINK},
    {(char *)"pagelock",    3,  CA_PUBLIC,  A_LPAGE},
    {(char *)"parentlock",  3,  CA_PUBLIC,  A_LPARENT},
    {(char *)"receivelock", 1,  CA_PUBLIC,  A_LRECEIVE},
    {(char *)"teloutlock",  2,  CA_PUBLIC,  A_LTELOUT},
    {(char *)"tportlock",   2,  CA_PUBLIC,  A_LTPORT},
    {(char *)"uselock", 1,  CA_PUBLIC,  A_LUSE},
    {(char *)"userlock",    4,  CA_PUBLIC,  A_LUSER},
    {(char *)"speechlock",  1,  CA_PUBLIC,  A_LSPEECH},
    { NULL,         0,  0,      0}
};

NAMETAB look_sw[] =
{
    {(char *)"outside",     1,      CA_PUBLIC,      LOOK_OUTSIDE},
    { NULL,                 0,      0,              0}
};

NAMETAB mail_sw[] =
{
    {(char *)"abort",       0,      CA_PUBLIC,      MAIL_ABORT},
    {(char *)"alias",       1,      CA_PUBLIC,      MAIL_ALIAS},
    {(char *)"alist",       1,      CA_PUBLIC,      MAIL_ALIST},
    {(char *)"cc",          2,      CA_PUBLIC,      MAIL_CC},
    {(char *)"clear",       1,      CA_PUBLIC,      MAIL_CLEAR},
    {(char *)"debug",       1,      CA_PUBLIC,      MAIL_DEBUG},
    {(char *)"dstats",      1,      CA_PUBLIC,      MAIL_DSTATS},
    {(char *)"edit",        2,      CA_PUBLIC,      MAIL_EDIT},
    {(char *)"file",        1,      CA_PUBLIC,      MAIL_FILE},
    {(char *)"folder",      1,      CA_PUBLIC,      MAIL_FOLDER},
    {(char *)"forward",     2,      CA_PUBLIC,      MAIL_FORWARD},
    {(char *)"fstats",      1,      CA_PUBLIC,      MAIL_FSTATS},
    {(char *)"fwd",         2,      CA_PUBLIC,      MAIL_FORWARD},
    {(char *)"list",        1,      CA_PUBLIC,      MAIL_LIST},
    {(char *)"nuke",        1,      CA_PUBLIC,      MAIL_NUKE},
    {(char *)"proof",       1,      CA_PUBLIC,      MAIL_PROOF},
    {(char *)"purge",       1,      CA_PUBLIC,      MAIL_PURGE},
    {(char *)"quick",       0,      CA_PUBLIC,      MAIL_QUICK},
    {(char *)"quote",       3,      CA_PUBLIC,      MAIL_QUOTE|SW_MULTIPLE},
    {(char *)"read",        1,      CA_PUBLIC,      MAIL_READ},
    {(char *)"reply",       3,      CA_PUBLIC,      MAIL_REPLY},
    {(char *)"replyall",    6,      CA_PUBLIC,      MAIL_REPLYALL},
    {(char *)"retract",     2,      CA_PUBLIC,      MAIL_RETRACT},
    {(char *)"review",      2,      CA_PUBLIC,      MAIL_REVIEW},
    {(char *)"safe",        2,      CA_PUBLIC,      MAIL_SAFE},
    {(char *)"send",        0,      CA_PUBLIC,      MAIL_SEND},
    {(char *)"stats",       1,      CA_PUBLIC,      MAIL_STATS},
    {(char *)"tag",         1,      CA_PUBLIC,      MAIL_TAG},
    {(char *)"unclear",     1,      CA_PUBLIC,      MAIL_UNCLEAR},
    {(char *)"untag",       1,      CA_PUBLIC,      MAIL_UNTAG},
    {(char *)"urgent",      1,      CA_PUBLIC,      MAIL_URGENT},
    { NULL,                 0,              0,      0}
};

NAMETAB malias_sw[] =
{
    {(char *)"desc",        1,      CA_PUBLIC,      MALIAS_DESC},
    {(char *)"chown",       1,      CA_PUBLIC,      MALIAS_CHOWN},
    {(char *)"add",         1,      CA_PUBLIC,      MALIAS_ADD},
    {(char *)"remove",      1,      CA_PUBLIC,      MALIAS_REMOVE},
    {(char *)"delete",      1,      CA_PUBLIC,      MALIAS_DELETE},
    {(char *)"rename",      1,      CA_PUBLIC,      MALIAS_RENAME},
    {(char *)"list",        1,      CA_PUBLIC,      MALIAS_LIST},
    {(char *)"status",      1,      CA_PUBLIC,      MALIAS_STATUS},
    { NULL,                 0,              0,      0}
};

NAMETAB mark_sw[] =
{
    {(char *)"set",     1,  CA_PUBLIC,  MARK_SET},
    {(char *)"clear",   1,  CA_PUBLIC,  MARK_CLEAR},
    { NULL,         0,  0,      0}
};

NAMETAB markall_sw[] =
{
    {(char *)"set",     1,  CA_PUBLIC,  MARK_SET},
    {(char *)"clear",   1,  CA_PUBLIC,  MARK_CLEAR},
    { NULL,         0,  0,      0}
};

NAMETAB motd_sw[] =
{
    {(char *)"brief",   1,  CA_WIZARD,  MOTD_BRIEF|SW_MULTIPLE},
    {(char *)"connect", 1,  CA_WIZARD,  MOTD_ALL},
    {(char *)"down",    1,  CA_WIZARD,  MOTD_DOWN},
    {(char *)"full",    1,  CA_WIZARD,  MOTD_FULL},
    {(char *)"list",    1,  CA_PUBLIC,  MOTD_LIST},
    {(char *)"wizard",  1,  CA_WIZARD,  MOTD_WIZ},
    { NULL,         0,  0,      0}
};

NAMETAB notify_sw[] =
{
    {(char *)"all",     1,  CA_PUBLIC,  NFY_NFYALL},
    {(char *)"first",   1,  CA_PUBLIC,  NFY_NFY},
    { NULL,         0,  0,      0}
};

NAMETAB open_sw[] =
{
    {(char *)"inventory",   1,  CA_PUBLIC,  OPEN_INVENTORY},
    {(char *)"location",    1,  CA_PUBLIC,  OPEN_LOCATION},
    { NULL,         0,  0,      0}
};

NAMETAB pemit_sw[] =
{
    {(char *)"contents", 1,  CA_PUBLIC,  PEMIT_CONTENTS|SW_MULTIPLE},
    {(char *)"html",     1,  CA_PUBLIC,  PEMIT_HTML|SW_MULTIPLE},
    {(char *)"list",     1,  CA_PUBLIC,  PEMIT_LIST|SW_MULTIPLE},
    {(char *)"noeval",   1,  CA_PUBLIC,  SW_NOEVAL|SW_MULTIPLE},
    {(char *)"object",   1,  CA_PUBLIC,  0},
    {(char *)"silent",   1,  CA_PUBLIC,  0},
    { NULL,              0,          0,  0}
};

NAMETAB pose_sw[] =
{
    {(char *)"default", 1,  CA_PUBLIC,  0},
    {(char *)"nospace", 1,  CA_PUBLIC,  SAY_NOSPACE},
    { NULL,         0,  0,      0}
};

NAMETAB ps_sw[] =
{
    {(char *)"all",     1,  CA_PUBLIC,  PS_ALL|SW_MULTIPLE},
    {(char *)"brief",   1,  CA_PUBLIC,  PS_BRIEF},
    {(char *)"long",    1,  CA_PUBLIC,  PS_LONG},
    {(char *)"summary", 1,  CA_PUBLIC,  PS_SUMM},
    { NULL,         0,  0,      0}
};

NAMETAB quota_sw[] =
{
    {(char *)"all",     1,  CA_GOD,     QUOTA_ALL|SW_MULTIPLE},
    {(char *)"fix",     1,  CA_WIZARD,  QUOTA_FIX},
    {(char *)"remaining",   1,  CA_WIZARD,  QUOTA_REM|SW_MULTIPLE},
    {(char *)"set",     1,  CA_WIZARD,  QUOTA_SET},
    {(char *)"total",   1,  CA_WIZARD,  QUOTA_TOT|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};

NAMETAB set_sw[] =
{
    {(char *)"quiet",   1,  CA_PUBLIC,  SET_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB stats_sw[] =
{
    {(char *)"all",     1,  CA_PUBLIC,  STAT_ALL},
    {(char *)"me",      1,  CA_PUBLIC,  STAT_ME},
    {(char *)"player",  1,  CA_PUBLIC,  STAT_PLAYER},
    { NULL,         0,  0,      0}
};

NAMETAB sweep_sw[] =
{
    {(char *)"commands",    3,  CA_PUBLIC,  SWEEP_COMMANDS|SW_MULTIPLE},
    {(char *)"connected",   3,  CA_PUBLIC,  SWEEP_CONNECT|SW_MULTIPLE},
    {(char *)"exits",   1,  CA_PUBLIC,  SWEEP_EXITS|SW_MULTIPLE},
    {(char *)"here",    1,  CA_PUBLIC,  SWEEP_HERE|SW_MULTIPLE},
    {(char *)"inventory",   1,  CA_PUBLIC,  SWEEP_ME|SW_MULTIPLE},
    {(char *)"listeners",   1,  CA_PUBLIC,  SWEEP_LISTEN|SW_MULTIPLE},
    {(char *)"players", 1,  CA_PUBLIC,  SWEEP_PLAYER|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};

NAMETAB switch_sw[] =
{
    {(char *)"all",     1,  CA_PUBLIC,  SWITCH_ANY},
    {(char *)"default", 1,  CA_PUBLIC,  SWITCH_DEFAULT},
    {(char *)"first",   1,  CA_PUBLIC,  SWITCH_ONE},
    { NULL,         0,  0,      0}
};

NAMETAB teleport_sw[] =
{
    {(char *)"loud",    1,  CA_PUBLIC,  TELEPORT_DEFAULT},
    {(char *)"quiet",   1,  CA_PUBLIC,  TELEPORT_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB timecheck_sw[] =
{
    {(char *)"log",     1,  CA_WIZARD,  TIMECHK_LOG | SW_MULTIPLE},
    {(char *)"reset",   1,  CA_WIZARD,  TIMECHK_RESET | SW_MULTIPLE},
    {(char *)"screen",  1,  CA_WIZARD,  TIMECHK_SCREEN | SW_MULTIPLE},
    { NULL,             0,  0,          0}
};

NAMETAB toad_sw[] =
{
    {(char *)"no_chown",    1,  CA_WIZARD,  TOAD_NO_CHOWN|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};

NAMETAB trig_sw[] =
{
    {(char *)"quiet",   1,  CA_PUBLIC,  TRIG_QUIET},
    { NULL,         0,  0,      0}
};

NAMETAB wall_sw[] =
{
    {(char *)"emit",    1,  CA_ANNOUNCE,    SAY_WALLEMIT},
    {(char *)"no_prefix",   1,  CA_ANNOUNCE,    SAY_NOTAG|SW_MULTIPLE},
    {(char *)"pose",    1,  CA_ANNOUNCE,    SAY_WALLPOSE},
    {(char *)"wizard",  1,  CA_ANNOUNCE,    SAY_WIZSHOUT|SW_MULTIPLE},
    {(char *)"admin",   1,  CA_ADMIN,   SAY_ADMINSHOUT},
    { NULL,         0,  0,      0}
};

NAMETAB warp_sw[] =
{
    {(char *)"check",   1,  CA_WIZARD,  TWARP_CLEAN|SW_MULTIPLE},
    {(char *)"dump",    1,  CA_WIZARD,  TWARP_DUMP|SW_MULTIPLE},
    {(char *)"idle",    1,  CA_WIZARD,  TWARP_IDLE|SW_MULTIPLE},
    {(char *)"queue",   1,  CA_WIZARD,  TWARP_QUEUE|SW_MULTIPLE},
    {(char *)"events",  1,  CA_WIZARD,  TWARP_EVENTS|SW_MULTIPLE},
    { NULL,         0,  0,      0}
};


/* ---------------------------------------------------------------------------
 * Command table: Definitions for builtin commands, used to build the command
 * hash table.
 *
 * Format:  Name        Switches    Permissions Needed
 *  Key (if any)    Calling Seq         Handler
 */
CMDENT_NO_ARG command_table_no_arg[] =
{
    {(char *)"@@",            NULL,       0,  0,      CS_NO_ARGS,         do_comment},
    {(char *)"@clist",        clist_sw,   CA_NO_SLAVE,        0,              CS_NO_ARGS,                     do_chanlist},
    {(char *)"@dbck",         NULL,       CA_WIZARD,    0,      CS_NO_ARGS,         do_dbck},
    {(char *)"@dbclean",      NULL,       CA_GOD,       0,      CS_NO_ARGS,         do_dbclean},
    {(char *)"@dump",         dump_sw,    CA_WIZARD,    0,      CS_NO_ARGS,         do_dump},
    {(char *)"@mark_all",     markall_sw, CA_WIZARD,    MARK_SET,   CS_NO_ARGS,         do_markall},
    {(char *)"@readcache",    NULL,       CA_WIZARD,    0,      CS_NO_ARGS,         do_readcache},
    {(char *)"@restart",      NULL,       CA_WIZARD,    0,      CS_NO_ARGS,         do_restart},
#ifndef WIN32
    {(char *)"@startslave",   NULL,       CA_WIZARD,    0,      CS_NO_ARGS,         boot_slave},
#endif
    {(char *)"@timecheck",    timecheck_sw, CA_WIZARD,  0,        CS_NO_ARGS,       do_timecheck},
    {(char *)"comlist",       NULL,       CA_NO_SLAVE,        0,              CS_NO_ARGS,                     do_comlist},
    {(char *)"clearcom",      NULL,       CA_NO_SLAVE,        0,              CS_NO_ARGS,                     do_clearcom},
    {(char *)"inventory",     NULL,       0,    LOOK_INVENTORY, CS_NO_ARGS,         do_inventory},
    {(char *)"leave",         leave_sw,   CA_LOCATION,    0,      CS_NO_ARGS|CS_INTERP,       do_leave},
    {(char *)"score",         NULL,       0,    LOOK_SCORE, CS_NO_ARGS,         do_score},
    {(char *)"version",       NULL,       0,    0,      CS_NO_ARGS,         do_version},
    {(char *)"quit",          NULL,       CA_PUBLIC,    CMD_QUIT,   CS_NO_ARGS,         logged_out0},
    {(char *)"logout",        NULL,       CA_PUBLIC,    CMD_LOGOUT, CS_NO_ARGS,         logged_out0},
    {(char *)"report",        NULL,       0,    0,      CS_NO_ARGS,   do_report},
    {(char *)NULL,            NULL,       0,     0,      0,              NULL}
};

CMDENT_ONE_ARG command_table_one_arg[] =
{
    {(char *)"+help",         NULL,       0,    HELP_PLUSHELP,  CS_ONE_ARG,         do_help},
    {(char *)"+shelp",        NULL,       CA_STAFF,    HELP_STAFFHELP, CS_ONE_ARG,         do_help},
    {(char *)"@boot",         boot_sw,    CA_NO_GUEST|CA_NO_SLAVE,    0,      CS_ONE_ARG|CS_INTERP,       do_boot},
    {(char *)"@ccreate",      NULL,       CA_NO_SLAVE|CA_NO_GUEST,        0,               CS_ONE_ARG,                    do_createchannel},
    {(char *)"@cdestroy",     NULL,       CA_NO_SLAVE|CA_NO_GUEST,        0,               CS_ONE_ARG,                    do_destroychannel},
    {(char *)"@cut",          NULL,       CA_WIZARD|CA_LOCATION,  0,      CS_ONE_ARG|CS_INTERP,       do_cut},
    {(char *)"@cwho",         NULL,       CA_NO_SLAVE,        0,              CS_ONE_ARG,                     do_channelwho},
    {(char *)"@destroy",      destroy_sw, CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,    DEST_ONE,   CS_ONE_ARG|CS_INTERP,       do_destroy},
    //{(char *)"@destroyall",   NULL,       CA_WIZARD|CA_GBL_BUILD,     DEST_ALL,   CS_ONE_ARG,         do_destroy},
    {(char *)"@disable",      NULL,       CA_WIZARD,    GLOB_DISABLE,   CS_ONE_ARG,         do_global},
    {(char *)"@doing",        doing_sw,   CA_PUBLIC,    0,      CS_ONE_ARG,         do_doing},
    {(char *)"@emit",         emit_sw,    CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,     SAY_EMIT,   CS_ONE_ARG|CS_INTERP,       do_say},
    {(char *)"@enable",       NULL,       CA_WIZARD,     GLOB_ENABLE,    CS_ONE_ARG,         do_global},
    {(char *)"@entrances",    NULL,       CA_NO_GUEST,     0,      CS_ONE_ARG|CS_INTERP,   do_entrances},
    {(char *)"@find",         NULL,       0,    0,      CS_ONE_ARG|CS_INTERP,       do_find},
    {(char *)"@halt",         halt_sw,    CA_NO_SLAVE,    0,      CS_ONE_ARG|CS_INTERP,       do_halt},
    {(char *)"@kick",         NULL,       CA_WIZARD,    QUEUE_KICK, CS_ONE_ARG|CS_INTERP,       do_queue},
    {(char *)"@last",         NULL,       CA_NO_GUEST,    0,      CS_ONE_ARG|CS_INTERP,       do_last},
    {(char *)"@list",         NULL,       0,    0,      CS_ONE_ARG|CS_INTERP,       do_list},
    {(char *)"@listcommands", NULL,       CA_GOD,    0,      CS_ONE_ARG,         do_listcommands},
    {(char *)"@list_file",    NULL,       CA_WIZARD,    0,      CS_ONE_ARG|CS_INTERP,       do_list_file},
    {(char *)"@listmotd",     listmotd_sw,0,    MOTD_LIST,  CS_ONE_ARG,         do_motd},
    {(char *)"@mark",         mark_sw,    CA_WIZARD,    SRCH_MARK,  CS_ONE_ARG|CS_NOINTERP,     do_search},
    {(char *)"@motd",         motd_sw,    CA_WIZARD,    0,      CS_ONE_ARG,         do_motd},
    {(char *)"@nemit",        emit_sw,    CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE, SAY_EMIT, CS_ONE_ARG|CS_UNPARSE|CS_NOSQUISH, do_say},
    {(char *)"@poor",         NULL,       CA_GOD,    0,      CS_ONE_ARG|CS_INTERP,       do_poor},
    {(char *)"@ps",           ps_sw,      0,    0,      CS_ONE_ARG|CS_INTERP,       do_ps},
    {(char *)"@quitprogram",  NULL,       CA_PUBLIC,    0,      CS_ONE_ARG|CS_INTERP,       do_quitprog},
    {(char *)"@search",       NULL,       0,    SRCH_SEARCH,    CS_ONE_ARG|CS_NOINTERP,     do_search},
    {(char *)"@shutdown",     NULL,       CA_WIZARD,    0,      CS_ONE_ARG,         do_shutdown},
    {(char *)"@stats",        stats_sw,   0,    0,      CS_ONE_ARG|CS_INTERP,       do_stats},
    {(char *)"@sweep",        sweep_sw,   0,    0,      CS_ONE_ARG,         do_sweep},
    {(char *)"@timewarp",     warp_sw,    CA_WIZARD,    0,      CS_ONE_ARG|CS_INTERP,       do_timewarp},
    {(char *)"@unlink",       NULL,       CA_NO_SLAVE|CA_GBL_BUILD,    0,      CS_ONE_ARG|CS_INTERP,       do_unlink},
    {(char *)"@unlock",       lock_sw,    CA_NO_SLAVE,    0,      CS_ONE_ARG|CS_INTERP,       do_unlock},
    {(char *)"@wall",         wall_sw,    CA_ANNOUNCE,    SAY_SHOUT,  CS_ONE_ARG|CS_INTERP,       do_say},
    {(char *)"@wipe",         wall_sw,    CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,    0,      CS_ONE_ARG|CS_INTERP,       do_wipe},
    {(char *)"allcom",        NULL,       CA_NO_SLAVE,        0,              CS_ONE_ARG,                     do_allcom},
    {(char *)"delcom",        NULL,       CA_NO_SLAVE,        0,              CS_ONE_ARG,                     do_delcom},
    {(char *)"drop",          drop_sw,    CA_NO_SLAVE|CA_CONTENTS|CA_LOCATION|CA_NO_GUEST,    0,      CS_ONE_ARG|CS_INTERP,       do_drop},
    {(char *)"enter",         enter_sw,   CA_LOCATION,    0,      CS_ONE_ARG|CS_INTERP,       do_enter},
    {(char *)"examine",       examine_sw, 0,    0,      CS_ONE_ARG|CS_INTERP,       do_examine},
    {(char *)"get",           get_sw,     CA_LOCATION|CA_NO_GUEST,    0,      CS_ONE_ARG|CS_INTERP,       do_get},
    {(char *)"goto",          goto_sw,    CA_LOCATION,    0,      CS_ONE_ARG|CS_INTERP,       do_move},
    {(char *)"help",          NULL,       0,    HELP_HELP,  CS_ONE_ARG,         do_help},
    {(char *)"look",          look_sw,    CA_LOCATION,    LOOK_LOOK,  CS_ONE_ARG|CS_INTERP,       do_look},
    {(char *)"news",          NULL,       0,    HELP_NEWS,  CS_ONE_ARG,         do_help},
    {(char *)"outputprefix",  NULL,       CA_PUBLIC,    CMD_PREFIX, CS_ONE_ARG,         logged_out1},
    {(char *)"outputsuffix",  NULL,       CA_PUBLIC,    CMD_SUFFIX, CS_ONE_ARG,         logged_out1},
    {(char *)"pose",          pose_sw,    CA_LOCATION|CA_NO_SLAVE,    SAY_POSE,   CS_ONE_ARG|CS_INTERP,       do_say},
    {(char *)"say",           NULL,       CA_LOCATION|CA_NO_SLAVE,    SAY_SAY,    CS_ONE_ARG|CS_INTERP,       do_say},
    {(char *)"session",       NULL,       CA_PUBLIC,    CMD_SESSION,    CS_ONE_ARG,         logged_out1},
    {(char *)"think",         NULL,       CA_NO_SLAVE,        0,              CS_ONE_ARG,                     do_think},
    {(char *)"use",           NULL,       CA_NO_SLAVE|CA_GBL_INTERP,    0,      CS_ONE_ARG|CS_INTERP,       do_use},
    {(char *)"wizhelp",       NULL,       CA_WIZARD,    HELP_WIZHELP,   CS_ONE_ARG,         do_help},
    {(char *)"wiznews",       NULL,       CA_WIZARD,        HELP_WIZNEWS,   CS_ONE_ARG,                     do_help},
    {(char *)"doing",         NULL,       CA_PUBLIC,    CMD_DOING,  CS_ONE_ARG,         logged_out1},
    {(char *)"who",           NULL,       CA_PUBLIC,    CMD_WHO,    CS_ONE_ARG,         logged_out1},
    {(char *)"puebloclient",  NULL,       CA_PUBLIC,      CMD_PUEBLOCLIENT,CS_ONE_ARG,                    logged_out1},
    {(char *)"\\",            NULL,       CA_NO_GUEST|CA_LOCATION|CF_DARK|CA_NO_SLAVE,    SAY_PREFIX, CS_ONE_ARG|CS_INTERP,       do_say},
    {(char *)":",             NULL,       CA_LOCATION|CF_DARK|CA_NO_SLAVE,    SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, do_say},
    {(char *)";",             NULL,       CA_LOCATION|CF_DARK|CA_NO_SLAVE,    SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, do_say},
    {(char *)"\"",            NULL,       CA_LOCATION|CF_DARK|CA_NO_SLAVE,     SAY_PREFIX, CS_ONE_ARG|CS_INTERP|CS_LEADIN, do_say},
    {(char *)"-",             NULL,       CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,     0,      CS_ONE_ARG|CS_LEADIN,       do_postpend},
    {(char *)"~",             NULL,       CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,     0,      CS_ONE_ARG|CS_LEADIN,       do_prepend},
    {(char *)NULL,            NULL,       0,     0,      0,              NULL}
};

CMDENT_ONE_ARG_CMDARG command_table_one_arg_cmdarg[] =
{
    {(char *)"@apply_marked", NULL,       CA_WIZARD|CA_GBL_INTERP,    0,      CS_ONE_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND,   do_apply_marked},
    {(char *)"#",             NULL,       CA_NO_SLAVE|CA_GBL_INTERP|CF_DARK,    0,      CS_ONE_ARG|CS_INTERP|CS_CMDARG, do_force_prefixed},
    {(char *)NULL,            NULL,       0,     0,      0,              NULL}
};

CMDENT_TWO_ARG command_table_two_arg[] =
{
    {(char *)"@addcommand",   NULL,       CA_GOD,                                0,         CS_TWO_ARG,           do_addcommand},
    {(char *)"@admin",        NULL,       CA_WIZARD,                             0,         CS_TWO_ARG|CS_INTERP, do_admin},
    {(char *)"@alias",        NULL,       CA_NO_GUEST|CA_NO_SLAVE,               0,         CS_TWO_ARG,           do_alias},
    {(char *)"@attribute",    attrib_sw,  CA_GOD,                                0,         CS_TWO_ARG|CS_INTERP, do_attribute},
    {(char *)"@cboot",        NULL,       CA_NO_SLAVE|CA_NO_GUEST,               0,         CS_TWO_ARG,           do_chboot},
    {(char *)"@ccharge",      NULL,       CA_NO_SLAVE|CA_NO_GUEST,               1,         CS_TWO_ARG,           do_editchannel},
    {(char *)"@cchown",       NULL,       CA_NO_SLAVE|CA_NO_GUEST,               0,         CS_TWO_ARG,           do_editchannel},
    {(char *)"@cemit",        cemit_sw,   CA_NO_SLAVE|CA_NO_GUEST,               0,         CS_TWO_ARG,           do_cemit},
    {(char *)"@chown",        NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,  CHOWN_ONE, CS_TWO_ARG|CS_INTERP, do_chown},
    {(char *)"@chownall",     NULL,       CA_WIZARD|CA_GBL_BUILD,                CHOWN_ALL, CS_TWO_ARG|CS_INTERP, do_chownall},
    {(char *)"@chzone",       NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,  0,         CS_TWO_ARG|CS_INTERP, do_chzone},
    {(char *)"@clone",        clone_sw,   CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST,   0,      CS_TWO_ARG|CS_INTERP,       do_clone},
    {(char *)"@coflags",      NULL,       CA_NO_SLAVE,        4,              CS_TWO_ARG,                     do_editchannel},
    {(char *)"@cpflags",      NULL,       CA_NO_SLAVE,        3,              CS_TWO_ARG,                     do_editchannel},
    {(char *)"@create",       NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST,   0,      CS_TWO_ARG|CS_INTERP,       do_create},
    {(char *)"@cset",         cset_sw,    CA_NO_SLAVE,        0,              CS_TWO_ARG|CS_INTERP,           do_chopen},
    {(char *)"@decompile",    decomp_sw,  0,    0,      CS_TWO_ARG|CS_INTERP,       do_decomp},
    {(char *)"@delcommand",   NULL,       CA_GOD,    0,      CS_TWO_ARG,         do_delcommand},
    {(char *)"@drain",        NULL,       CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST,    NFY_DRAIN,  CS_TWO_ARG,         do_notify},
    {(char *)"@femit",        femit_sw,   CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,    PEMIT_FEMIT,    CS_TWO_ARG|CS_INTERP,       do_pemit},
    {(char *)"@fixdb",        fixdb_sw,   CA_GOD,    0,      CS_TWO_ARG|CS_INTERP,       do_fixdb},
    {(char *)"@fpose",        fpose_sw,   CA_LOCATION|CA_NO_SLAVE,    PEMIT_FPOSE,    CS_TWO_ARG|CS_INTERP,       do_pemit},
    {(char *)"@fsay",         NULL,       CA_LOCATION|CA_NO_SLAVE,    PEMIT_FSAY, CS_TWO_ARG|CS_INTERP,       do_pemit},
    {(char *)"@function",     function_sw,CA_GOD,    0,      CS_TWO_ARG|CS_INTERP,       do_function},
    {(char *)"@link",         NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,    0,      CS_TWO_ARG|CS_INTERP,       do_link},
    {(char *)"@lock",         lock_sw,    CA_NO_SLAVE,    0,      CS_TWO_ARG|CS_INTERP,       do_lock},
    {(char *)"@log",          NULL,       CA_WIZARD,      0,      CS_TWO_ARG, do_log},
    {(char *)"@mail",         mail_sw,    CA_NO_SLAVE|CA_NO_GUEST|CA_PLAYER,        0,              CS_TWO_ARG|CS_INTERP,          do_mail},
    {(char *)"@malias",       malias_sw,  CA_NO_SLAVE|CA_NO_GUEST,        0,              CS_TWO_ARG|CS_INTERP,          do_malias},
    {(char *)"@name",         NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,    0,      CS_TWO_ARG|CS_INTERP,       do_name},
    {(char *)"@newpassword",  NULL,       CA_WIZARD,    PASS_ANY,   CS_TWO_ARG,         do_newpassword},
    {(char *)"@notify",       notify_sw,  CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST,    0,      CS_TWO_ARG,         do_notify},
    {(char *)"@oemit",        NULL,       CA_LOCATION|CA_NO_GUEST|CA_NO_SLAVE,    PEMIT_OEMIT,    CS_TWO_ARG|CS_INTERP,       do_pemit},
    {(char *)"@parent",       NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,    0,      CS_TWO_ARG,         do_parent},
    {(char *)"@password",     NULL,       CA_NO_GUEST,    PASS_MINE,  CS_TWO_ARG,         do_password},
    {(char *)"@pcreate",      NULL,       CA_WIZARD|CA_GBL_BUILD,    PCRE_PLAYER,    CS_TWO_ARG,         do_pcreate},
    {(char *)"@pemit",        pemit_sw,   CA_NO_GUEST|CA_NO_SLAVE,    PEMIT_PEMIT,    CS_TWO_ARG|CS_INTERP,       do_pemit},
    {(char *)"@npemit",       pemit_sw,   CA_NO_GUEST|CA_NO_SLAVE,    PEMIT_PEMIT,    CS_TWO_ARG|CS_UNPARSE|CS_NOSQUISH,      do_pemit},
    {(char *)"@power",        NULL,       0,    0,      CS_TWO_ARG,         do_power},
    {(char *)"@program",      NULL,       CA_PUBLIC,    0,      CS_TWO_ARG|CS_INTERP,           do_prog},
    {(char *)"@quota",        quota_sw,   0,    0,      CS_TWO_ARG|CS_INTERP,       do_quota},
    {(char *)"@robot",        NULL,       CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST|CA_PLAYER,    PCRE_ROBOT, CS_TWO_ARG,         do_pcreate},
    {(char *)"@set",          set_sw,     CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,    0,      CS_TWO_ARG, do_set},
    {(char *)"@teleport",     teleport_sw,CA_NO_GUEST,    TELEPORT_DEFAULT, CS_TWO_ARG|CS_INTERP,     do_teleport},
    {(char *)"@toad",         toad_sw,    CA_WIZARD,    0,      CS_TWO_ARG|CS_INTERP,       do_toad},
    {(char *)"addcom",        NULL,       CA_NO_SLAVE,        0,              CS_TWO_ARG,                     do_addcom},
    {(char *)"comtitle",      NULL,       CA_NO_SLAVE,        0,              CS_TWO_ARG,                    do_comtitle},
    {(char *)"give",          give_sw,    CA_LOCATION|CA_NO_GUEST,    0,      CS_TWO_ARG|CS_INTERP,       do_give},
    {(char *)"kill",          NULL,       CA_NO_GUEST|CA_NO_SLAVE,    KILL_KILL,  CS_TWO_ARG|CS_INTERP,       do_kill},
    {(char *)"page",          NULL,       CA_NO_SLAVE,    0,      CS_TWO_ARG|CS_INTERP,       do_page},
    {(char *)"slay",          NULL,       CA_WIZARD,    KILL_SLAY,  CS_TWO_ARG|CS_INTERP,       do_kill},
    {(char *)"whisper",       NULL,       CA_LOCATION|CA_NO_SLAVE,    PEMIT_WHISPER,  CS_TWO_ARG|CS_INTERP,       do_pemit},
    {(char *)"&",             NULL,       CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,     0,      CS_TWO_ARG|CS_LEADIN,       do_setvattr},
    {(char *)NULL,            NULL,       0,     0,      0,              NULL}
};

CMDENT_TWO_ARG_ARGV command_table_two_arg_argv[] =
{
    {(char *)"@cpattr",       NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,         0,             CS_TWO_ARG|CS_ARGV,             do_cpattr},
    {(char *)"@dig",          dig_sw,     CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,     0,      CS_TWO_ARG|CS_ARGV|CS_INTERP,   do_dig},
    {(char *)"@edit",         NULL,       CA_NO_SLAVE|CA_NO_GUEST,    0,      CS_TWO_ARG|CS_ARGV|CS_STRIP_AROUND, do_edit},
    {(char *)"@mvattr",       NULL,       CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,    0,      CS_TWO_ARG|CS_ARGV,     do_mvattr},
    {(char *)"@open",         open_sw,    CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,    0,      CS_TWO_ARG|CS_ARGV|CS_INTERP,   do_open},
    {(char *)"@trigger",      trig_sw,    CA_GBL_INTERP,    0,      CS_TWO_ARG|CS_ARGV,     do_trigger},
    {(char *)"@verb",         NULL,       CA_GBL_INTERP|CA_NO_SLAVE,    0,      CS_TWO_ARG|CS_ARGV|CS_INTERP|CS_STRIP_AROUND, do_verb},
    {(char *)NULL,            NULL,       0,     0,      0,              NULL}
};

CMDENT_TWO_ARG_CMDARG command_table_two_arg_cmdarg[] =
{
    {(char *)"@dolist",       dolist_sw,  CA_GBL_INTERP,    0,      CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, do_dolist},
    {(char *)"@force",        NULL,       CA_NO_SLAVE|CA_GBL_INTERP|CA_NO_GUEST,    FRC_COMMAND,    CS_TWO_ARG|CS_INTERP|CS_CMDARG, do_force},
    {(char *)"@wait",         NULL,       CA_GBL_INTERP,    0,      CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, do_wait},
    {(char *)NULL,            NULL,       0,     0,      0,              NULL}
};

CMDENT_TWO_ARG_ARGV_CMDARG command_table_two_arg_argv_cmdarg[] =
{
    {(char *)"@switch",       switch_sw,  CA_GBL_INTERP,    0,      CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP_AROUND, do_switch},
    {(char *)NULL,            NULL,       0,     0,      0,              NULL}
};

CMDENT *prefix_cmds[256];

CMDENT *goto_cmdp;

void NDECL(init_cmdtab)
{
    CMDENT_NO_ARG               *cp0a;
    CMDENT_ONE_ARG              *cp1a;
    CMDENT_ONE_ARG_CMDARG       *cp1ac;
    CMDENT_TWO_ARG              *cp2a;
    CMDENT_TWO_ARG_ARGV         *cp2aa;
    CMDENT_TWO_ARG_CMDARG       *cp2ac;
    CMDENT_TWO_ARG_ARGV_CMDARG  *cp2aac;

    ATTR *ap;

    // Load attribute-setting commands.
    //
    for (ap = attr; ap->name; ap++)
    {
        if (ap->flags & AF_NOCMD)
        {
            continue;
        }

        int nBuffer;
        BOOL bValid;
        char *cbuff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid);
        if (!bValid)
        {
            continue;
        }

        cp2a = (CMDENT_TWO_ARG *)MEMALLOC(sizeof(CMDENT_TWO_ARG));
        ISOUTOFMEMORY(cp2a);
        cp2a->cmdname = (char *)StringClone(cbuff);
        cp2a->perms = CA_NO_GUEST | CA_NO_SLAVE;
        cp2a->switches = NULL;
        if (ap->flags & (AF_WIZARD | AF_MDARK))
        {
            cp2a->perms |= CA_WIZARD;
        }
        cp2a->extra = ap->number;
        cp2a->callseq = CS_TWO_ARG;
        cp2a->handler = do_setattr;
        hashaddLEN(cp2a->cmdname, nBuffer, (int *)cp2a, &mudstate.command_htab);
    }

    /*
     * Load the builtin commands 
     */
    for (cp0a = command_table_no_arg; cp0a->cmdname; cp0a++)
        hashaddLEN(cp0a->cmdname, strlen(cp0a->cmdname), (int *)cp0a, &mudstate.command_htab);

    for (cp1a = command_table_one_arg; cp1a->cmdname; cp1a++)
        hashaddLEN(cp1a->cmdname, strlen(cp1a->cmdname), (int *)cp1a, &mudstate.command_htab);

    for (cp1ac = command_table_one_arg_cmdarg; cp1ac->cmdname; cp1ac++)
        hashaddLEN(cp1ac->cmdname, strlen(cp1ac->cmdname), (int *)cp1ac, &mudstate.command_htab);

    for (cp2a = command_table_two_arg; cp2a->cmdname; cp2a++)
        hashaddLEN(cp2a->cmdname, strlen(cp2a->cmdname), (int *)cp2a, &mudstate.command_htab);

    for (cp2aa = command_table_two_arg_argv; cp2aa->cmdname; cp2aa++)
        hashaddLEN(cp2aa->cmdname, strlen(cp2aa->cmdname), (int *)cp2aa, &mudstate.command_htab);

    for (cp2ac = command_table_two_arg_cmdarg; cp2ac->cmdname; cp2ac++)
        hashaddLEN(cp2ac->cmdname, strlen(cp2ac->cmdname), (int *)cp2ac, &mudstate.command_htab);

    for (cp2aac = command_table_two_arg_argv_cmdarg; cp2aac->cmdname; cp2aac++)
        hashaddLEN(cp2aac->cmdname, strlen(cp2aac->cmdname), (int *)cp2aac, &mudstate.command_htab);

    set_prefix_cmds();

    goto_cmdp = (CMDENT *) hashfindLEN((char *)"goto", strlen("goto"), &mudstate.command_htab);
}

void set_prefix_cmds()
{
    int i;

    // Load the command prefix table. Note - these commands can never
    // be typed in by a user because commands are lowercased before
    // the hash table is checked. The names are abbreviated to
    // minimise name checking time.
    //
    for (i = 0; i < 256; i++)
    {
        prefix_cmds[i] = NULL;
    }
    prefix_cmds['"']  = (CMDENT *) hashfindLEN((char *)"\"", 1, &mudstate.command_htab);
    prefix_cmds[':']  = (CMDENT *) hashfindLEN((char *)":",  1, &mudstate.command_htab);
    prefix_cmds[';']  = (CMDENT *) hashfindLEN((char *)";",  1, &mudstate.command_htab);
    prefix_cmds['\\'] = (CMDENT *) hashfindLEN((char *)"\\", 1, &mudstate.command_htab);
    prefix_cmds['#']  = (CMDENT *) hashfindLEN((char *)"#",  1, &mudstate.command_htab);
    prefix_cmds['&']  = (CMDENT *) hashfindLEN((char *)"&",  1, &mudstate.command_htab);
    prefix_cmds['-']  = (CMDENT *) hashfindLEN((char *)"-",  1, &mudstate.command_htab);
    prefix_cmds['~']  = (CMDENT *) hashfindLEN((char *)"~",  1, &mudstate.command_htab);
}

/*
 * ---------------------------------------------------------------------------
 * * check_access: Check if player has access to function.  
 */

int check_access(dbref player, int mask)
{
    int succ, fail;

    if (mask & (CA_DISABLED|CA_STATIC))
    {
        return 0;
    }
    if (God(player) || mudstate.initializing)
    {
        return 1;
    }

    succ = fail = 0;
    if (mask & CA_GOD)
        fail++;
    if (mask & CA_WIZARD)
    {
        if (Wizard(player))
            succ++;
        else
            fail++;
    }
    if ((succ == 0) && (mask & CA_ADMIN))
    {
        if (WizRoy(player))
            succ++;
        else
            fail++;
    }
    if ((succ == 0) && (mask & CA_BUILDER))
    {
        if (Builder(player))
            succ++;
        else
            fail++;
    }
    if ((succ == 0) && (mask & CA_STAFF))
    {
        if (Staff(player))
            succ++;
        else
            fail++;
    }
    if ((succ == 0) && (mask & CA_HEAD))
    {
        if (Head(player))
            succ++;
        else
            fail++;
    }
    if ((succ == 0) && (mask & CA_ANNOUNCE))
    {
        if (Announce(player))
            succ++;
        else
            fail++;
    }
    if ((succ == 0) && (mask & CA_IMMORTAL))
    {
        if (Immortal(player))
            succ++;
        else
            fail++;
    }
    if ((succ == 0) && (mask & CA_ROBOT))
    {
        if (Robot(player))
            succ++;
        else
            fail++;
    }
    if (succ > 0)
        fail = 0;
    if (fail > 0)
        return 0;

    // Check for forbidden flags.
    //
    if (  !Wizard(player)
       && (  ((mask & CA_NO_HAVEN)   && Player_haven(player))
          || ((mask & CA_NO_ROBOT)   && Robot(player))
          || ((mask & CA_NO_SLAVE)   && Slave(player))
          || ((mask & CA_NO_SUSPECT) && Suspect(player))
          || ((mask & CA_NO_GUEST)   && Guest(player))))
    {
        return 0;
    }
    return 1;
}

/*
 * ---------------------------------------------------------------------------
 * * process_cmdent: Perform indicated command with passed args.
 */

void process_cmdent(CMDENT *cmdp, char *switchp, dbref player, dbref cause, int interactive, char *arg,
            char *unp_command, char *cargs[], int ncargs)
{
    char *buf1, *buf2, tchar, *bp, *str, *buff, *s, *j, *new0;
    char *args[MAX_ARG];
    int nargs, i, interp, key, xkey, aflags;
    int hasswitch = 0;
    dbref aowner;
    char *aargs[10];
    ADDENT *add;
    
    // Perform object type checks.
    //
    if (Invalid_Objtype(player))
    {
        notify(player, "Command incompatible with invoker type.");
        return;
    }

    // Check if we have permission to execute the command.
    //
    if (!check_access(player, cmdp->perms))
    {
        notify(player, NOPERM_MESSAGE);
        return;
    }

    // Check global flags
    //
    if (  !Builder(player)
       && Protect(CA_GBL_BUILD)
       && !(mudconf.control_flags & CF_BUILD))
    {
        notify(player, "Sorry, building is not allowed now.");
        return;
    }
    if (Protect(CA_GBL_INTERP) && !(mudconf.control_flags & CF_INTERP))
    {
        notify(player, "Sorry, queueing and triggering are not allowed now.");
        return;
    }
    key = cmdp->extra & ~SW_MULTIPLE;
    if (key & SW_GOT_UNIQUE)
    {
        i = 1;
        key = key & ~SW_GOT_UNIQUE;
    }
    else
    {
        i = 0;
    }

    // Check command switches.  Note that there may be more than one,
    // and that we OR all of them together along with the extra value
    // from the command table to produce the key value in the handler
    // call.
    //
    if (switchp && cmdp->switches)
    {
        do
        {
            buf1 = (char *)strchr(switchp, '/');
            if (buf1)
                *buf1++ = '\0';
            xkey = search_nametab(player, cmdp->switches, switchp);
            if (xkey == -1)
            {
                notify(player,
                       tprintf("Unrecognized switch '%s' for command '%s'.",
                           switchp, cmdp->cmdname));
                return;
            }
            else if (xkey == -2)
            {
                notify(player, NOPERM_MESSAGE);
                return;
            }
            else if (!(xkey & SW_MULTIPLE))
            {
                if (i == 1)
                {
                    notify(player, "Illegal combination of switches.");
                    return;
                }
                i = 1;
            }
            else
            {
                xkey &= ~SW_MULTIPLE;
            }
            key |= xkey;
            switchp = buf1;
            hasswitch = 1;
        } while (buf1);
    }
    else if (switchp && !(cmdp->callseq & CS_ADDED))
    {
        notify(player, tprintf("Command %s does not take switches.",
            cmdp->cmdname));
        return;
    }

    // We are allowed to run the command.  Now, call the handler using
    // the appropriate calling sequence and arguments.
    //
    //if ((cmdp->callseq & CS_INTERP) && (key & SW_NOEVAL))
    if (key & SW_NOEVAL)
    {
        // The user specified /noeval on a @pemit or a @npemit,
        // just do EV_STRIP_CURLY and remove the SW_NOEVAL from the
        // 'key'.
        //
        interp = EV_STRIP_CURLY;
        key &= ~SW_NOEVAL;
    }
    else if (  (cmdp->callseq & CS_INTERP)
            || !(interactive
            || (cmdp->callseq & CS_NOINTERP)))
    {
        // If the command is interpreted, or we're interactive (and
        // the command isn't specified CS_NOINTERP), eval the args.
        //
        interp = EV_EVAL | EV_STRIP_CURLY;
    }
    else if (cmdp->callseq & CS_STRIP)
    {
        interp = EV_STRIP_CURLY;
    }
    else if (cmdp->callseq & CS_STRIP_AROUND)
    {
        interp = EV_STRIP_AROUND;
    }
    else
    {
        interp = 0;
    }

    switch (cmdp->callseq & CS_NARG_MASK)
    {
    case CS_NO_ARGS: // <cmd>   (no args)
        (*(((CMDENT_NO_ARG *)cmdp)->handler)) (player, cause, key);
        break;

    case CS_ONE_ARG:    /*
                 * <cmd> <arg> 
                 */

        /*
         * If an unparsed command, just give it to the handler 
         */

#if 0 // This never happens.
        if (cmdp->callseq & CS_UNPARSE)
        {
            (*(((CMDENT_ONE_ARG *)cmdp)->handler)) (player, unp_command);
            break;
        }
#endif
        // Interpret if necessary, but not twice for CS_ADDED.
        //
        if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED))
        {
            buf1 = bp = alloc_lbuf("process_cmdent");
            str = arg;
            TinyExec(buf1, &bp, 0, player, cause, interp | EV_FCHECK | EV_TOP, &str, cargs, ncargs);
            *bp = '\0';
        }
        else
        {
            buf1 = parse_to(&arg, '\0', interp | EV_TOP);
        }


        // Call the correct handler.
        //
        if (cmdp->callseq & CS_CMDARG)
        {
            (*(((CMDENT_ONE_ARG_CMDARG *)cmdp)->handler)) (player, cause, key, buf1, cargs, ncargs);
        }
        else
        {
            if (cmdp->callseq & CS_ADDED)
            {
                for (add = (ADDENT *)cmdp->handler; add != NULL; add = add->next)
                {
                    buff = atr_get(add->thing, add->atr, &aowner, &aflags);

                    // Skip the '$' character, and the next character.
                    //
                    for (s = buff + 2; *s && (*s != ':'); s++)
                    {
                        // nothing
                    }
                    if (!*s)
                    {
                        break;
                    }
                    *s++ = '\0';
                    
                    if (!(cmdp->callseq & CS_LEADIN))
                    {
                        for (j = unp_command; *j && (*j != ' '); j++) ;
                    }
                    else
                    {
                        for (j = unp_command; *j; j++) ;
                    }
                
                    new0 = alloc_lbuf("process_cmdent.soft");
                    bp = new0;
                    if (!*j)
                    {
                        // No args.
                        //
                        if (!(cmdp->callseq & CS_LEADIN))
                        {
                            safe_str(cmdp->cmdname, new0, &bp);
                        }
                        else
                        {
                            safe_str(unp_command, new0, &bp);
                        }
                        if (switchp)
                        {
                            safe_chr('/', new0, &bp);
                            safe_str(switchp, new0, &bp);
                        }
                        *bp = '\0';
                    }
                    else
                    {
                        j++;
                        safe_str(cmdp->cmdname, new0, &bp);
                        if (switchp)
                        {
                            safe_chr('/', new0, &bp);
                            safe_str(switchp, new0, &bp);
                        }
                        safe_chr(' ', new0, &bp);
                        safe_str(j, new0, &bp);
                        *bp = '\0';
                    } 
                
                    if (wild(buff + 1, new0, aargs, 10))
                    {
                        wait_que(add->thing, player, 0, NOTHING, 0, s, aargs, 10, mudstate.global_regs);
                        for (i = 0; i < 10; i++)
                        {
                            if (aargs[i])
                            {
                                free_lbuf(aargs[i]);
                            }
                        }
                    }
                    free_lbuf(new0);
                    free_lbuf(buff);
                }
            }
            else
            {
                (*(((CMDENT_ONE_ARG *)cmdp)->handler)) (player, cause, key, buf1);
            }
        }

        // Free the buffer if one was allocated.
        //
        if ((interp & EV_EVAL) && !(cmdp->callseq & CS_ADDED))
        {
            free_lbuf(buf1);
        }
        break;

    case CS_TWO_ARG: // <cmd> <arg1> = <arg2>

        // Interpret ARG1
        //
        buf2 = parse_to(&arg, '=', EV_STRIP_TS);

        // Handle when no '=' was specified.
        //
        if (!arg || (arg && !*arg))
        {
            arg = &tchar;
            *arg = '\0';
        }
        buf1 = bp = alloc_lbuf("process_cmdent.2");
        str = buf2;
        TinyExec(buf1, &bp, 0, player, cause, EV_STRIP_CURLY | EV_FCHECK | EV_EVAL | EV_TOP, &str, cargs, ncargs);
        *bp = '\0';

        if (cmdp->callseq & CS_ARGV)
        {
            // Arg2 is ARGV style.  Go get the args.
            //
            parse_arglist(player, cause, arg, '\0', interp | EV_STRIP_LS | EV_STRIP_TS, args, MAX_ARG, cargs, ncargs, &nargs);

            // Call the correct command handler.
            //
            if (cmdp->callseq & CS_CMDARG)
            {
                (*(((CMDENT_TWO_ARG_ARGV_CMDARG *)cmdp)->handler)) (player, cause, key, buf1, args, nargs, cargs, ncargs);
            }
            else
            {
                (*(((CMDENT_TWO_ARG_ARGV *)cmdp)->handler)) (player, cause, key, buf1, args, nargs);
            }

            // Free the argument buffers.
            //
            for (i = 0; i < nargs; i++)
            {
                free_lbuf(args[i]);
            }
        }
        else
        {
            // Arg2 is normal style.  Interpret if needed.
            //
            if (interp & EV_EVAL)
            {
                buf2 = bp = alloc_lbuf("process_cmdent.3");
                str = arg;
                TinyExec(buf2, &bp, 0, player, cause, interp | EV_FCHECK | EV_TOP, &str, cargs, ncargs);
                *bp = '\0';
            }
            else if (cmdp->callseq & CS_UNPARSE)
            {
                buf2 = parse_to(&arg, '\0', interp | EV_TOP | EV_NO_COMPRESS);
            }
            else
            {
                buf2 = parse_to(&arg, '\0', interp | EV_STRIP_LS | EV_STRIP_TS | EV_TOP);
            }

            // Call the correct command handler.
            //
            if (cmdp->callseq & CS_CMDARG)
            {
                (*(((CMDENT_TWO_ARG_CMDARG *)cmdp)->handler)) (player, cause, key, buf1, buf2, cargs, ncargs);
            }
            else
            {
                (*(((CMDENT_TWO_ARG *)cmdp)->handler)) (player, cause, key, buf1, buf2);
            }

            // Free the buffer, if needed.
            //
            if (interp & EV_EVAL)
            {
                free_lbuf(buf2);
            }
        }

        // Free the buffer obtained by evaluating Arg1.
        //
        free_lbuf(buf1);
        break;
    }
    return;
}

/*
 * ---------------------------------------------------------------------------
 * * process_command: Execute a command.
 */

void process_command(dbref player, dbref cause, int interactive, char *arg_command, char *args[], int nargs)
{
    char *pOriginalCommand = arg_command;
    static char SpaceCompressCommand[LBUF_SIZE];
    static char LowerCaseCommand[LBUF_SIZE];
    char *pCommand;
    char *p, *q, *arg, *pSlash, *cmdsave, *bp, *str;
    int succ, aflags, i;
    dbref exit, aowner;
    CMDENT *cmdp;

    // Robustify player.
    //
    cmdsave = mudstate.debug_cmd;
    mudstate.debug_cmd = (char *)"< process_command >";

    Tiny_Assert(pOriginalCommand);

    if (!Good_obj(player))
    {
        // We are using SpaceCompressCommand temporarily.
        //
        STARTLOG(LOG_BUGS, "CMD", "PLYR");
        sprintf(SpaceCompressCommand, "Bad player in process_command: %d", player);
        log_text(SpaceCompressCommand);
        ENDLOG;
        mudstate.debug_cmd = cmdsave;
        return;
    }

    // Make sure player isn't going or halted.
    //
    if (  Going(player)
       || (Halted(player) && !((Typeof(player) == TYPE_PLAYER) && interactive)))
    {
        notify(Owner(player), tprintf("Attempt to execute command by halted object #%d", player));
        mudstate.debug_cmd = cmdsave;
        return;
    }
    if (Suspect(player))
    {
        STARTLOG(LOG_SUSPECTCMDS, "CMD", "SUSP");
        log_name_and_loc(player);
        log_text(" entered: ");
        log_text(pOriginalCommand);
        ENDLOG;
    }
    else
    {
        STARTLOG(LOG_ALLCOMMANDS, "CMD", "ALL");
        log_name_and_loc(player);
        log_text(" entered: ");
        log_text(pOriginalCommand);
        ENDLOG;
    }

    // Reset recursion limits.
    //
    mudstate.func_nest_lev = 0;
    mudstate.func_invk_ctr = 0;
    mudstate.ntfy_nest_lev = 0;
    mudstate.lock_nest_lev = 0;
    mudstate.ufunc_nest_lev = 0;

    if (Verbose(player))
    {
        notify(Owner(player), tprintf("%s] %s", Name(player), pOriginalCommand));
    }

    // Eat leading whitespace, and space-compress if configured.
    //
    while (Tiny_IsSpace[(unsigned char)*pOriginalCommand])
    {
        pOriginalCommand++;
    }
    mudstate.debug_cmd = pOriginalCommand;

    if (mudconf.space_compress)
    {
        // Compress out the spaces and use that as the command
        //
        pCommand = SpaceCompressCommand;

        p = pOriginalCommand;
        q = SpaceCompressCommand;
        while (*p)
        {
            while (*p && !Tiny_IsSpace[(unsigned char)*p])
            {
                *q++ = *p++;
            }
            while (Tiny_IsSpace[(unsigned char)*p])
            {
                p++;
            }
            if (*p)
            {
                *q++ = ' ';
            }
        }
        *q = '\0';
    }
    else
    {
        // Don't compress the spaces. Use the original command
        // (without leading spaces) as the command to use.
        //
        pCommand = pOriginalCommand;
    }

    // Now comes the fun stuff.  First check for single-letter leadins.
    // We check these before checking HOME because they are among the
    // most frequently executed commands, and they can never be the
    // HOME command.
    //
    i = pCommand[0] & 0xff;
    if (i && (prefix_cmds[i] != NULL))
    {
        process_cmdent(prefix_cmds[i], NULL, player, cause, interactive, pCommand, pCommand, args, nargs);
        mudstate.debug_cmd = cmdsave;
        return;
    }

    if (  mudconf.have_comsys
       && !(Slave(player))
       && !do_comsystem(player, pCommand))
    {
        return;
    }

    // Check for the HOME command.
    //
    if (string_compare(pCommand, "home") == 0)
    {
        if (((Fixed(player)) || (Fixed(Owner(player)))) &&
            !(WizRoy(player)))
        {
            notify(player, mudconf.fixed_home_msg);
            return;
        }
        do_move(player, cause, 0, "home");
        mudstate.debug_cmd = cmdsave;
        return;
    }

    // Only check for exits if we may use the goto command.
    //
    if (check_access(player, goto_cmdp->perms))
    {
        // Check for an exit name.
        //
        init_match_check_keys(player, pCommand, TYPE_EXIT);
        match_exit_with_parents();
        exit = last_match_result();
        if (exit != NOTHING)
        {
            move_exit(player, exit, 0, "You can't go that way.", 0);
            mudstate.debug_cmd = cmdsave;
            return;
        }

        // Check for an exit in the master room.
        //
        init_match_check_keys(player, pCommand, TYPE_EXIT);
        match_master_exit();
        exit = last_match_result();
        if (exit != NOTHING)
        {
            move_exit(player, exit, 1, NULL, 0);
            mudstate.debug_cmd = cmdsave;
            return;
        }
    }
    
    // Set up a lowercase command and an arg pointer for the hashed
    // command check.  Since some types of argument processing destroy
    // the arguments, make a copy so that we keep the original command
    // line intact.  Store the edible copy in LowerCaseCommand after
    // the lower-cased command.
    //

    // Make lowercase command
    //
    for (p = pCommand, q = LowerCaseCommand;
         *p && !Tiny_IsSpace[(unsigned char)*p];
         p++, q++)
    {
        *q = Tiny_ToLower[(unsigned char)*p];
    }
    *q = '\0';
    int nLowerCaseCommand = q - LowerCaseCommand;

    // Skip spaces before arg
    //
    while (Tiny_IsSpace[(unsigned char)*p])
    {
        p++;
    }

    // Remember where arg starts
    //
    arg = p;

    // Strip off any command switches and save them.
    //
    pSlash = (char *)strchr(LowerCaseCommand, '/');
    if (pSlash)
    {
        nLowerCaseCommand = pSlash - LowerCaseCommand;
        *pSlash++ = '\0';
    }

    // Check for a builtin command (or an alias of a builtin command)
    //
    cmdp = (CMDENT *)hashfindLEN(LowerCaseCommand, nLowerCaseCommand, &mudstate.command_htab);
    if (cmdp != NULL)
    {
        if (mudconf.space_compress && (cmdp->callseq & CS_NOSQUISH))
        {
            // We handle this specially -- there is no space compression
            // involved, so we must go back to the original command.
            // We skip over the command and a single space to position
            // arg at the arguments.
            //
            arg = pCommand = pOriginalCommand;
            while (*arg && !Tiny_IsSpace[(unsigned char)*arg])
            {
                arg++;
            }
            if (*arg)
            {
                // We stopped on the space, advance to next.
                //
                arg++;     
            }
        }
        process_cmdent(cmdp, pSlash, player, cause, interactive, arg, pCommand, args, nargs);
        mudstate.debug_cmd = cmdsave;
        return;
    }

    // Check for enter and leave aliases, user-defined commands on the
    // player, other objects where the player is, on objects in the
    // player's inventory, and on the room that holds the player. We
    // evaluate the command line here to allow chains of $-commands
    // to work.
    //
    bp = LowerCaseCommand;
    str = pCommand;
    TinyExec(LowerCaseCommand, &bp, 0, player, cause, EV_EVAL | EV_FCHECK | EV_STRIP_CURLY | EV_TOP, &str, args, nargs);
    *bp = '\0';
    succ = 0;

    // Idea for enter/leave aliases from R'nice@TinyTIM
    //
    if (Has_location(player) && Good_obj(Location(player)))
    {
        // Check for a leave alias.
        //
        p = atr_pget(Location(player), A_LALIAS, &aowner, &aflags);
        if (p && *p)
        {
            if (matches_exit_from_list(LowerCaseCommand, p))
            {
                free_lbuf(p);
                do_leave(player, player, 0);
                return;
            }
        }
        free_lbuf(p);

        // Check for enter aliases.
        //
        DOLIST(exit, Contents(Location(player)))
        {
            p = atr_pget(exit, A_EALIAS, &aowner, &aflags);
            if (p && *p)
            {
                if (matches_exit_from_list(LowerCaseCommand, p))
                {
                    free_lbuf(p);
                    do_enter_internal(player, exit, 0);
                    return;
                }
            }
            free_lbuf(p);
        }
    }

    // Check for $-command matches on me.
    //
    if (mudconf.match_mine && (!(No_Command(player))))
    {
        if (((Typeof(player) != TYPE_PLAYER) || mudconf.match_mine_pl)
            && (atr_match(player, player, AMATCH_CMD, LowerCaseCommand, 1) > 0))
        {
            succ++;
        }
    }

    // Check for $-command matches on nearby things and on my room.
    //
    if (Has_location(player))
    {
        succ += list_check(Contents(Location(player)), player, AMATCH_CMD, LowerCaseCommand, 1);

        if (!(No_Command(Location(player))))
        {
            if (atr_match(Location(player), player, AMATCH_CMD, LowerCaseCommand, 1) > 0)
            {
                succ++;
            }
        }
    }

    // Check for $-command matches in my inventory.
    //
    if (Has_contents(player))
    {
        succ += list_check(Contents(player), player, AMATCH_CMD, LowerCaseCommand, 1);
    }

    // now do check on zones.
    //
    if ((!succ) && mudconf.have_zones &&
        (Zone(Location(player)) != NOTHING))
    {
        if (Typeof(Zone(Location(player))) == TYPE_ROOM)
        {
            // zone of player's location is a parent room.
            //
            if (Location(player) != Zone(player))
            {
                // check parent room exits.
                //
                init_match_check_keys(player, pCommand, TYPE_EXIT);
                match_zone_exit();
                exit = last_match_result();
                if (exit != NOTHING)
                {
                    move_exit(player, exit, 1, NULL, 0);
                    mudstate.debug_cmd = cmdsave;
                    return;
                }
                succ += list_check(Contents(Zone(Location(player))), player,
                           AMATCH_CMD, LowerCaseCommand, 1);

                // end of parent room checks.
                //
            }
        }
        else
        {
            // try matching commands on area zone object.
            //
            if (  (!succ)
               && mudconf.have_zones
               && (Zone(Location(player)) != NOTHING)
               && (!(No_Command(Zone(Location(player))))))
            {
               succ += atr_match(Zone(Location(player)), player, AMATCH_CMD, LowerCaseCommand, 1);
            }
        }
    }
    
    // End of matching on zone of player's location.
    //
    
    // if nothing matched with parent room/zone object, try matching
    // zone commands on the player's personal zone.
    //
    if (  (!succ)
       && mudconf.have_zones
       && (Zone(player) != NOTHING)
       && (!(No_Command(Zone(player))))
       && (Zone(Location(player)) != Zone(player)))
    {
        succ += atr_match(Zone(player), player, AMATCH_CMD, LowerCaseCommand, 1);
    }

    // If we didn't find anything, try in the master room.
    //
    if (!succ)
    {
        if (  Good_obj(mudconf.master_room)
           && Has_contents(mudconf.master_room))
        {
            succ += list_check(Contents(mudconf.master_room),
                       player, AMATCH_CMD, LowerCaseCommand, 0);
            if (!(No_Command(mudconf.master_room)))
            {
                if (atr_match(mudconf.master_room, player, AMATCH_CMD, LowerCaseCommand, 0) > 0)
                {
                    succ++;
                }
            }
        }
    }

    // If we still didn't find anything, tell how to get help.
    //
    if (!succ)
    {
        // We use LowerCaseCommand for another purpose.
        //
        notify(player, "Huh?  (Type \"help\" for help.)");
        STARTLOG(LOG_BADCOMMANDS, "CMD", "BAD");
        log_name_and_loc(player);
        log_text(" entered: ");
        log_text(pCommand);
        ENDLOG;
    }
    mudstate.debug_cmd = cmdsave;
    return;
}

/*
 * ---------------------------------------------------------------------------
 * * list_cmdtable: List internal commands.
 */

static void list_cmdtable(dbref player)
{
    char *buf, *bp, *cp;

    buf = alloc_lbuf("list_cmdtable");
    bp = buf;
    for (cp = (char *)"Commands:"; *cp; cp++)
        *bp++ = *cp;

    {
        CMDENT_NO_ARG *cmdp;
        for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    *bp++ = ' ';
                    for (cp = cmdp->cmdname; *cp; cp++)
                        *bp++ = *cp;
                }
            }
        }
    }
    {
        CMDENT_ONE_ARG *cmdp;
        for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    *bp++ = ' ';
                    for (cp = cmdp->cmdname; *cp; cp++)
                        *bp++ = *cp;
                }
            }
        }
    }
    {
        CMDENT_ONE_ARG_CMDARG *cmdp;
        for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    *bp++ = ' ';
                    for (cp = cmdp->cmdname; *cp; cp++)
                        *bp++ = *cp;
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG *cmdp;
        for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    *bp++ = ' ';
                    for (cp = cmdp->cmdname; *cp; cp++)
                        *bp++ = *cp;
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_ARGV *cmdp;
        for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    *bp++ = ' ';
                    for (cp = cmdp->cmdname; *cp; cp++)
                        *bp++ = *cp;
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_CMDARG *cmdp;
        for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    *bp++ = ' ';
                    for (cp = cmdp->cmdname; *cp; cp++)
                        *bp++ = *cp;
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_ARGV_CMDARG *cmdp;
        for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    *bp++ = ' ';
                    for (cp = cmdp->cmdname; *cp; cp++)
                        *bp++ = *cp;
                }
            }
        }
    }
    *bp = '\0';

    /*
     * Players get the list of logged-out cmds too 
     */

    if (Typeof(player) == TYPE_PLAYER)
        display_nametab(player, logout_cmdtable, buf, 1);
    else
        notify(player, buf);
    free_lbuf(buf);
}

/*
 * ---------------------------------------------------------------------------
 * * list_attrtable: List available attributes.
 */

static void list_attrtable(dbref player)
{
    ATTR *ap;
    char *buf, *bp, *cp;

    buf = alloc_lbuf("list_attrtable");
    bp = buf;
    for (cp = (char *)"Attributes:"; *cp; cp++)
        *bp++ = *cp;
    for (ap = attr; ap->name; ap++) {
        if (See_attr(player, player, ap, player, 0)) {
            *bp++ = ' ';
            for (cp = (char *)(ap->name); *cp; cp++)
                *bp++ = *cp;
        }
    }
    *bp = '\0';
    raw_notify(player, buf);
    free_lbuf(buf);
}

/*
 * ---------------------------------------------------------------------------
 * * list_cmdaccess: List access commands.
 */

NAMETAB access_nametab[] =
{
    {(char *)"builder",       6, CA_WIZARD, CA_BUILDER},
    {(char *)"dark",          4, CA_GOD,    CF_DARK},
    {(char *)"disabled",      4, CA_GOD,    CA_DISABLED},
    {(char *)"global_build",  8, CA_PUBLIC, CA_GBL_BUILD},
    {(char *)"global_interp", 8, CA_PUBLIC, CA_GBL_INTERP},
    {(char *)"god",           2, CA_GOD,    CA_GOD},
    {(char *)"head",          2, CA_WIZARD, CA_HEAD},
    {(char *)"immortal",      3, CA_WIZARD, CA_IMMORTAL},
    {(char *)"need_location", 6, CA_PUBLIC, CA_LOCATION},
    {(char *)"need_contents", 6, CA_PUBLIC, CA_CONTENTS},
    {(char *)"need_player",   6, CA_PUBLIC, CA_PLAYER},
    {(char *)"no_haven",      4, CA_PUBLIC, CA_NO_HAVEN},
    {(char *)"no_robot",      4, CA_WIZARD, CA_NO_ROBOT},
    {(char *)"no_slave",      5, CA_PUBLIC, CA_NO_SLAVE},
    {(char *)"no_suspect",    5, CA_WIZARD, CA_NO_SUSPECT},
    {(char *)"no_guest",      5, CA_WIZARD, CA_NO_GUEST},
    {(char *)"robot",         2, CA_WIZARD, CA_ROBOT},
    {(char *)"staff",         4, CA_WIZARD, CA_STAFF},
    {(char *)"static",        4, CA_GOD,    CA_STATIC},
    {(char *)"wizard",        3, CA_WIZARD, CA_WIZARD},
    {NULL,                    0, 0,         0}
};

static void list_cmdaccess(dbref player)
{
    ATTR *ap;

    char *buff = alloc_sbuf("list_cmdaccess");
    {
        CMDENT_NO_ARG *cmdp;
        for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    sprintf(buff, "%.60s:", cmdp->cmdname);
                    listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
                }
            }
        }
    }
    {
        CMDENT_ONE_ARG *cmdp;
        for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    sprintf(buff, "%.60s:", cmdp->cmdname);
                    listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
                }
            }
        }
    }
    {
        CMDENT_ONE_ARG_CMDARG *cmdp;
        for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    sprintf(buff, "%.60s:", cmdp->cmdname);
                    listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG *cmdp;
        for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    sprintf(buff, "%.60s:", cmdp->cmdname);
                    listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_ARGV *cmdp;
        for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    sprintf(buff, "%.60s:", cmdp->cmdname);
                    listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_CMDARG *cmdp;
        for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    sprintf(buff, "%.60s:", cmdp->cmdname);
                    listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_ARGV_CMDARG *cmdp;
        for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (check_access(player, cmdp->perms))
            {
                if (!(cmdp->perms & CF_DARK))
                {
                    sprintf(buff, "%.60s:", cmdp->cmdname);
                    listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
                }
            }
        }
    }
    free_sbuf(buff);
    for (ap = attr; ap->name; ap++)
    {
        if (ap->flags & AF_NOCMD)
        {
            continue;
        }

        int nBuffer;
        BOOL bValid;
        buff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid);
        if (!bValid)
        {
            continue;
        }

        CMDENT *cmdp = (CMDENT *)hashfindLEN(buff, nBuffer, &mudstate.command_htab);
        if (cmdp == NULL)
        {
            continue;
        }

        if (!check_access(player, cmdp->perms))
        {
            continue;
        }

        if (!(cmdp->perms & CF_DARK))
        {
            sprintf(buff, "%.60s:", cmdp->cmdname);
            listset_nametab(player, access_nametab, cmdp->perms, buff, 1);
        }
    }
}

/*
 * ---------------------------------------------------------------------------
 * * list_cmdswitches: List switches for commands.
 */

static void list_cmdswitches(dbref player)
{
    char *buff;

    buff = alloc_sbuf("list_cmdswitches");
    {
        CMDENT_NO_ARG *cmdp;
        for (cmdp = command_table_no_arg; cmdp->cmdname; cmdp++)
        {
            if (cmdp->switches)
            {
                if (check_access(player, cmdp->perms))
                {
                    if (!(cmdp->perms & CF_DARK))
                    {
                        sprintf(buff, "%.60s:", cmdp->cmdname);
                        display_nametab(player, cmdp->switches, buff, 0);
                    }
                }
            }
        }
    }
    {
        CMDENT_ONE_ARG *cmdp;
        for (cmdp = command_table_one_arg; cmdp->cmdname; cmdp++)
        {
            if (cmdp->switches)
            {
                if (check_access(player, cmdp->perms))
                {
                    if (!(cmdp->perms & CF_DARK))
                    {
                        sprintf(buff, "%.60s:", cmdp->cmdname);
                        display_nametab(player, cmdp->switches, buff, 0);
                    }
                }
            }
        }
    }
    {
        CMDENT_ONE_ARG_CMDARG *cmdp;
        for (cmdp = command_table_one_arg_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (cmdp->switches)
            {
                if (check_access(player, cmdp->perms))
                {
                    if (!(cmdp->perms & CF_DARK))
                    {
                        sprintf(buff, "%.60s:", cmdp->cmdname);
                        display_nametab(player, cmdp->switches, buff, 0);
                    }
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG *cmdp;
        for (cmdp = command_table_two_arg; cmdp->cmdname; cmdp++)
        {
            if (cmdp->switches)
            {
                if (check_access(player, cmdp->perms))
                {
                    if (!(cmdp->perms & CF_DARK))
                    {
                        sprintf(buff, "%.60s:", cmdp->cmdname);
                        display_nametab(player, cmdp->switches, buff, 0);
                    }
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_ARGV *cmdp;
        for (cmdp = command_table_two_arg_argv; cmdp->cmdname; cmdp++)
        {
            if (cmdp->switches)
            {
                if (check_access(player, cmdp->perms))
                {
                    if (!(cmdp->perms & CF_DARK))
                    {
                        sprintf(buff, "%.60s:", cmdp->cmdname);
                        display_nametab(player, cmdp->switches, buff, 0);
                    }
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_CMDARG *cmdp;
        for (cmdp = command_table_two_arg_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (cmdp->switches)
            {
                if (check_access(player, cmdp->perms))
                {
                    if (!(cmdp->perms & CF_DARK))
                    {
                        sprintf(buff, "%.60s:", cmdp->cmdname);
                        display_nametab(player, cmdp->switches, buff, 0);
                    }
                }
            }
        }
    }
    {
        CMDENT_TWO_ARG_ARGV_CMDARG *cmdp;
        for (cmdp = command_table_two_arg_argv_cmdarg; cmdp->cmdname; cmdp++)
        {
            if (cmdp->switches)
            {
                if (check_access(player, cmdp->perms))
                {
                    if (!(cmdp->perms & CF_DARK))
                    {
                        sprintf(buff, "%.60s:", cmdp->cmdname);
                        display_nametab(player, cmdp->switches, buff, 0);
                    }
                }
            }
        }
    }
    free_sbuf(buff);
}

/* ---------------------------------------------------------------------------
 * list_attraccess: List access to attributes.
 */

NAMETAB attraccess_nametab[] =
{
    {(char *)"dark",        2,  CA_WIZARD,  AF_DARK},
    {(char *)"deleted",     2,  CA_WIZARD,  AF_DELETED},
    {(char *)"god",         1,  CA_PUBLIC,  AF_GOD},
    {(char *)"hidden",      1,  CA_WIZARD,  AF_MDARK},
    {(char *)"ignore",      2,  CA_WIZARD,  AF_NOCMD},
    {(char *)"internal",        2,  CA_WIZARD,  AF_INTERNAL},
    {(char *)"is_lock",     4,  CA_PUBLIC,  AF_IS_LOCK},
    {(char *)"locked",      1,  CA_PUBLIC,  AF_LOCK},
    {(char *)"no_command",      4,  CA_PUBLIC,  AF_NOPROG},
    {(char *)"no_inherit",      4,  CA_PUBLIC,  AF_PRIVATE},
    {(char *)"private",     1,  CA_PUBLIC,  AF_ODARK},
    {(char *)"regexp",              1,      CA_PUBLIC,      AF_REGEXP},
    {(char *)"visual",      1,  CA_PUBLIC,  AF_VISUAL},
    {(char *)"wizard",      1,  CA_PUBLIC,  AF_WIZARD},
    { NULL,             0,  0,      0}
};

NAMETAB indiv_attraccess_nametab[] =
{
    {(char *)"hidden",      1,  CA_WIZARD,  AF_MDARK},
    {(char *)"wizard",      1,  CA_WIZARD,  AF_WIZARD},
    {(char *)"no_command",      4,  CA_PUBLIC,  AF_NOPROG},
    {(char *)"no_inherit",      4,  CA_PUBLIC,  AF_PRIVATE},
    {(char *)"visual",      1,  CA_PUBLIC,  AF_VISUAL},
    {(char *)"regexp",              1,      CA_PUBLIC,      AF_REGEXP},
    { NULL,             0,  0,      0}
};

static void list_attraccess(dbref player)
{
    char *buff;
    ATTR *ap;

    buff = alloc_sbuf("list_attraccess");
    for (ap = attr; ap->name; ap++)
    {
        if (Read_attr(player, player, ap, player, 0))
        {
            sprintf(buff, "%s:", ap->name);
            listset_nametab(player, attraccess_nametab, ap->flags, buff, 1);
        }
    }
    free_sbuf(buff);
}

/*
 * ---------------------------------------------------------------------------
 * * cf_access: Change command or switch permissions.
 */

extern void FDECL(cf_log_notfound, (dbref, char *, const char *, char *));

CF_HAND(cf_access)
{
    CMDENT *cmdp;
    char *ap;
    int set_switch;

    for (ap = str; *ap && !Tiny_IsSpace[(unsigned char)*ap] && (*ap != '/'); ap++) ;
    if (*ap == '/') {
        set_switch = 1;
        *ap++ = '\0';
    } else {
        set_switch = 0;
        if (*ap)
            *ap++ = '\0';
        while (Tiny_IsSpace[(unsigned char)*ap])
            ap++;
    }

    cmdp = (CMDENT *)hashfindLEN(str, strlen(str), &mudstate.command_htab);
    if (cmdp != NULL)
    {
        if (set_switch)
            return cf_ntab_access((int *)cmdp->switches, ap,
                          extra, player, cmd);
        else
            return cf_modify_bits(&(cmdp->perms), ap,
                          extra, player, cmd);
    }
    else
    {
        cf_log_notfound(player, cmd, "Command", str);
        return -1;
    }
}

/*
 * ---------------------------------------------------------------------------
 * * cf_acmd_access: Change command permissions for all attr-setting cmds.
 */

CF_HAND(cf_acmd_access)
{
    ATTR *ap;

    for (ap = attr; ap->name; ap++)
    {
        int nBuffer;
        int bValid;
        char *buff = MakeCanonicalAttributeCommand(ap->name, &nBuffer, &bValid);
        if (!bValid)
        {
            continue;
        }

        CMDENT *cmdp = (CMDENT *)hashfindLEN(buff, nBuffer, &mudstate.command_htab);
        if (cmdp != NULL)
        {
            int save = cmdp->perms;
            int failure = cf_modify_bits(&(cmdp->perms), str, extra, player, cmd);
            if (failure != 0)
            {
                cmdp->perms = save;
                free_sbuf(buff);
                return -1;
            }
        }
    }
    return 0;
}

/*
 * ---------------------------------------------------------------------------
 * * cf_attr_access: Change access on an attribute.
 */

CF_HAND(cf_attr_access)
{
    ATTR *ap;
    char *sp;

    for (sp = str; *sp && !Tiny_IsSpace[(unsigned char)*sp]; sp++) ;
    if (*sp)
        *sp++ = '\0';
    while (Tiny_IsSpace[(unsigned char)*sp])
        sp++;

    ap = atr_str(str);
    if (ap != NULL)
        return cf_modify_bits(&(ap->flags), sp, extra, player, cmd);
    else {
        cf_log_notfound(player, cmd, "Attribute", str);
        return -1;
    }
}

/*
 * ---------------------------------------------------------------------------
 * * cf_cmd_alias: Add a command alias.
 */

CF_HAND(cf_cmd_alias)
{
    char *ap;
    CMDENT *cmdp, *cmd2;
    NAMETAB *nt;
    int *hp;

    TINY_STRTOK_STATE tts;
    Tiny_StrTokString(&tts, str);
    Tiny_StrTokControl(&tts, " \t=,");
    char *alias = Tiny_StrTokParse(&tts);
    char *orig = Tiny_StrTokParse(&tts);

    if (!orig)
    {
        // We only got one argument to @alias. Bad.
        //
        return -1;
    }

    for (ap = orig; *ap && (*ap != '/'); ap++) ;
    if (*ap == '/') {

        /*
         * Switch form of command aliasing: create an alias for a  *
         * * * * * * command + a switch 
         */

        *ap++ = '\0';

        /*
         * Look up the command 
         */

        cmdp = (CMDENT *) hashfindLEN(orig, strlen(orig), (CHashTable *) vp);
        if (cmdp == NULL || cmdp->switches == NULL)
        {
            cf_log_notfound(player, cmd, "Command", orig);
            return -1;
        }
        /*
         * Look up the switch 
         */

        nt = find_nametab_ent(player, (NAMETAB *) cmdp->switches, ap);
        if (!nt)
        {
            cf_log_notfound(player, cmd, "Switch", ap);
            return -1;
        }

        // Got it, create the new command table entry.
        //
        cmd2 = (CMDENT *)MEMALLOC(sizeof(CMDENT));
        ISOUTOFMEMORY(cmd2);
        cmd2->cmdname = StringClone(alias);
        cmd2->switches = cmdp->switches;
        cmd2->perms = cmdp->perms | nt->perm;
        cmd2->extra = (cmdp->extra | nt->flag) & ~SW_MULTIPLE;
        if (!(nt->flag & SW_MULTIPLE))
        {
            cmd2->extra |= SW_GOT_UNIQUE;
        }
        cmd2->callseq = cmdp->callseq;
        cmd2->handler = cmdp->handler;
        if (hashaddLEN(cmd2->cmdname, strlen(cmd2->cmdname), (int *)cmd2, (CHashTable *) vp))
        {
            MEMFREE(cmd2->cmdname);
            MEMFREE(cmd2);
        }
    }
    else
    {

        /*
         * A normal (non-switch) alias 
         */

        hp = hashfindLEN(orig, strlen(orig), (CHashTable *) vp);
        if (hp == NULL)
        {
            cf_log_notfound(player, cmd, "Entry", orig);
            return -1;
        }
        hashaddLEN(alias, strlen(alias), hp, (CHashTable *) vp);
    }
    return 0;
}

/*
 * ---------------------------------------------------------------------------
 * * list_df_flags: List default flags at create time.
 */

static void list_df_flags(dbref player)
{
    char *playerb, *roomb, *thingb, *exitb, *robotb, *buff;

    playerb = decode_flags(player,
                   (mudconf.player_flags.word1 | TYPE_PLAYER),
                   mudconf.player_flags.word2,
                   mudconf.player_flags.word3);
    roomb = decode_flags(player,
                 (mudconf.room_flags.word1 | TYPE_ROOM),
                 mudconf.room_flags.word2,
                 mudconf.room_flags.word3);
    exitb = decode_flags(player,
                 (mudconf.exit_flags.word1 | TYPE_EXIT),
                 mudconf.exit_flags.word2,
                 mudconf.exit_flags.word3);
    thingb = decode_flags(player,
                  (mudconf.thing_flags.word1 | TYPE_THING),
                  mudconf.thing_flags.word2,
                  mudconf.thing_flags.word3);
    robotb = decode_flags(player,
                  (mudconf.robot_flags.word1 | TYPE_PLAYER),
                  mudconf.robot_flags.word2,
                  mudconf.robot_flags.word3);
    buff = alloc_lbuf("list_df_flags");
    sprintf(buff,
        "Default flags: Players...%s Rooms...%s Exits...%s Things...%s Robots...%s",
        playerb, roomb, exitb, thingb, robotb);
    raw_notify(player, buff);
    free_lbuf(buff);
    free_sbuf(playerb);
    free_sbuf(roomb);
    free_sbuf(exitb);
    free_sbuf(thingb);
    free_sbuf(robotb);
}

/*
 * ---------------------------------------------------------------------------
 * * list_costs: List the costs of things.
 */

#define coin_name(s)    (((s)==1) ? mudconf.one_coin : mudconf.many_coins)

static void list_costs(dbref player)
{
    char *buff;

    buff = alloc_mbuf("list_costs");
    *buff = '\0';
    if (mudconf.quotas)
        sprintf(buff, " and %d quota", mudconf.room_quota);
    notify(player,
           tprintf("Digging a room costs %d %s%s.",
               mudconf.digcost, coin_name(mudconf.digcost), buff));
    if (mudconf.quotas)
        sprintf(buff, " and %d quota", mudconf.exit_quota);
    notify(player,
           tprintf("Opening a new exit costs %d %s%s.",
               mudconf.opencost, coin_name(mudconf.opencost), buff));
    notify(player,
           tprintf("Linking an exit, home, or dropto costs %d %s.",
               mudconf.linkcost, coin_name(mudconf.linkcost)));
    if (mudconf.quotas)
        sprintf(buff, " and %d quota", mudconf.thing_quota);
    if (mudconf.createmin == mudconf.createmax)
        raw_notify(player,
               tprintf("Creating a new thing costs %d %s%s.",
                   mudconf.createmin,
                   coin_name(mudconf.createmin), buff));
    else
        raw_notify(player,
        tprintf("Creating a new thing costs between %d and %d %s%s.",
            mudconf.createmin, mudconf.createmax,
            mudconf.many_coins, buff));
    if (mudconf.quotas)
        sprintf(buff, " and %d quota", mudconf.player_quota);
    notify(player,
           tprintf("Creating a robot costs %d %s%s.",
               mudconf.robotcost, coin_name(mudconf.robotcost),
               buff));
    if (mudconf.killmin == mudconf.killmax) {
        raw_notify(player,
               tprintf("Killing costs %d %s, with a %d%% chance of success.",
                mudconf.killmin, coin_name(mudconf.digcost),
                   (mudconf.killmin * 100) /
                   mudconf.killguarantee));
    } else {
        raw_notify(player,
               tprintf("Killing costs between %d and %d %s.",
                   mudconf.killmin, mudconf.killmax,
                   mudconf.many_coins));
        raw_notify(player,
               tprintf("You must spend %d %s to guarantee success.",
                   mudconf.killguarantee,
                   coin_name(mudconf.killguarantee)));
    }
    raw_notify(player,
           tprintf("Computationally expensive commands and functions (ie: @entrances, @find, @search, @stats (with an argument or switch), search(), and stats()) cost %d %s.",
            mudconf.searchcost, coin_name(mudconf.searchcost)));
    if (mudconf.machinecost > 0)
        raw_notify(player,
           tprintf("Each command run from the queue costs 1/%d %s.",
               mudconf.machinecost, mudconf.one_coin));
    if (mudconf.waitcost > 0) {
        raw_notify(player,
               tprintf("A %d %s deposit is charged for putting a command on the queue.",
                   mudconf.waitcost, mudconf.one_coin));
        raw_notify(player, "The deposit is refunded when the command is run or canceled.");
    }
    if (mudconf.sacfactor == 0)
    {
        Tiny_ltoa(mudconf.sacadjust, buff);
    }
    else if (mudconf.sacfactor == 1)
    {
        if (mudconf.sacadjust < 0)
            sprintf(buff, "<create cost> - %d", -mudconf.sacadjust);
        else if (mudconf.sacadjust > 0)
            sprintf(buff, "<create cost> + %d", mudconf.sacadjust);
        else
            sprintf(buff, "<create cost>");
    }
    else
    {
        if (mudconf.sacadjust < 0)
            sprintf(buff, "(<create cost> / %d) - %d", mudconf.sacfactor, -mudconf.sacadjust);
        else if (mudconf.sacadjust > 0)
            sprintf(buff, "(<create cost> / %d) + %d", mudconf.sacfactor, mudconf.sacadjust);
        else
            sprintf(buff, "<create cost> / %d", mudconf.sacfactor);
    }
    raw_notify(player, tprintf("The value of an object is %s.", buff));
    if (mudconf.clone_copy_cost)
        raw_notify(player, "The default value of cloned objects is the value of the original object.");
    else
        raw_notify(player, tprintf("The default value of cloned objects is %d %s.",
                mudconf.createmin, coin_name(mudconf.createmin)));

    free_mbuf(buff);
}

/*
 * ---------------------------------------------------------------------------
 * * list_options: List more game options from mudconf.
 */

static const char *switchd[] =
{"/first", "/all"};
static const char *examd[] =
{"/brief", "/full"};
static const char *ed[] =
{"Disabled", "Enabled"};

static void list_options(dbref player)
{
    char *buff;

    CLinearTimeAbsolute ltaNow;
    ltaNow.GetUTC();

    if (mudconf.quotas)
        raw_notify(player, "Building quotas are enforced.");
    if (mudconf.name_spaces)
        raw_notify(player, "Player names may contain spaces.");
    else
        raw_notify(player, "Player names may not contain spaces.");
    if (!mudconf.robot_speak)
        raw_notify(player, "Robots are not allowed to speak in public areas.");
    if (mudconf.player_listen)
        raw_notify(player, "The @Listen/@Ahear attribute set works on player objects.");
    if (mudconf.ex_flags)
        raw_notify(player, "The 'examine' command lists the flag names for the object's flags.");
    if (!mudconf.quiet_look)
        raw_notify(player, "The 'look' command shows visible attributes in addition to the description.");
    if (mudconf.see_own_dark)
        raw_notify(player, "The 'look' command lists DARK objects owned by you.");
    if (!mudconf.dark_sleepers)
        raw_notify(player, "The 'look' command shows disconnected players.");
    if (mudconf.terse_look)
        raw_notify(player, "The 'look' command obeys the TERSE flag.");
    if (mudconf.trace_topdown)
    {
        raw_notify(player, "Trace output is presented top-down (whole expression first, then sub-exprs).");
        raw_notify(player, tprintf("Only %d lines of trace output are displayed.", mudconf.trace_limit));
    }
    else
    {
        raw_notify(player, "Trace output is presented bottom-up (subexpressions first).");
    }
    if (!mudconf.quiet_whisper)
        raw_notify(player, "The 'whisper' command lets others in the room with you know you whispered.");
    if (mudconf.pemit_players)
        raw_notify(player, "The '@pemit' command may be used to emit to faraway players.");
    if (!mudconf.terse_contents)
        raw_notify(player, "The TERSE flag suppresses listing the contents of a location.");
    if (!mudconf.terse_exits)
        raw_notify(player, "The TERSE flag suppresses listing obvious exits in a location.");
    if (!mudconf.terse_movemsg)
        raw_notify(player, "The TERSE flag suppresses enter/leave/succ/drop messages generated by moving.");
    if (mudconf.pub_flags)
        raw_notify(player, "The 'flags()' function will return the flags of any object.");
    if (mudconf.read_rem_desc)
        raw_notify(player, "The 'get()' function will return the description of faraway objects,");
    if (mudconf.read_rem_name)
        raw_notify(player, "The 'name()' function will return the name of faraway objects.");
    raw_notify(player, tprintf("The default switch for the '@switch' command is %s.", switchd[mudconf.switch_df_all]));
    raw_notify(player, tprintf("The default switch for the 'examine' command is %s.", examd[mudconf.exam_public]));
    if (mudconf.sweep_dark)
        raw_notify(player, "Players may @sweep dark locations.");
    if (mudconf.fascist_tport)
        raw_notify(player, "You may only @teleport out of locations that are JUMP_OK or that you control.");
    raw_notify(player,
           tprintf("Players may have at most %d commands in the queue at one time.",
               mudconf.queuemax));
    if (mudconf.match_mine) {
        if (mudconf.match_mine_pl)
            raw_notify(player, "All objects search themselves for $-commands.");
        else
            raw_notify(player, "Objects other than players search themselves for $-commands.");
    }
    if (!Wizard(player))
        return;
    buff = alloc_mbuf("list_options");

    raw_notify(player,
           tprintf("%d commands are run from the queue when there is no net activity.",
               mudconf.queue_chunk));
    raw_notify(player,
           tprintf("%d commands are run from the queue when there is net activity.",
               mudconf.active_q_chunk));
    if (mudconf.idle_wiz_dark)
        raw_notify(player, "Wizards idle for longer than the default timeout are automatically set DARK.");
    if (mudconf.safe_unowned)
        raw_notify(player, "Objects not owned by you are automatically considered SAFE.");
    if (mudconf.paranoid_alloc)
        raw_notify(player, "The buffer pools are checked for consistency on each allocate or free.");
    if (mudconf.cache_names)
        raw_notify(player, "A seperate name cache is used.");
#if !defined(VMS) && !defined(WIN32)
    if (mudconf.fork_dump)
    {
        raw_notify(player, "Database dumps are performed by a fork()ed process.");
        if (mudconf.fork_vfork)
            raw_notify(player, "The 'vfork()' call is used to perform the fork.");
    }
#endif // WIN32
    if (mudconf.max_players >= 0)
        raw_notify(player,
        tprintf("There may be at most %d players logged in at once.",
            mudconf.max_players));
    if (mudconf.quotas)
        sprintf(buff, " and %d quota", mudconf.start_quota);
    else
        *buff = '\0';
    raw_notify(player,
           tprintf("New players are given %d %s to start with.",
               mudconf.paystart, mudconf.many_coins));
    raw_notify(player,
           tprintf("Players are given %d %s each day they connect.",
               mudconf.paycheck, mudconf.many_coins));
    raw_notify(player,
      tprintf("Earning money is difficult if you have more than %d %s.",
          mudconf.paylimit, mudconf.many_coins));
    if (mudconf.payfind > 0)
        raw_notify(player,
               tprintf("Players have a 1 in %d chance of finding a %s each time they move.",
                   mudconf.payfind, mudconf.one_coin));
    raw_notify(player,
           tprintf("The head of the object freelist is #%d.",
               mudstate.freelist));

    sprintf(buff, "Intervals: Dump...%d  Clean...%d  Idlecheck...%d",
        mudconf.dump_interval, mudconf.check_interval,
        mudconf.idle_interval);
    raw_notify(player, buff);

    CLinearTimeDelta ltdDump = mudstate.dump_counter - ltaNow;
    CLinearTimeDelta ltdCheck = mudstate.check_counter - ltaNow;
    CLinearTimeDelta ltdIdle = mudstate.idle_counter - ltaNow;
    sprintf(buff, "Timers: Dump...%ld  Clean...%ld  Idlecheck...%ld",
        ltdDump.ReturnSeconds(), ltdCheck.ReturnSeconds(), ltdIdle.ReturnSeconds());
    raw_notify(player, buff);

    sprintf(buff, "Timeouts: Idle...%d  Connect...%d  Tries...%d",
        mudconf.idle_timeout, mudconf.conn_timeout,
        mudconf.retry_limit);
    raw_notify(player, buff);

    sprintf(buff, "Scheduling: Timeslice...%d  Max_Quota...%d  Increment...%d",
        mudconf.timeslice, mudconf.cmd_quota_max, mudconf.cmd_quota_incr);
    raw_notify(player, buff);

    sprintf(buff, "Spaces...%s  Savefiles...%s",
        ed[mudconf.space_compress], ed[mudconf.compress_db]);
    raw_notify(player, buff);

    sprintf(buff, "New characters: Room...#%d  Home...#%d  DefaultHome...#%d  Quota...%d",
        mudconf.start_room, mudconf.start_home, mudconf.default_home,
        mudconf.start_quota);
    raw_notify(player, buff);

    sprintf(buff, "Misc: GuestChar...#%d  IdleQueueChunk...%d  ActiveQueueChunk...%d  Master_room...#%d",
        mudconf.guest_char, mudconf.queue_chunk,
        mudconf.active_q_chunk, mudconf.master_room);
    raw_notify(player, buff);

    free_mbuf(buff);
}

/*
 * ---------------------------------------------------------------------------
 * * list_vattrs: List user-defined attributes
 */

static void list_vattrs(dbref player)
{
    VATTR *va;
    int na;
    char *buff;

    buff = alloc_lbuf("list_vattrs");
    raw_notify(player, "--- User-Defined Attributes ---");
    for (va = vattr_first(), na = 0; va; va = vattr_next(va), na++) {
        if (!(va->flags & AF_DELETED)) {
            sprintf(buff, "%s(%d):", va->name, va->number);
            listset_nametab(player, attraccess_nametab, va->flags,
                    buff, 1);
        }
    }

    raw_notify(player, tprintf("%d attributes, next=%d",
                   na, mudstate.attr_next));
    free_lbuf(buff);
}

/*
 * ---------------------------------------------------------------------------
 * * list_hashstats: List information from hash tables
 */

static void list_hashstat(dbref player, const char *tab_name, CHashTable *htab)
{
    char *buff = hashinfo(tab_name, htab);
    raw_notify(player, buff);
    free_mbuf(buff);
}

static void list_hashstats(dbref player)
{
    raw_notify(player, "Hash Stats       Size  Entries  Deleted    Lookups       Hits     Checks Longest");
    list_hashstat(player, "Commands", &mudstate.command_htab);
    list_hashstat(player, "Logged-out Cmds", &mudstate.logout_cmd_htab);
    list_hashstat(player, "Functions", &mudstate.func_htab);
    list_hashstat(player, "Flags", &mudstate.flags_htab);
    list_hashstat(player, "Powers", &mudstate.powers_htab);
    list_hashstat(player, "Attr names", &mudstate.attr_name_htab);
    list_hashstat(player, "Vattr names", &mudstate.vattr_name_htab);
    list_hashstat(player, "Player Names", &mudstate.player_htab);
    list_hashstat(player, "Net Descriptors", &mudstate.desc_htab);
    list_hashstat(player, "Forwardlists", &mudstate.fwdlist_htab);
    list_hashstat(player, "Overlaid $-cmds", &mudstate.parent_htab);
    list_hashstat(player, "Mail messages", &mudstate.mail_htab);
    list_hashstat(player, "Channel names", &mudstate.channel_htab);
    list_hashstat(player, "News topics", &mudstate.news_htab);
    list_hashstat(player, "Help topics", &mudstate.help_htab);
    list_hashstat(player, "Wizhelp topics", &mudstate.wizhelp_htab);
    list_hashstat(player, "+Help topics", &mudstate.plushelp_htab);
    list_hashstat(player, "+Shelp topics", &mudstate.staffhelp_htab);
    list_hashstat(player, "Wiznews topics", &mudstate.wiznews_htab);
    list_hashstat(player, "Attribute Cache", &mudstate.acache_htab);
}

#ifndef MEMORY_BASED
//
// These are from 'svdhash.cpp'.
//
extern CLinearTimeAbsolute cs_ltime;
extern int cs_writes;       // total writes
extern int cs_reads;        // total reads
extern int cs_dels;         // total deletes
extern int cs_fails;        // attempts to grab nonexistent
extern int cs_syncs;        // total cache syncs
extern int cs_dbreads;      // total read-throughs
extern int cs_dbwrites;     // total write-throughs
extern int cs_rhits;        // total reads filled from cache
extern int cs_whits;        // total writes to dirty cache
#endif // !MEMORY_BASED


#ifdef RADIX_COMPRESSION
extern unsigned int strings_compressed;     // Total number of compressed strings  
extern unsigned int strings_decompressed;   // Total number of decompressed strings  
extern unsigned int chars_in;               // Total characters compressed
extern unsigned int symbols_out;            // Total symbols emitted
#endif // RADIX_COMPRESSION  

/*
 * ---------------------------------------------------------------------------
 * * list_db_stats: Get useful info from the DB layer about hash stats, etc.
 */

static void list_db_stats(dbref player)
{
#ifdef MEMORY_BASED
    raw_notify(player, "Database is memory based.");
#else
    CLinearTimeAbsolute lsaNow;
    lsaNow.GetUTC();
    CLinearTimeDelta ltd = lsaNow - cs_ltime;
    raw_notify(player, tprintf("DB Cache Stats   Writes       Reads  (over %d seconds)", ltd.ReturnSeconds()));
    raw_notify(player, tprintf("Calls      %12d%12d", cs_writes, cs_reads));
    raw_notify(player, tprintf("\nDeletes    %12d", cs_dels));
    raw_notify(player, tprintf("Syncs      %12d", cs_syncs));
    raw_notify(player, tprintf("I/O        %12d%12d", cs_dbwrites, cs_dbreads));
    raw_notify(player, tprintf("Cache Hits %12d%12d", cs_whits, cs_rhits));
#endif // !MEMORY_BASED

#ifdef RADIX_COMPRESSION
    raw_notify(player, "Compression statistics:");
    raw_notify(player, tprintf("Strings compressed %d", strings_compressed));
    raw_notify(player, tprintf("Strings decompressed %d", strings_decompressed));
    raw_notify(player, tprintf("Compression ratio %d:%d", chars_in, symbols_out + (symbols_out >> 1)));
#endif // RADIX_COMPRESSION
}

/*
 * ---------------------------------------------------------------------------
 * * list_process: List local resource usage stats of the mux process.
 * * Adapted from code by Claudius@PythonMUCK,
 * *     posted to the net by Howard/Dark_Lord.
 */

static void list_process(dbref player)
{
    int maxfds;

#ifdef HAVE_GETRUSAGE
    struct rusage usage;
    int ixrss, idrss, isrss, curr, last, dur;

    getrusage(RUSAGE_SELF, &usage);

    // Calculate memory use from the aggregate totals.
    //
    curr = mudstate.mstat_curr;
    last = 1 - curr;
    dur = mudstate.mstat_secs[curr] - mudstate.mstat_secs[last];
    if (dur > 0)
    {
        ixrss = (mudstate.mstat_ixrss[curr] -
             mudstate.mstat_ixrss[last]) / dur;
        idrss = (mudstate.mstat_idrss[curr] -
             mudstate.mstat_idrss[last]) / dur;
        isrss = (mudstate.mstat_isrss[curr] -
             mudstate.mstat_isrss[last]) / dur;
    }
    else
    {
        ixrss = 0;
        idrss = 0;
        isrss = 0;
    }
#endif

#ifdef WIN32
    maxfds = FD_SETSIZE;
#else // WIN32
#ifdef HAVE_GETDTABLESIZE
    maxfds = getdtablesize();
#else
    maxfds = sysconf(_SC_OPEN_MAX);
#endif
    int psize = getpagesize();
#endif // WIN32

    /*
     * Go display everything 
     */

#ifdef WIN32
    raw_notify(player, tprintf("Process ID:  %10d", game_pid));
#else // WIN32
    raw_notify(player, tprintf("Process ID:  %10d        %10d bytes per page", game_pid, psize));
#endif // WIN32

#ifdef HAVE_GETRUSAGE
    raw_notify(player, tprintf("Time used:   %10d user   %10d sys",
               usage.ru_utime.tv_sec, usage.ru_stime.tv_sec));
/*
 * raw_notify(player,
 * * tprintf("Resident mem:%10d shared %10d private%10d stack",
 * * ixrss, idrss, isrss));
 */
    raw_notify(player,
           tprintf("Integral mem:%10d shared %10d private%10d stack",
               usage.ru_ixrss, usage.ru_idrss, usage.ru_isrss));
    raw_notify(player,
           tprintf("Max res mem: %10d pages  %10d bytes",
               usage.ru_maxrss, (usage.ru_maxrss * psize)));
    raw_notify(player,
           tprintf("Page faults: %10d hard   %10d soft   %10d swapouts",
               usage.ru_majflt, usage.ru_minflt, usage.ru_nswap));
    raw_notify(player,
           tprintf("Disk I/O:    %10d reads  %10d writes",
               usage.ru_inblock, usage.ru_oublock));
    raw_notify(player,
           tprintf("Network I/O: %10d in     %10d out",
               usage.ru_msgrcv, usage.ru_msgsnd));
    raw_notify(player,
           tprintf("Context swi: %10d vol    %10d forced %10d sigs",
               usage.ru_nvcsw, usage.ru_nivcsw, usage.ru_nsignals));
    raw_notify(player,
           tprintf("Descs avail: %10d", maxfds));
#endif
}
/*
 * ---------------------------------------------------------------------------
 * * do_list: List information stored in internal structures.
 */

#define LIST_ATTRIBUTES 1
#define LIST_COMMANDS   2
#define LIST_COSTS  3
#define LIST_FLAGS  4
#define LIST_FUNCTIONS  5
#define LIST_GLOBALS    6
#define LIST_ALLOCATOR  7
#define LIST_LOGGING    8
#define LIST_DF_FLAGS   9
#define LIST_PERMS  10
#define LIST_ATTRPERMS  11
#define LIST_OPTIONS    12
#define LIST_HASHSTATS  13
#define LIST_BUFTRACE   14
#define LIST_CONF_PERMS 15
#define LIST_SITEINFO   16
#define LIST_POWERS 17
#define LIST_SWITCHES   18
#define LIST_VATTRS 19
#define LIST_DB_STATS   20
#define LIST_PROCESS    21
#define LIST_BADNAMES   22
#define LIST_RESOURCES  23

NAMETAB list_names[] =
{
    {(char *)"allocations",     2,  CA_WIZARD,  LIST_ALLOCATOR},
    {(char *)"attr_permissions",    5,  CA_WIZARD,  LIST_ATTRPERMS},
    {(char *)"attributes",      2,  CA_PUBLIC,  LIST_ATTRIBUTES},
    {(char *)"bad_names",       2,  CA_WIZARD,  LIST_BADNAMES},
    {(char *)"buffers",     2,  CA_WIZARD,  LIST_BUFTRACE},
    {(char *)"commands",        3,  CA_PUBLIC,  LIST_COMMANDS},
    {(char *)"config_permissions",  3,  CA_GOD,     LIST_CONF_PERMS},
    {(char *)"costs",       3,  CA_PUBLIC,  LIST_COSTS},
    {(char *)"db_stats",        2,  CA_WIZARD,  LIST_DB_STATS},
    {(char *)"default_flags",   1,  CA_PUBLIC,  LIST_DF_FLAGS},
    {(char *)"flags",       2,  CA_PUBLIC,  LIST_FLAGS},
    {(char *)"functions",       2,  CA_PUBLIC,  LIST_FUNCTIONS},
    {(char *)"globals",     1,  CA_WIZARD,  LIST_GLOBALS},
    {(char *)"hashstats",       1,  CA_WIZARD,  LIST_HASHSTATS},
    {(char *)"logging",     1,  CA_GOD,     LIST_LOGGING},
    {(char *)"options",     1,  CA_PUBLIC,  LIST_OPTIONS},
    {(char *)"permissions",     2,  CA_WIZARD,  LIST_PERMS},
    {(char *)"powers",      2,  CA_WIZARD,  LIST_POWERS},
    {(char *)"process",     2,  CA_WIZARD,  LIST_PROCESS},
    {(char *)"resources",     1,  CA_WIZARD,  LIST_RESOURCES},
    {(char *)"site_information",    2,  CA_WIZARD,  LIST_SITEINFO},
    {(char *)"switches",        2,  CA_PUBLIC,  LIST_SWITCHES},
    {(char *)"user_attributes", 1,  CA_WIZARD,  LIST_VATTRS},
    { NULL,             0,  0,      0}
};

extern NAMETAB enable_names[];
extern NAMETAB logoptions_nametab[];
extern NAMETAB logdata_nametab[];

void do_list(dbref player, dbref cause, int extra, char *arg)
{
    int flagvalue;

    flagvalue = search_nametab(player, list_names, arg);
    switch (flagvalue) {
    case LIST_ALLOCATOR:
        list_bufstats(player);
        break;
    case LIST_BUFTRACE:
        list_buftrace(player);
        break;
    case LIST_ATTRIBUTES:
        list_attrtable(player);
        break;
    case LIST_COMMANDS:
        list_cmdtable(player);
        break;
    case LIST_SWITCHES:
        list_cmdswitches(player);
        break;
    case LIST_COSTS:
        list_costs(player);
        break;
    case LIST_OPTIONS:
        list_options(player);
        break;
    case LIST_HASHSTATS:
        list_hashstats(player);
        break;
    case LIST_SITEINFO:
        list_siteinfo(player);
        break;
    case LIST_FLAGS:
        display_flagtab(player);
        break;
    case LIST_FUNCTIONS:
        list_functable(player);
        break;
    case LIST_GLOBALS:
        interp_nametab(player, enable_names, mudconf.control_flags,
                (char *)"Global parameters:", (char *)"enabled",
                   (char *)"disabled");
        break;
    case LIST_DF_FLAGS:
        list_df_flags(player);
        break;
    case LIST_PERMS:
        list_cmdaccess(player);
        break;
    case LIST_CONF_PERMS:
        list_cf_access(player);
        break;
    case LIST_POWERS:
        display_powertab(player);
        break;
    case LIST_ATTRPERMS:
        list_attraccess(player);
        break;
    case LIST_VATTRS:
        list_vattrs(player);
        break;
    case LIST_LOGGING:
        interp_nametab(player, logoptions_nametab, mudconf.log_options,
                   (char *)"Events Logged:", (char *)"enabled",
                   (char *)"disabled");
        interp_nametab(player, logdata_nametab, mudconf.log_info,
                   (char *)"Information Logged:", (char *)"yes",
                   (char *)"no");
        break;
    case LIST_DB_STATS:
        list_db_stats(player);
        break;
    case LIST_PROCESS:
        list_process(player);
        break;
    case LIST_BADNAMES:
        badname_list(player, "Disallowed names:");
        break;
    case LIST_RESOURCES:
        list_system_resources(player);
        break;
    default:
        display_nametab(player, list_names,
                (char *)"Unknown option.  Use one of:", 1);
    }
}