/
umud/DOC/
umud/DOC/examples/
umud/DOC/internals/
umud/DOC/wizard/
umud/MISC/
umud/MISC/dbchk/
umud/RWHO/rwhod/
/*
	Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

#ifndef	lint
static	char	RCSid[] = "$Header: /home/mjr/hacks/umud/RCS/cmd.c,v 1.8 91/10/22 11:29:33 mjr Exp $";
#endif


/* configure all options BEFORE including system stuff. */
#include	"config.h"

#ifndef VMS
#include	<sys/param.h>
#endif


#include	"mud.h"
#include	"cmd.h"
#include	"vars.h"

/* standard commands */
extern	int	cmd_build();
extern	int	cmd_do();
extern	int	cmd_drop();
extern	int	cmd_go();
extern	int	cmd_help();		/* in cmd.c (this file) */
extern	int	cmd__if();
extern	int	cmd_inv();
extern	int	cmd_look();
extern	int	cmd_NEWS();
extern	int	cmd_QUIT();
extern	int	cmd_WHO();		/* in tcpio.c (net-specific) */
extern	int	cmd_page();
extern	int	cmd_password();
extern	int	cmd__password();	/* wiz-only */
extern	int	cmd__rand();
extern	int	cmd_read();
extern	int	cmd_say();
extern	int	cmd_set();		/* in vars.c */
extern	int	cmd_unset();		/* in vars.c */
extern	int	cmd_take();
extern	int	cmd_telep();
extern	int	cmd_use();
extern	int	cmd__wall();
extern	int	cmd_which();
extern	int	cmd_whisper();
extern	int	cmd_destroy();
extern	int	cmd_examine();
/* wiz internal debug functions */
extern	int	cmd__dump();
extern	int	cmd__echo();
extern	int	cmd__force();
extern	int	cmd__cacheconfig();	/* in cache.c */
#ifdef COMMAND_STATS
extern	int	cmd__cmdstats();	/* in run.c */
#endif
extern	int	cmd__wizard();
#ifdef	CMD_LOWLEVEL_LIST
extern	int	cmd__ladd();
extern	int	cmd__ldel();
#endif
extern	int	cmd__mark();
extern	int	cmd__cronconfig();	/* in cron.c */
extern	int	cmd__mudconfig();	/* in mud.c */
extern	int	cmd__netconfig();	/* in tcpio.c or whatever net module */
#ifdef	CMD_LOWLEVEL_SET
extern	int	cmd__set();
extern	int	cmd__unset();
#endif



