/* command.c - command parser and support routines */
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifdef WANT_ANSI
#ifdef __STDC__
#include <stdlib.h>
#endif /* __STDC__ */
#endif /* WANT_ANSI */
#include "config.h"
#include "db.h"
#include "interface.h"
#include "mudconf.h"
#include "command.h"
#include "functions.h"
#include "externs.h"
#include "match.h"
#include "flags.h"
extern void list_cf_access(dbref player);
/* ---------------------------------------------------------------------------
* Switch tables for the various commands.
*/
#define SW_MULTIPLE 0x80000000 /* This sw may be spec'd w/others */
#define SW_GOT_UNIQUE 0x40000000 /* Already have a unique option */
/* (typically via a switch alias) */
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 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 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_WIZARD, DOING_HEADER},
{(char *)"message", 1, CA_PUBLIC, DOING_MESSAGE},
{(char *)"poll", 1, CA_PUBLIC, DOING_POLL},
{ 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},
{ NULL, 0, 0, 0}};
NAMETAB emit_sw[] = {
{(char *)"here", 1, CA_PUBLIC, SAY_HERE|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 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 get_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, GET_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_WIZARD, HALT_ALL},
{ NULL, 0, 0, 0}};
NAMETAB leave_sw[] = {
{(char *)"quiet", 1, CA_PUBLIC, MOVE_QUIET},
{ 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", 1, CA_PUBLIC, A_LPAGE},
{(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},
{ 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 *)"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},
{(char *)"object", 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_WIZARD, 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 rwho_sw[] = {
{(char *)"start", 3, CA_PUBLIC, RWHO_START},
{(char *)"stop", 3, CA_PUBLIC, RWHO_STOP},
{ 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 toad_sw[] = {
{(char *)"no_chown", 1, CA_WIZARD, TOAD_NO_CHOWN|SW_MULTIPLE},
{ NULL, 0, 0, 0}};
NAMETAB wall_sw[] = {
{(char *)"emit", 1, CA_WIZARD, SAY_WALLEMIT},
{(char *)"no_prefix", 1, CA_WIZARD, SAY_NOTAG|SW_MULTIPLE},
{(char *)"pose", 1, CA_WIZARD, SAY_WALLPOSE},
{(char *)"wizard", 1, CA_WIZARD, SAY_WIZSHOUT|SW_MULTIPLE},
{ 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 *)"rwho", 1, CA_WIZARD, TWARP_RWHO|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 command_table[] = {
{(char *)"@@", NULL, 0,
0, CS_NO_ARGS, do_comment},
{(char *)"@admin", NULL, CA_GOD,
0, CS_TWO_ARG|CS_INTERP, do_admin},
{(char *)"@alias", NULL, CA_NO_GUEST|CA_NO_SLAVE,
0, CS_TWO_ARG, do_alias},
{(char *)"@apply_marked", NULL, CA_WIZARD|CA_GBL_INTERP,
0, CS_ONE_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP,
do_apply_marked},
{(char *)"@attribute", attrib_sw, CA_GOD,
0, CS_TWO_ARG|CS_INTERP, do_attribute},
{(char *)"@boot", boot_sw, CA_WIZARD,
0, CS_ONE_ARG|CS_INTERP, do_boot},
{(char *)"@cat", NULL, CA_WIZARD,
0, CS_TWO_ARG|CS_INTERP, do_cat},
{(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 *)"@clone", clone_sw,
CA_NO_SLAVE|CA_GBL_BUILD|CA_LOCATION|CA_CONTENTS|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP, do_clone},
{(char *)"@create", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_CONTENTS|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP, do_create},
{(char *)"@cut", NULL, CA_WIZARD|CA_LOCATION,
0, CS_ONE_ARG|CS_INTERP, do_cut},
{(char *)"@dbck", NULL, CA_WIZARD,
0, CS_NO_ARGS, do_dbck},
{(char *)"@decompile", NULL, 0,
0, CS_TWO_ARG|CS_INTERP, do_decomp},
{(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 *)"@dig", dig_sw,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
0, CS_TWO_ARG|CS_ARGV|CS_INTERP, do_dig},
{(char *)"@disable", NULL, CA_WIZARD,
GLOB_DISABLE, CS_ONE_ARG, do_global},
{(char *)"@doing", doing_sw, CA_PLAYER,
0, CS_ONE_ARG|CS_NOINTERP, do_doing},
{(char *)"@dolist", NULL, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP, do_dolist},
{(char *)"@drain", NULL,
CA_GBL_INTERP|CA_NO_SLAVE|CA_NO_GUEST,
NFY_DRAIN, CS_TWO_ARG, do_notify},
{(char *)"@dump", dump_sw, CA_WIZARD,
0, CS_NO_ARGS, do_dump},
{(char *)"@edit", NULL, CA_NO_SLAVE|CA_NO_GUEST,
0, CS_TWO_ARG|CS_ARGV|CS_STRIP, do_edit},
{(char *)"@emit", emit_sw,
CA_LOCATION|CA_NO_GUEST|CA_NO_GAGGED,
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_LOCATION|CA_NO_GUEST,
0, CS_ONE_ARG|CS_INTERP, do_entrances},
{(char *)"@femit", NULL,
CA_LOCATION|CA_NO_GUEST|CA_NO_GAGGED,
PEMIT_FEMIT, CS_TWO_ARG|CS_INTERP, do_pemit},
{(char *)"@find", NULL, 0,
0, CS_ONE_ARG|CS_INTERP, do_find},
{(char *)"@fixdb", fixdb_sw, CA_GOD,
0, CS_TWO_ARG|CS_INTERP, do_fixdb},
/*{(char *)"@fnd", NULL, 0,
0, CS_ONE_ARG|CS_UNPARSE, do_fnd}, */
{(char *)"@force", NULL,
CA_NO_SLAVE|CA_GBL_INTERP|CA_NO_GUEST,
FRC_COMMAND, CS_TWO_ARG|CS_INTERP|CS_CMDARG, do_force},
{(char *)"@fpose", fpose_sw, CA_LOCATION|CA_NO_GAGGED,
PEMIT_FPOSE, CS_TWO_ARG|CS_INTERP, do_pemit},
{(char *)"@fsay", NULL, CA_LOCATION|CA_NO_GAGGED,
PEMIT_FSAY, CS_TWO_ARG|CS_INTERP, do_pemit},
{(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 *)"@link", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_LOCATION|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP, do_link},
{(char *)"@list", NULL, 0,
0, CS_ONE_ARG|CS_INTERP, do_list},
{(char *)"@list_file", NULL, CA_WIZARD,
0, CS_ONE_ARG|CS_INTERP, do_list_file},
{(char *)"@listmotd", NULL, 0,
MOTD_LIST, CS_ONE_ARG, do_motd},
{(char *)"@lock", lock_sw, CA_NO_SLAVE,
0, CS_TWO_ARG|CS_INTERP, do_lock},
{(char *)"@mark", mark_sw, CA_WIZARD,
SRCH_MARK, CS_ONE_ARG|CS_NOINTERP, do_search},
{(char *)"@mark_all", markall_sw, CA_WIZARD,
MARK_SET, CS_NO_ARGS, do_markall},
{(char *)"@motd", motd_sw, CA_WIZARD,
0, CS_ONE_ARG, do_motd},
{(char *)"@mvattr", NULL,
CA_NO_SLAVE|CA_NO_GUEST|CA_GBL_BUILD,
0, CS_TWO_ARG|CS_ARGV, do_mvattr},
{(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 *)"@note", NULL, CA_WIZARD,
SAY_NOTE, CS_ONE_ARG, do_say},
{(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_GAGGED,
PEMIT_OEMIT, CS_TWO_ARG|CS_INTERP, do_pemit},
{(char *)"@open", open_sw,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,
0, CS_TWO_ARG|CS_ARGV|CS_INTERP, do_open},
{(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_GAGGED,
PEMIT_PEMIT, CS_TWO_ARG|CS_INTERP, do_pemit},
{(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 *)"@quota", quota_sw, 0,
0, CS_TWO_ARG|CS_INTERP, do_quota},
{(char *)"@readcache", NULL, CA_WIZARD,
0, CS_NO_ARGS, do_readcache},
{(char *)"@robot", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST|CA_PLAYER,
PCRE_ROBOT, CS_TWO_ARG, do_pcreate},
{(char *)"@rwho", rwho_sw, CA_GOD,
0, CS_NO_ARGS, do_rwho},
{(char *)"@search", NULL, 0,
SRCH_SEARCH, CS_ONE_ARG|CS_NOINTERP, do_search},
{(char *)"@set", NULL,
CA_NO_SLAVE|CA_GBL_BUILD|CA_NO_GUEST,
0, CS_TWO_ARG, do_set},
{(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_NO_ARGS, do_sweep},
{(char *)"@switch", switch_sw, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_ARGV|CS_CMDARG|CS_NOINTERP|CS_STRIP,
do_switch},
{(char *)"@teleport", NULL, CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP, do_teleport},
{(char *)"@timewarp", warp_sw, CA_WIZARD,
0, CS_ONE_ARG|CS_INTERP, do_timewarp},
{(char *)"@toad", toad_sw, CA_WIZARD,
0, CS_TWO_ARG|CS_INTERP, do_toad},
{(char *)"@trigger", NULL, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_ARGV, do_trigger},
{(char *)"@unlink", NULL, CA_NO_SLAVE|CA_GBL_BUILD,
0, CS_ONE_ARG|CS_INTERP, do_unlink},
{(char *)"@unlock", lock_sw, CA_NO_SLAVE|CA_GBL_BUILD,
0, CS_ONE_ARG|CS_INTERP, do_unlock},
{(char *)"@verb", NULL, CA_GBL_INTERP|CA_NO_SLAVE,
0, CS_TWO_ARG|CS_ARGV|CS_INTERP|CS_STRIP, do_verb},
{(char *)"@wait", NULL, CA_GBL_INTERP,
0, CS_TWO_ARG|CS_CMDARG|CS_NOINTERP|CS_STRIP, do_wait},
{(char *)"@wall", wall_sw, CA_WIZARD,
SAY_SHOUT, CS_ONE_ARG|CS_INTERP, do_say},
{(char *)"@whereis", NULL, CA_NO_GUEST,
0, CS_ONE_ARG|CS_INTERP, do_whereis},
{(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 *)"give", NULL, CA_LOCATION|CA_NO_GUEST,
0, CS_TWO_ARG|CS_INTERP, do_give},
{(char *)"goto", goto_sw, CA_LOCATION,
0, CS_ONE_ARG|CS_INTERP, do_move},
{(char *)"gripe", NULL, 0,
SAY_GRIPE, CS_ONE_ARG, do_say},
{(char *)"help", NULL, 0,
HELP_HELP, CS_ONE_ARG, do_help},
{(char *)"inventory", NULL, 0,
LOOK_INVENTORY, CS_NO_ARGS, do_inventory},
{(char *)"kill", NULL, CA_NO_GUEST|CA_NO_SLAVE,
KILL_KILL, CS_TWO_ARG|CS_INTERP, do_kill},
{(char *)"leave", leave_sw, CA_LOCATION,
0, CS_NO_ARGS|CS_INTERP, do_leave},
{(char *)"look", NULL, CA_LOCATION,
LOOK_LOOK, CS_ONE_ARG|CS_INTERP, do_look},
{(char *)"news", NULL, 0,
HELP_NEWS, CS_ONE_ARG, do_help},
{(char *)"page", NULL, CA_NO_HAVEN|CA_NO_GAGGED,
0, CS_TWO_ARG|CS_INTERP, do_page},
{(char *)"pose", pose_sw, CA_LOCATION|CA_NO_GAGGED,
SAY_POSE, CS_ONE_ARG|CS_INTERP, do_say},
{(char *)"rob", NULL,
CA_DISABLED, /*NO_SLAVE|NO_GUEST|CONTENTS */
0, CS_ONE_ARG|CS_INTERP, do_rob},
{(char *)"say", NULL, CA_LOCATION|CA_NO_GAGGED,
SAY_SAY, CS_ONE_ARG|CS_INTERP, do_say},
{(char *)"score", NULL, 0,
LOOK_SCORE, CS_NO_ARGS, do_score},
{(char *)"slay", NULL, CA_WIZARD,
KILL_SLAY, CS_TWO_ARG|CS_INTERP, do_kill},
{(char *)"use", NULL, CA_NO_SLAVE|CA_GBL_INTERP,
0, CS_ONE_ARG|CS_INTERP, do_use},
{(char *)"version", NULL, 0,
0, CS_NO_ARGS, do_version},
{(char *)"whisper", NULL, CA_LOCATION|CA_NO_GAGGED,
PEMIT_WHISPER, CS_TWO_ARG|CS_INTERP, do_pemit},
{(char *)"wizhelp", NULL, CA_WIZARD,
HELP_WIZHELP, CS_ONE_ARG, do_help},
{(char *)"E", NULL,
CA_NO_GUEST|CA_LOCATION|CF_DARK|CA_NO_GAGGED,
SAY_PREFIX, CS_ONE_ARG|CS_INTERP, do_say},
{(char *)"F", NULL,
CA_NO_SLAVE|CA_GBL_INTERP|CF_DARK,
0, CS_ONE_ARG|CS_INTERP|CS_CMDARG, do_force_prefixed},
{(char *)"P", NULL,
CA_LOCATION|CF_DARK|CA_NO_GAGGED,
SAY_PREFIX, CS_ONE_ARG|CS_INTERP, do_say},
{(char *)"S", NULL,
CA_LOCATION|CF_DARK|CA_NO_GAGGED,
SAY_PREFIX, CS_ONE_ARG|CS_INTERP, do_say},
{(char *)"V", NULL,
CA_NO_GUEST|CA_NO_SLAVE|CF_DARK,
0, CS_TWO_ARG, do_setvattr},
{(char *)NULL, NULL, 0,
0, 0, NULL}};
CMDENT *prefix_cmds[256];
void init_cmdtab()
{
CMDENT *cp;
ATTR *ap;
char *p, *q;
int anum;
char *cbuff;
hashinit(&mudstate.command_htab, 217);
/* Load attribute-setting commands */
cbuff = alloc_sbuf("init_cmdtab");
for (ap=attr; ap->name; ap++) {
if ((ap->flags & AF_NOCMD) == 0) {
p=cbuff;
*p++='@';
for (q=(char *)ap->name; *q; p++,q++) *p=ToLower(*q);
*p='\0';
cp = (CMDENT *)malloc(sizeof(CMDENT));
cp->cmdname = (char *)strsave(cbuff);
cp->perms = CA_NO_GUEST|CA_NO_SLAVE;
if (ap->flags & (AF_WIZARD|AF_MDARK)) {
cp->perms |= CA_WIZARD;
}
cp->extra = ap->number;
cp->callseq = CS_TWO_ARG;
cp->handler = &do_setattr;
hashadd(cp->cmdname, (int *)cp, &mudstate.command_htab);
}
}
free_sbuf(cbuff);
/* Load the builtin commands */
for (cp=command_table; cp->cmdname; cp++)
hashadd(cp->cmdname, (int *)cp, &mudstate.command_htab);
/* 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 (anum=0; anum<256; anum++) prefix_cmds[anum] = NULL;
prefix_cmds['"'] = (CMDENT *)hashfind((char *)"S",
&mudstate.command_htab);
prefix_cmds[':'] = (CMDENT *)hashfind((char *)"P",
&mudstate.command_htab);
prefix_cmds[';'] = (CMDENT *)hashfind((char *)"P",
&mudstate.command_htab);
prefix_cmds['\\'] = (CMDENT *)hashfind((char *)"E",
&mudstate.command_htab);
prefix_cmds['#'] = (CMDENT *)hashfind((char *)"F",
&mudstate.command_htab);
prefix_cmds['&'] = (CMDENT *)hashfind((char *)"V",
&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)
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_IMMORTAL))
{if (Immortal(player)) succ++; else fail++;}
if ((succ == 0) && (mask & CA_BUILDER))
{if (Builder(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_GAGGED) && Gagged(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;
char *args[MAX_ARG];
int nargs, i, fail, interp, key, xkey;
#define Protect(x) (cmdp->perms & x)
/* Perform object type checks. */
fail = 0;
if (Protect(CA_LOCATION) & !Has_location(player)) fail++;
if (Protect(CA_CONTENTS) & !Has_contents(player)) fail++;
if (Protect(CA_PLAYER) & (Typeof(player) != TYPE_PLAYER)) fail++;
if (fail > 0) {
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, "Permission denied.");
return;
}
/* Check global flags */
if (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 *)index(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 & SW_MULTIPLE)) {
if (i == 1) {
notify(player,
"Illegal combination of switches.");
return;
}
i = 1;
} else {
xkey &= ~SW_MULTIPLE;
}
key |= xkey;
switchp = buf1;
} while (buf1);
} else if (switchp) {
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) ||
!(interactive | (cmdp->callseq & CS_NOINTERP)))
interp = EV_EVAL|EV_STRIP;
else if (cmdp->callseq & CS_STRIP)
interp = EV_STRIP;
else
interp = 0;
switch (cmdp->callseq & CS_NARG_MASK) {
case CS_NO_ARGS: /* <cmd> (no args) */
(*(cmdp->handler))(player, cause, key);
break;
case CS_ONE_ARG: /* <cmd> <arg> */
/* If an unparsed command, just give it to the handler */
if (cmdp->callseq & CS_UNPARSE) {
(*(cmdp->handler))(player, unp_command);
break;
}
/* Interpret if necessary */
if (interp & EV_EVAL)
buf1 = exec(player, cause, interp|EV_FCHECK, arg,
cargs, ncargs);
else
buf1 = parse_to(&arg, '\0', interp);
/* Call the correct handler */
if (cmdp->callseq & CS_CMDARG) {
(*(cmdp->handler))(player, cause, key, buf1,
cargs, ncargs);
} else {
(*(cmdp->handler))(player, cause, key, buf1);
}
/* Free the buffer if one was allocated */
if (interp & EV_EVAL)
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 = exec(player, cause, EV_STRIP|EV_FCHECK, buf2,
cargs, ncargs);
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);
for (nargs=0; (nargs<MAX_ARG) && args[nargs]; nargs++) ;
/* Call the correct command handler */
if (cmdp->callseq & CS_CMDARG) {
(*(cmdp->handler))(player, cause, key,
buf1, args, nargs, cargs, ncargs);
} else {
(*(cmdp->handler))(player, cause, key,
buf1, args, nargs);
}
/* Free the argument buffers */
for (i=0; i<=nargs; i++)
if (args[i]) free_lbuf(args[i]);
} else {
/* Arg2 is normal style. Interpret if needed */
if (interp & EV_EVAL) {
buf2 = exec(player, cause, interp|EV_FCHECK,
arg, cargs, ncargs);
} else {
buf2 = parse_to(&arg, '\0',
interp|EV_STRIP_LS|EV_STRIP_TS);
}
/* Call the correct command handler */
if (cmdp->callseq & CS_CMDARG) {
(*(cmdp->handler))(player, cause, key,
buf1, buf2, cargs, ncargs);
} else {
(*(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 *command, char *args[], int nargs)
{
char *p, *q, *arg, *lcbuf, *slashp, *cmdsave;
int succ, aflags;
dbref exit, aowner;
CMDENT *cmdp;
/* Robustify player */
cmdsave = mudstate.debug_cmd;
mudstate.debug_cmd = (char *)"< process_command >";
if (!command) abort();
if (!Good_obj(player)) {
STARTLOG(LOG_BUGS,"CMD","PLYR")
lcbuf=alloc_mbuf("process_command.LOG.badplayer");
sprintf(lcbuf,"Bad player in process_command: %d",
player);
log_text(lcbuf);
free_mbuf(lcbuf);
ENDLOG
mudstate.debug_cmd = cmdsave;
return;
}
/* Make sure player isn't going or halted */
if ((Flags(player) & GOING) ||
(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;
}
STARTLOG(LOG_ALLCOMMANDS,"CMD","ALL")
log_name_and_loc(player);
lcbuf=alloc_lbuf("process_command.LOG.allcmds");
sprintf(lcbuf, " entered: '%s'", command);
log_text(lcbuf);
free_lbuf(lcbuf);
ENDLOG
/* Reset recursion limits */
mudstate.func_nest_lev = 0;
mudstate.func_invk_ctr = 0;
mudstate.ntfy_nest_lev = 0;
mudstate.lock_nest_lev = 0;
if (Flags(player) & VERBOSE)
notify(Owner(player), tprintf("%s] %s", Name(player), command));
/* Convert all newlines to spaces; we can't really handle newlines. */
p = q = command;
for (p = command; *p != '\0'; p++) {
if (*p == '\n') *p = ' '; /* convert newline to space */
if (*p != '\r') *q++ = *p; /* eat cr character */
}
*q = '\0';
/* Eat leading whitespace, and space-compress if configured */
while (*command && isspace(*command)) command++;
mudstate.debug_cmd = command;
if (mudconf.space_compress) {
p = q = command;
while (*p) {
while (*p && !isspace(*p))
*q++ = *p++; /* scan over word */
while (*p && isspace(*p)) p++; /* smash spaces */
if (*p) *q++ = ' '; /* separate words */
}
*q = '\0'; /* terminate string */
}
/* 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. */
if ((prefix_cmds[command[0]] != NULL) && command[0]) {
process_cmdent(prefix_cmds[command[0]], NULL, player, cause,
interactive, command, command, args, nargs);
mudstate.debug_cmd = cmdsave;
return;
}
/* Check for the HOME command */
if (string_compare(command, "home") == 0) {
do_move(player, cause, 0, "home");
mudstate.debug_cmd = cmdsave;
return;
}
/* Check for an exit name */
init_match(player, command, 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(player, command, 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 lcbuf after the lowercased
* command. */
lcbuf=alloc_lbuf("process_commands.LCbuf");
for (p=command,q=lcbuf; *p && !isspace(*p); p++,q++)
*q=ToLower(*p); /* Make lowercase command */
*q++='\0'; /* Terminate command */
while (*p && isspace(*p)) p++; /* Skip spaces before arg */
arg = q; /* Remember where arg starts */
while (*p) *q++ = *p++; /* Copy arg */
*q='\0'; /* Terminate arg */
/* Strip off any command switches and save them */
slashp = (char *)index(lcbuf, '/');
if (slashp)
*slashp++ = '\0';
/* Check for a builtin command (or an alias of a builtin command) */
cmdp = (CMDENT *)hashfind(lcbuf, &mudstate.command_htab);
if (cmdp != NULL) {
process_cmdent(cmdp, slashp, player, cause, interactive, arg,
command, args, nargs);
free_lbuf(lcbuf);
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. */
free_lbuf(lcbuf);
lcbuf = exec(player, cause, EV_EVAL|EV_FCHECK|EV_STRIP, command,
args, nargs);
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(lcbuf, p)) {
free_lbuf(lcbuf);
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(lcbuf, p)) {
free_lbuf(lcbuf);
free_lbuf(p);
do_enter_internal(player, exit, 0);
return;
}
}
free_lbuf(p);
}
}
/* Check for $-command matches on me */
if (mudconf.match_mine) {
if (((Typeof(player) != TYPE_PLAYER) ||
mudconf.match_mine_pl) &&
(atr_match(player, player, AMATCH_CMD, lcbuf, 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, lcbuf, 1);
if (atr_match(Location(player), player,
AMATCH_CMD, lcbuf, 1) > 0) {
succ++;
}
}
/* Check for $-command matches in my inventory */
if (Has_contents(player))
succ += list_check(Contents(player), player,
AMATCH_CMD, lcbuf, 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, lcbuf, 0);
if (atr_match(mudconf.master_room,
player, AMATCH_CMD, lcbuf, 0) > 0) {
succ++;
}
}
}
free_lbuf(lcbuf);
/* If we still didn't find anything, tell how to get help. */
if (!succ) {
notify(player, "Huh? (Type \"help\" for help.)");
STARTLOG(LOG_BADCOMMANDS,"CMD","BAD")
log_name_and_loc(player);
lcbuf=alloc_lbuf("process_commands.LOG.badcmd");
sprintf(lcbuf, " entered: '%s'", command);
log_text(lcbuf);
free_lbuf(lcbuf);
ENDLOG
}
mudstate.debug_cmd = cmdsave;
return;
}
/* ---------------------------------------------------------------------------
* powers_nametab: Extended powers table.
* IMPORTANT - Keep this table in sync with the POW_xxx #defines in externs.h
*/
NAMETAB powers_nametab[] = {
{(char *)"change_quotas", 3, CA_WIZARD, CA_WIZARD},
{(char *)"chown_anywhere", 6, CA_WIZARD, CA_GOD},
{(char *)"chown_mine", 7, CA_WIZARD, CA_WIZARD},
{(char *)"chown_others", 7, CA_WIZARD, CA_WIZARD},
{(char *)"chown_players", 7, CA_WIZARD, CA_GOD},
{(char *)"control_global", 2, CA_WIZARD, CA_WIZARD},
{(char *)"expanded_who", 3, CA_WIZARD, CA_WIZARD},
{(char *)"examine_global", 3, CA_WIZARD, CA_WIZARD|CA_IMMORTAL},
{(char *)"find_unfindable", 2, CA_WIZARD, CA_WIZARD|CA_IMMORTAL},
{(char *)"free_money", 6, CA_WIZARD, CA_WIZARD|CA_IMMORTAL},
{(char *)"free_quota", 6, CA_WIZARD, CA_WIZARD|CA_IMMORTAL},
{(char *)"grab_player", 1, CA_WIZARD, CA_WIZARD},
{(char *)"ignore_rst_flags", 1, CA_WIZARD, CA_WIZARD},
{(char *)"join_player", 1, CA_WIZARD, CA_WIZARD},
{(char *)"long_fingers", 1, CA_WIZARD, CA_WIZARD|CA_IMMORTAL},
{(char *)"no_boot", 4, CA_WIZARD, CA_GOD},
{(char *)"no_toad", 4, CA_WIZARD, CA_WIZARD},
{(char *)"rename_myself", 1, CA_WIZARD, CA_NO_GUEST|CA_NO_SLAVE},
{(char *)"see_admin_flags", 6, CA_WIZARD, CA_WIZARD},
{(char *)"see_all_queue", 6, CA_WIZARD, CA_WIZARD},
{(char *)"see_hidden", 5, CA_WIZARD, CA_WIZARD|CA_IMMORTAL},
{(char *)"see_inviz_attrs", 5, CA_WIZARD, CA_WIZARD},
{(char *)"see_maint_flags", 5, CA_WIZARD, CA_GOD},
{(char *)"set_admin_attrs", 11, CA_WIZARD, CA_WIZARD},
{(char *)"set_admin_flags", 11, CA_WIZARD, CA_WIZARD},
{(char *)"set_maint_attrs", 11, CA_WIZARD, CA_WIZARD},
{(char *)"set_maint_flags", 11, CA_WIZARD, CA_WIZARD},
{(char *)"stat_any", 3, CA_WIZARD, CA_WIZARD},
{(char *)"steal_money", 3, CA_WIZARD, CA_WIZARD},
{(char *)"tel_anywhere", 6, CA_WIZARD, CA_WIZARD},
{(char *)"tel_unrestricted", 6, CA_WIZARD, CA_GOD},
{(char *)"unkillable", 1, CA_WIZARD, CA_WIZARD|CA_IMMORTAL},
{ NULL, 0, 0, 0}};
/* ---------------------------------------------------------------------------
* list_cmdtable: List internal commands.
*/
static void list_cmdtable (dbref player)
{
CMDENT *cmdp;
char *buf, *bp, *cp;
buf=alloc_lbuf("list_cmdtable");
bp=buf;
for (cp=(char *)"Commands:"; *cp; cp++) *bp++ = *cp;
for (cmdp=command_table; 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)) {
*bp++ = ' ';
for (cp=(char *)(ap->name); *cp; cp++)
*bp++ = *cp;
}
}
*bp='\0';
notify(player, buf);
free_lbuf(buf);
}
/* ---------------------------------------------------------------------------
* list_flagtable: List available flags.
*/
static void list_flagtable (dbref player)
{
display_flagtab(player, player_flags, "Player flags:");
display_flagtab(player, thing_flags, "Thing flags:");
display_flagtab(player, room_flags, "Room flags:");
display_flagtab(player, exit_flags, "Exit flags:");
display_flagtab(player, gen_flags, "Common flags:");
return;
}
/* ---------------------------------------------------------------------------
* list_ntab_flags: List flags field of an ntab.
*/
static void list_ntab_flags (dbref player, NAMETAB *ntab, NAMETAB *flaglist)
{
char *buff;
NAMETAB *np;
buff=alloc_sbuf("list_attraccess");
for (np=ntab; np->name; np++) {
if (check_access(player, np->perm)) {
sprintf(buff,"%s:", np->name);
listset_nametab(player, flaglist,
np->flag, buff, 1);
}
}
free_sbuf(buff);
}
/* ---------------------------------------------------------------------------
* list_cmdaccess: List access commands.
*/
NAMETAB access_nametab[] = {
{(char *)"god", 2, CA_GOD, CA_GOD},
{(char *)"wizard", 3, CA_WIZARD, CA_WIZARD},
{(char *)"builder", 6, CA_WIZARD, CA_BUILDER},
{(char *)"immortal", 3, CA_WIZARD, CA_IMMORTAL},
{(char *)"robot", 2, CA_WIZARD, CA_ROBOT},
{(char *)"no_haven", 4, CA_PUBLIC, CA_NO_HAVEN},
{(char *)"no_robot", 4, CA_WIZARD, CA_NO_ROBOT},
{(char *)"no_gagged", 5, CA_WIZARD, CA_NO_GAGGED},
{(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 *)"global_build", 8, CA_PUBLIC, CA_GBL_BUILD},
{(char *)"global_interp", 8, CA_PUBLIC, CA_GBL_INTERP},
{(char *)"disabled", 4, CA_GOD, CA_DISABLED},
{(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 *)"dark", 4, CA_GOD, CF_DARK},
{ NULL, 0, 0, 0}};
static void list_cmdaccess (dbref player)
{
char *buff, *p, *q;
CMDENT *cmdp;
ATTR *ap;
buff=alloc_sbuf("list_cmdaccess");
for (cmdp=command_table; cmdp->cmdname; cmdp++) {
if (check_access(player, cmdp->perms)) {
if (!(cmdp->perms & CF_DARK)) {
sprintf(buff,"%s:", cmdp->cmdname);
listset_nametab(player, access_nametab,
cmdp->perms, buff, 1);
}
}
}
for (ap=attr; ap->name; ap++) {
p=buff;
*p++='@';
for (q=(char *)ap->name; *q; p++,q++) *p=ToLower(*q);
if (ap->flags & AF_NOCMD) continue;
*p='\0';
cmdp = (CMDENT *)hashfind(buff, &mudstate.command_htab);
if (cmdp == NULL) continue;
if (!check_access(player, cmdp->perms)) continue;
if (!(cmdp->perms & CF_DARK)) {
sprintf(buff,"%s:", cmdp->cmdname);
listset_nametab(player, access_nametab,
cmdp->perms, buff, 1);
}
}
free_sbuf(buff);
}
/* ---------------------------------------------------------------------------
* list_cmdswitches: List switches for commands.
*/
static void list_cmdswitches (dbref player)
{
char *buff;
CMDENT *cmdp;
buff=alloc_sbuf("list_cmdswitches");
for (cmdp=command_table; cmdp->cmdname; cmdp++) {
if (cmdp->switches) {
if (check_access(player, cmdp->perms)) {
if (!(cmdp->perms & CF_DARK)) {
sprintf(buff,"%s:", 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 *)"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_WIZARD, AF_NOCMD},
{(char *)"no_program", 4, CA_PUBLIC, AF_NOPROG},
{(char *)"private", 1, CA_PUBLIC, AF_ODARK},
{(char *)"wizard", 1, CA_PUBLIC, AF_WIZARD},
{ NULL, 0, 0, 0}};
NAMETAB indiv_attraccess_nametab[] = {
{(char *)"no_command", 1, CA_PUBLIC, AF_NOPROG},
{ 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)) {
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 int cf_modify_bits (int *vp, char *str, int extra, dbref player,
char *cmd);
extern void cf_log_notfound (dbref player, char *cmd, const char *thingname,
char *thing);
int cf_access (int *vp, char *str, int extra, dbref player, char *cmd)
{
CMDENT *cmdp;
char *ap;
int set_switch;
for (ap=str; *ap && !isspace(*ap) && (*ap!='/'); ap++);
if (*ap == '/') {
set_switch = 1;
*ap++ = '\0';
} else {
set_switch = 0;
if (*ap) *ap++ = '\0';
while (*ap && isspace(*ap)) ap++;
}
cmdp = (CMDENT *)hashfind(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: Chante command permissions for all attr-setting cmds.
*/
int cf_acmd_access (int *vp, char *str, int extra, dbref player, char *cmd)
{
CMDENT *cmdp;
ATTR *ap;
char *buff, *p, *q;
int failure, save;
buff=alloc_sbuf("cf_acmd_access");
for (ap=attr; ap->name; ap++) {
p=buff;
*p++='@';
for (q=(char *)ap->name; *q; p++,q++) *p=ToLower(*q);
*p='\0';
cmdp = (CMDENT *)hashfind(buff, &mudstate.command_htab);
if (cmdp != NULL) {
save = cmdp->perms;
failure = cf_modify_bits(&(cmdp->perms), str,
extra, player, cmd);
if (failure != 0) {
cmdp->perms = save;
free_sbuf(buff);
return -1;
}
}
}
free_sbuf(buff);
return 0;
}
/* ---------------------------------------------------------------------------
* cf_attr_access: Change access on an attribute.
*/
int cf_attr_access (int *vp, char *str, int extra, dbref player, char *cmd)
{
ATTR *ap;
char *sp;
for (sp=str; *sp && !isspace(*sp); sp++);
if (*sp) *sp++='\0';
while (*sp && isspace(*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.
*/
int cf_cmd_alias (int *vp, char *str, int extra, dbref player, char *cmd)
{
char *alias, *orig, *ap;
CMDENT *cmdp, *cmd2;
NAMETAB *nt;
int *hp;
alias = strtok(str, " \t=,");
orig = strtok(NULL, " \t=,");
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 *)hashfind(orig, (HASHTAB *)vp);
if (cmdp == 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 *)malloc(sizeof(CMDENT));
cmd2->cmdname = strsave(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;
hashadd(cmd2->cmdname, (int *)cmd2, (HASHTAB *)vp);
} else {
/* A normal (non-switch) alias */
hp = hashfind(orig, (HASHTAB *)vp);
if (hp == NULL) {
cf_log_notfound(player, cmd, "Entry", orig);
return -1;
}
hashadd(alias, hp, (HASHTAB *)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, TYPE_PLAYER);
roomb = decode_flags(player, mudconf.room_flags, TYPE_ROOM);
exitb = decode_flags(player, mudconf.exit_flags, TYPE_EXIT);
thingb = decode_flags(player, mudconf.thing_flags, TYPE_THING);
robotb = decode_flags(player, mudconf.robot_flags, TYPE_PLAYER);
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);
notify(player, buff);
free_lbuf(buff);
free_sbuf(playerb);
free_sbuf(roomb);
free_sbuf(exitb);
free_sbuf(thingb);
free_sbuf(robotb);
}
/* ---------------------------------------------------------------------------
* list_functable: List available functions.
*/
extern FUN flist[];
static void list_functable (dbref player)
{
FUN *fp;
char *buf, *bp, *cp;
buf=alloc_lbuf("list_functable");
bp=buf;
for (cp=(char *)"Functions:"; *cp; cp++) *bp++ = *cp;
for (fp=flist; fp->name; fp++) {
*bp++ = ' ';
for (cp=(char *)(fp->name); *cp; cp++)
*bp++ = *cp;
}
*bp='\0';
notify(player, buf);
free_lbuf(buf);
}
/* ---------------------------------------------------------------------------
* 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)
notify(player,
tprintf("Creating a new thing costs %d %d %s%s.",
mudconf.createmin,
coin_name(mudconf.createmin), buff));
else
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) {
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 {
notify(player,
tprintf("Killing costs between %d and %d %s.",
mudconf.killmin, mudconf.killmax,
mudconf.many_coins));
notify(player,
tprintf("You must spend %d %s to guarantee success.",
mudconf.killguarantee,
coin_name(mudconf.killguarantee)));
}
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)
notify(player,
tprintf("Each command run from the queue costs 1/%d %s.",
mudconf.machinecost, mudconf.one_coin));
if (mudconf.waitcost > 0) {
notify(player,
tprintf("A %d %s deposit is charged for putting a command on the queue.",
mudconf.waitcost, mudconf.one_coin));
notify(player, "The deposit is refunded when the command is run or canceled.");
}
if (mudconf.sacfactor == 0)
sprintf(buff, "%d", mudconf.sacadjust);
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);
}
notify(player, tprintf("The value of an object is %s.", buff));
if (mudconf.clone_copy_cost)
notify(player, "The default value of cloned objects is the value of the original object.");
else
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 const char *ud[] = {"Down", "Up"};
static void list_options (dbref player)
{
char *buff;
if (mudconf.quotas)
notify(player, "Building quotas are enforced.");
if (mudconf.sac_dest)
notify(player, "Objects sacrificed in temples are @destroyed automatically.");
if (!mudconf.robot_speak)
notify(player, "Robots are not allowed to speak in public areas.");
if (mudconf.player_listen)
notify(player, "The @Listen/@Ahear attribute set works on player objects.");
if (mudconf.ex_flags)
notify(player, "The 'examine' command lists the flag names for the object's flags.");
if (!mudconf.quiet_look)
notify(player, "The 'look' command shows visible attributes in addition to the description.");
if (mudconf.see_own_dark)
notify(player, "The 'look' command lists DARK objects owned by you.");
if (!mudconf.dark_sleepers)
notify(player, "The 'look' command shows disconnected players.");
if (!mudconf.quiet_whisper)
notify(player, "The 'whisper' command lets others in the room with you know you whispered.");
if (mudconf.pemit_players)
notify(player, "The '@pemit' command may be used to emit to faraway players.");
if (mudconf.whereis_notify)
notify(player, "The '@whereis' command notifies its target that you located them.");
if (mudconf.pub_flags)
notify(player, "The 'flags()' function will return the flags of any object.");
if (mudconf.read_rem_desc)
notify(player, "The 'get()' function will return the description of faraway objects,");
if (mudconf.read_rem_name)
notify(player, "The 'name()' function will return the name of faraway objects.");
notify(player,
tprintf("The default switch for the '@switch' command is %s.",
switchd[mudconf.switch_df_all]));
notify(player,
tprintf("The default switch for the 'examine' command is %s.",
examd[mudconf.exam_public]));
if (mudconf.sweep_dark)
notify(player, "Players may @sweep dark locations.");
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)
notify(player, "Objects other than players search themselves for $-commands.");
else
notify(player, "All objects search themselves for $-commands.");
}
if (!Wizard(player))
return;
buff = alloc_mbuf("list_options");
notify(player,
tprintf("%d commands are run from the queue when there is no net activity.",
mudconf.queue_chunk));
notify(player,
tprintf("%d commands are run from the queue when there is net activity.",
mudconf.active_q_chunk));
if (mudconf.idle_wiz_dark)
notify(player, "Wizards idle for longer than the default timeout are automatically set DARK.");
if (mudconf.fork_dump) {
notify(player, "Database dumps are performed by a fork()ed process.");
if (mudconf.fork_vfork)
notify(player, "The 'vfork()' call is used to perform the fork.");
}
if (mudconf.max_players >= 0)
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';
notify(player,
tprintf("New players are given %d %s%s to start with.",
mudconf.paystart, mudconf.many_coins));
notify(player,
tprintf("Players are given %d %s each day they connect.",
mudconf.paycheck, mudconf.many_coins));
notify(player,
tprintf("Earning money is difficult if you have more than %d %s.",
mudconf.paylimit, mudconf.many_coins));
if (mudconf.payfind > 0)
notify(player,
tprintf("Players have a 1 in %d chance of finding a %s each time they move.",
mudconf.payfind, mudconf.one_coin));
notify(player,
tprintf("The head of the object freelist is #%d.",
mudstate.freelist));
sprintf(buff, "Intervals: Dump...%d Clean...%d Idlecheck...%d Rwho...%d",
mudconf.dump_interval, mudconf.check_interval,
mudconf.idle_interval, mudconf.rwho_interval);
notify(player, buff);
sprintf(buff, "Timers: Dump...%d Clean...%d Idlecheck...%d Rwho...%d",
mudstate.dump_counter, mudstate.check_counter,
mudstate.idle_counter, mudstate.rwho_counter);
notify(player, buff);
sprintf(buff, "Timeouts: Idle...%d Connect...%d Tries...%d",
mudconf.idle_timeout, mudconf.conn_timeout,
mudconf.retry_limit);
notify(player, buff);
sprintf(buff, "Scheduling: Timeslice...%d Max_Quota...%d Increment...%d",
mudconf.timeslice, mudconf.cmd_quota_max,
mudconf.cmd_quota_incr);
notify(player, buff);
sprintf(buff, "Compression: Strings...%s Spaces...%s Savefiles...%s",
ed[mudconf.intern_comp], ed[mudconf.space_compress],
ed[mudconf.compress_db]);
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);
notify(player, buff);
sprintf(buff, "Rwho: Host...%s Port...%d Connection...%s Transmit...%s",
mudconf.rwho_host, mudconf.rwho_info_port,
ud[mudstate.rwho_on], ed[mudconf.rwho_transmit]);
notify(player, buff);
sprintf(buff, "Misc: GuestChar...#%d IdleQueueChunk...%d ActiveQueueChunk...%d CompactChunk...%d GdbmCache...%d Master_room...#%d",
mudconf.guest_char, mudconf.queue_chunk, mudconf.active_q_chunk,
mudconf.garbage_chunk, mudconf.gdbm_cache_size,
mudconf.master_room);
notify(player, buff);
free_mbuf(buff);
}
/* ---------------------------------------------------------------------------
* list_vattrs: List user-defined attributes
*/
static void list_vattrs (dbref player)
{
VATTR *va;
int na, nf;
char *buff;
buff = alloc_lbuf("list_vattrs");
notify(player, "--- User-Defined Attributes ---");
for (va=mudstate.user_attrs,na=0; va; va=va->next,na++) {
if (!(va->flags & AF_DELETED)) {
sprintf(buff, "%s(%d):", va->name, va->number);
listset_nametab(player, attraccess_nametab, va->flags,
buff, 1);
}
}
notify(player, "--- Freed Attributes ---");
for (va=mudstate.user_attr_free,nf=0; va; va=va->next,nf++) {
notify(player, tprintf("%d", va->number));
}
notify(player, tprintf("%d attributes, %d freed attributes, next=%d",
na, nf, mudstate.attr_next));
free_lbuf(buff);
}
/* ---------------------------------------------------------------------------
* list_hashstats: List information from hash tables
*/
static void list_hashstat (dbref player, const char *tab_name, HASHTAB *htab)
{
char *buff;
buff = hashinfo(tab_name, htab);
notify(player, buff);
free_mbuf(buff);
}
static void list_nhashstat (dbref player, const char *tab_name, NHSHTAB *htab)
{
char *buff;
buff = nhashinfo(tab_name, htab);
notify(player, buff);
free_mbuf(buff);
}
static void list_hashstats (dbref player)
{
notify(player, "Hash Stats Size Entries Deleted Empty 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, "Player flags", &mudstate.p_flags_htab);
list_hashstat(player, "Thing flags", &mudstate.t_flags_htab);
list_hashstat(player, "Room flags", &mudstate.r_flags_htab);
list_hashstat(player, "Exit flags", &mudstate.e_flags_htab);
list_hashstat(player, "Attr names", &mudstate.attr_name_htab);
list_nhashstat(player, "Attr numbers", &mudstate.attr_num_htab);
list_hashstat(player, "VAttr names", &mudstate.vattr_name_htab);
list_nhashstat(player, "VAttr numbers", &mudstate.vattr_num_htab);
list_hashstat(player, "Player Names", &mudstate.player_htab);
list_nhashstat(player, "Net Descriptors", &mudstate.desc_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);
}
/* These are from 'udb_cache.c'. */
extern time_t cs_ltime;
extern int cs_writes; /* total writes */
extern int cs_reads; /* total reads */
extern int cs_dbreads; /* total read-throughs */
extern int cs_dbwrites; /* total write-throughs */
extern int cs_dels; /* total deletes */
extern int cs_checks; /* total checks */
extern int cs_rhits; /* total reads filled from cache */
extern int cs_ahits; /* total reads filled active cache */
extern int cs_whits; /* total writes to dirty cache */
extern int cs_fails; /* attempts to grab nonexistent */
extern int cs_resets; /* total cache resets */
extern int cs_syncs; /* total cache syncs */
extern int cs_objects; /* total cache size */
/* ---------------------------------------------------------------------------
* list_db_stats: Get useful info from the DB layer about hash stats, etc.
*/
static void list_db_stats (dbref player)
{
notify (player,
tprintf ("DB Cache Stats Writes Reads (over %d seconds)",
time(0) - cs_ltime));
notify (player, tprintf ("Calls %12d%12d", cs_writes, cs_reads));
notify (player, tprintf ("Cache Hits %12d%12d (%d in active cache)",
cs_whits, cs_rhits, cs_ahits));
notify (player, tprintf ("I/O %12d%12d",
cs_dbwrites, cs_dbreads));
notify (player, tprintf("\nDeletes %12d", cs_dels));
notify (player, tprintf("Checks %12d", cs_checks));
notify (player, tprintf("Resets %12d", cs_resets));
notify (player, tprintf("Syncs %12d", cs_syncs));
notify (player, tprintf("Cache Size %12d", cs_objects));
}
/* ---------------------------------------------------------------------------
* list_process: List local resource usage stats of the mush process.
* Adapted from code by Claudius@PythonMUCK,
* posted to the net by Howard/Dark_Lord.
*/
static void list_process (dbref player)
{
int pid, psize, ixrss, idrss, isrss, curr, last, dur;
struct rusage usage;
pid=getpid();
psize=getpagesize();
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;
}
/* Go display everything */
notify(player,
tprintf("Process ID: %10d %10d bytes per page",
pid, psize));
notify(player,
tprintf("Time used: %10d user %10d sys",
usage.ru_utime.tv_sec, usage.ru_stime.tv_sec));
/* notify(player,
tprintf("Resident mem:%10d shared %10d private%10d stack",
ixrss, idrss, isrss)); */
notify(player,
tprintf("Integral mem:%10d shared %10d private%10d stack",
usage.ru_ixrss, usage.ru_idrss, usage.ru_isrss));
notify(player,
tprintf("Max res mem: %10d pages %10d bytes",
usage.ru_maxrss, (usage.ru_maxrss * psize)));
notify(player,
tprintf("Page faults: %10d hard %10d soft %10d swapouts",
usage.ru_majflt, usage.ru_minflt, usage.ru_nswap));
notify(player,
tprintf("Disk I/O: %10d reads %10d writes",
usage.ru_inblock, usage.ru_oublock));
notify(player,
tprintf("Network I/O: %10d in %10d out",
usage.ru_msgrcv, usage.ru_msgsnd));
notify(player,
tprintf("Context swi: %10d vol %10d forced %10d sigs",
usage.ru_nvcsw, usage.ru_nivcsw, usage.ru_nsignals));
}
/* ---------------------------------------------------------------------------
* 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 /* GAC 4/6/92 */
#define LIST_PROCESS 21
#define LIST_BADNAMES 22
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 *)"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:
list_flagtable(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:
list_ntab_flags(player, powers_nametab, access_nametab);
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;
default:
display_nametab(player, list_names,
(char *)"Unknown option. Use one of:", 1);
}
}
/* ---------------------------------------------------------------------------
* do_list_file: List contents of message file.
*/
#define LISTF_GUEST 1
#define LISTF_CONN 2
#define LISTF_CREG 3
#define LISTF_REGF 4
#define LISTF_MOTD 5
#define LISTF_WIZMOTD 6
#define LISTF_QUIT 7
#define LISTF_DOWN 8
#define LISTF_SITE 9
#define LISTF_CREA 10
#define LISTF_FULL 11
NAMETAB list_files[] = {
{(char *)"badsite_connect", 1, CA_WIZARD, LISTF_SITE},
{(char *)"connect", 2, CA_WIZARD, LISTF_CONN},
{(char *)"create_register", 2, CA_WIZARD, LISTF_REGF},
{(char *)"down", 1, CA_WIZARD, LISTF_DOWN},
{(char *)"full", 1, CA_WIZARD, LISTF_FULL},
{(char *)"guest_motd", 1, CA_WIZARD, LISTF_GUEST},
{(char *)"motd", 1, CA_WIZARD, LISTF_MOTD},
{(char *)"newuser", 1, CA_WIZARD, LISTF_CREA},
{(char *)"quit", 1, CA_WIZARD, LISTF_QUIT},
{(char *)"register_connect", 1, CA_WIZARD, LISTF_CREG},
{(char *)"wizard_motd", 1, CA_WIZARD, LISTF_WIZMOTD},
{ NULL, 0, 0, 0}};
void do_list_file (dbref player, dbref cause, int extra, char *arg)
{
int flagvalue;
FBLOCK *fb;
flagvalue = search_nametab(player, list_files, arg);
switch (flagvalue) {
case LISTF_GUEST: fb = mudstate.guest_fcache; break;
case LISTF_CONN: fb = mudstate.conn_fcache; break;
case LISTF_CREG: fb = mudstate.creg_fcache; break;
case LISTF_REGF: fb = mudstate.regf_fcache; break;
case LISTF_MOTD: fb = mudstate.motd_fcache; break;
case LISTF_WIZMOTD: fb = mudstate.wizmotd_fcache; break;
case LISTF_QUIT: fb = mudstate.quit_fcache; break;
case LISTF_DOWN: fb = mudstate.down_fcache; break;
case LISTF_SITE: fb = mudstate.site_fcache; break;
case LISTF_CREA: fb = mudstate.crea_fcache; break;
case LISTF_FULL: fb = mudstate.full_fcache; break;
default:
display_nametab(player, list_files,
(char *)"Unknown file. Use one of:", 1);
return;
}
fcache_send(player, fb);
}