/*
MASTER command table. THIS IS SEARCHED LINEARLY, WHICH IS WHY YOU
SHOULD MAKE SURE THAT MOST FREQENTLY USED COMMANDS ARE NEAREST TO
THE TOP OF THE TABLE.

(linear search is faster in the case of a MUD than a binary search,
since we can predict that 90% of ops will fall between emote/say)
*/
static Cmd	ctab[] = {


{ /* blather something in a TinyMUD-like manner */
"say",			1,	CM_EXACT,		cmd_say,
	"say \"string\""
},


{ /* emote command - TinyMUD-like emote (do and emote are aliases) */
"do",			1,	CM_EXACT,		cmd_do,
	"do \"string\""
},


{ /* look around */
"look",			1,	CM_NOFLG,		cmd_look,
	"look [thing1] ..."
},


{ /* go */
"go",			2,	CM_FIXARG|CM_EXACT,	cmd_go,
	"go place"
},


{ /* whisper */
"whisper",		3,	CM_FIXARG,		cmd_whisper,
	"whisper player message"
},


{ /* page */
"page",			2,	CM_NOFLG,		cmd_page,
	"page player [message]"
},


{ /* echo back to user */
"_echo",		2,	CM_NOFLG,		cmd__echo,
	"_echo text"
},


{ /* inventory */
"inventory",		1,	CM_NOFLG,		cmd_inv,
	"inventory [thing] ..."
},


{ /* take */
"take",			2,	CM_NOFLG,		cmd_take,
	"take thing [thing2] ..."
},


{ /* read text off of something */
"read",			2,	CM_FIXARG,		cmd_read,
	"read [thing] ..."
},


{ /* get - an alias for take */
"get",			2,	CM_EXACT,		cmd_take,
	"get thing [thing2] ..."
},


{ /* drop */
"drop",			2,	CM_NOFLG,		cmd_drop,
	"drop thing [thing2] ..."
},


{ /* examine object(s) */
"examine",		1,	CM_NOFLG,		cmd_examine,
	"examine [thing1] ..."
},


{
"set",			2,	CM_EXACT,		cmd_set,
	"set thing [type] attribute value (or \"set help\" for help)"
},


{
"unset",		3,	CM_FIXARG,		cmd_unset,
	"unset thing attribute"
},


{ /* hold */
"hold",			1,	CM_EXACT,		cmd_use,
	"hold thing (or nothing to stop holding current object)"
},


{ /* use */
"use",			1,	CM_EXACT,		cmd_use,
	"use thing (or nothing to stop using current object)"
},


{ /* create a new ?? */
#ifdef	BUILD_WIZ_ONLY
"build",		2,	CM_PRIV,		cmd_build,
#else
"build",		2,	CM_NOFLG,		cmd_build,
#endif
	"build object-type [object-specific options] (or \"build help\")"
},


{ /* create a new (alias for build)?? */
#ifdef	BUILD_WIZ_ONLY
"create",		2,	CM_PRIV,		cmd_build,
#else
"create",		2,	CM_NOFLG,		cmd_build,
#endif
	"create object-type [object-specific options] (or \"create help\")"
},

{ /* create a new (alias for build)?? */
#ifdef	BUILD_WIZ_ONLY
"create",		2,	CM_PRIV,		cmd_build,
#else
"create",		2,	CM_NOFLG,		cmd_build,
#endif
	"create object-type [object-specific options] (or \"create help\")"
},


{ /* which */
"which",		2,	CM_NOFLG,		cmd_which,
	"which [object-type] thing-to-match"
},


{ /* randomly pick a command */
"_rand",		2,	CM_NOFLG,		cmd__rand,
	"_rand [cmd1] [cmd2] [...cmdN]"
},


{ /* conditional (of sorts) */
"_if",			2,	CM_NOFLG,		cmd__if,
	"_if boolean-expression cmd [\"else\" cmd]"
},


{ /* teleport */
"teleport",		3,	CM_FIXARG,		cmd_telep,
	"teleport [thing] [destination]"
},


{ /* destroy an object ; command name must match exactly */
#ifdef	BUILD_WIZ_ONLY
"destroy",	2,		CM_EXACT|CM_PRIV,	cmd_destroy,
#else
"destroy",	2,		CM_EXACT,		cmd_destroy,
#endif
	"destroy object-type object (or \"destroy help\")"
},


{ /* NEWS */
"NEWS",			1,	CM_NOFLG,		cmd_NEWS,
	"NEWS [action] [article] (or \"NEWS help\")"
},


{ /* QUIT command */
"QUIT",			1,	CM_EXACT|CM_NOWHERE,	cmd_QUIT,
	"QUIT"
},


{ /* WHO command */
"WHO",			1,	CM_NOWHERE,		cmd_WHO,
	"WHO [who] ..."
},


{ /* dump command list/summary */
"help",			1,	CM_NOWHERE,		cmd_help,
	"help [cmd] ..."
},


{ /* dump object to controlling terminal in OIF format */
"_dump",		2,	CM_NOFLG,		cmd__dump,
	"_dump objid"
},


{ /* submit a command as someone else */
"_force",		3,	CM_PRIV,		cmd__force,
	"_force who command"
},


{ /* shout */
"_wall",		1,	CM_PRIV,		cmd__wall,
	"_wall message"
},


{ /* set a thing's password */
"password",		3,	CM_FIXARG,		cmd_password,
	"password oldpassword newpassword"
},


{ /* wiz set a thing's password */
"_password",		3,	CM_FIXARG|CM_PRIV,	cmd__password,
	"_password thing password"
},


{ /* cache-specific commands [implementation dependent] */
"_cacheconfig",		2,	CM_PRIV,		cmd__cacheconfig,
	"_cacheconfig [options] (or \"_cacheconfig help\")"
},


{ /* permanent database specific commands [implementation dependent] */
"_dbconfig",		2,	CM_PRIV,		CMD__DBCONFIG,
	"_dbconfig [options] (or \"_dbconfig help\")"
},


{ /* output a text mark for 'bots. echo back first arg with an '@' */
"_mark",		1,	CM_NOFLG,		cmd__mark,
	"_mark \"string\""
},


#ifdef	CMD_LOWLEVEL_LIST
{ /* add the object id to the named list in the named object */
"_ladd",		4,	CM_PRIV|CM_FIXARG,	cmd__ladd,
	"_ladd object listname objectid "
},


{ /* drop the object id from the named list in the named object */
"_ldel",		4,	CM_PRIV|CM_FIXARG,	cmd__ldel,
	"_ldel object listname objectid "
},
#endif


{ /* mud server specific commands [somewhat implementation dependent] */
"_mudconfig",		2,	CM_PRIV|CM_NOWHERE,	cmd__mudconfig,
	"_mudconfig [options] (or \"_mudconfig help\")"
},


{ /* cron execution specific commands [somewhat implementation dependent] */
"_cronconfig",		2,	CM_PRIV|CM_NOWHERE,	cmd__cronconfig,
	"_cronconfig [options] (or \"_cronconfig help\")"
},


{ /* network layer specific commands [somewhat implementation dependent] */
"_netconfig",		2,	CM_PRIV,		cmd__netconfig,
	"_netconfig [options] (or \"_netconfig help\")"
},


#ifdef	CMD_LOWLEVEL_SET
{ /* set an attribute directly into an object - VERY LOW LEVEL! */
"_set",		5,		CM_PRIV|CM_FIXARG,	cmd__set,
	"_set objid vartype varname \"data\""
},


{ /* unset an attribute from an object - VERY LOW LEVEL! */
"_unset",	3,		CM_PRIV|CM_FIXARG,	cmd__unset,
	"_unset objid varname"
},
#endif


{ /* wizard management */
"_wizard",		2,	CM_NOFLG,		cmd__wizard,
	"_wizard [options] (or \"_wizard help\")"
},

#ifdef COMMAND_STATS
{ /* print command statistics */
"_cmdstats",		1,	CM_PRIV,		cmd__cmdstats,
	"_cmdstats"
},
#endif


/* list terminator */
0,0,0,0,0
};




Cmd	*
cmdlookup(s)
char	*s;
{
	Cmd	*p = ctab;
	int	x;

	x = strlen(s);

	while(p->name != (char *)0) {
		if((p->flgs & CM_EXACT) && *s == *p->name && !strcmp(s,p->name))
			return(p);
		if(!(p->flgs & CM_EXACT) && *s == *p->name && !strncmp(s,p->name,x))
			return(p);
		p++;
	}
	return(0);
}





/* ARGSUSED */
cmd_help(argc,argv,who,aswho)
int	argc;
char	*argv[];
char	*who;
char	*aswho;
{
	Cmd	*p = ctab;
	int	x;
	int	wiz;

	wiz = ut_flagged(who,var_wiz);

	if(argc <= 1) {
		while(p->name != (char *)0) {
			if(wiz || !(p->flgs & CM_PRIV))
				say(who,p->usage,"\n",(char *)0);
			p++;
		}
		return(0);
	}
	for(x = 1; x < argc; x++) {
		char	fnuf[MAXPATHLEN];
		char	*jnk;

		jnk = argv[x];
		while((jnk = index(jnk,'.')) != (char *)0) {
			if(*(jnk + 1) == '.') {
				say(who, "nice try: \"",argv[x],"\"\n",
			    	(char *)0);
				return(1);
			}
			jnk++;
		}

		if (strlen(argv[x]) >= MAXPATHLEN) {
			say(who, "impossible command: \"",argv[x],"\"\n",
			    (char *)0);
			continue;
		}
		sprintf(fnuf,"HELP/%s",argv[x]);

		if((p = cmdlookup(argv[x])) != (Cmd *)0) {
			if(wiz || !(p->flgs & CM_PRIV)) {
				say(who,"usage: ",p->usage,"\n",(char *)0);
			}
			if(say_file(who,fnuf))
				say(who,"no help file available.\n",(char *)0);
		} else {
			if(say_file(who,fnuf))
				say(who,"unknown command: \"",argv[x],"\"\n",(char *)0);
		}
	}
	return(0);
}