untermud/DOC/
untermud/DOC/U/
untermud/DOC/U/U-examples/
untermud/DOC/internals/
untermud/DOC/wizard/
untermud/MISC/
untermud/MISC/dbchk/
untermud/RWHO/
untermud/RWHO/rwhod/
The compleat hacker's guide to adding commands to the UnterMUD server:
----------------------------------------------------------------------

	First off, figure out what you're trying to do, and see if there
is a command that already exists that does something remotely like it.
That's probably a good place to start. Take a look in the CMD directory,
and at least glance through the various command modules.

	The first thing that should leap to your attention is that all
the commands are called with the following interface:

cmd_say(argc,argv,who,aswho)

	Where argc is an integer, argv is an array of string pointers,
who is a string pointer and aswho is a string pointer. Basically, each
command is VERY much like a little standalone UNIX program, having its
own argc and null-terminated argv. In addition to that, there is the
object-id of the caller ("who") and the permissions object-id of the
caller ("aswho") in case the command is being called setuid.

	All you need to remember about "who" and "aswho" are the following
three simple facts:
	1) "who" is the person you should send all relevant output to.
	2) "aswho" is the object-id you should use for all permissions
		related things, whatever they may be.
	3) WHATEVER YOU DO, DO NOT MODIFY "who" OR "aswho", THEY ARE
		POINTERS OUTSIDE OF THE SPACE YOU ARE PERMITTED TO
		ALTER! Sorry to shout, but typically "who" may be
		a pointer straight back into some private buffer in
		the I/O layer, and if you skank with it, you've just
		literally changed the ID of the connected player.

	The argc and argv that are passed to each command are in private
space somewhere in the stack, and you can feel perfectly free to change
them, or re-point the argv[] pointers, if you like, as long as you don't
overrun buffers and so forth. If you treat your argv/argc with the care
that any sane person shows a UNIX argv/argc, you'll be OK.

	Anyhow, once you've figured out what you want to do, and looked
at some of the other commands, now take a look at some of the code in
objutil.c and maybe match.c - the idea here is to avoid replicating
loads of code if you can. Small is good. The tricky decision comes when
you're writing a command that will do a lot of modification to a bunch
of objects. Using the higher-level functions in objutil.c may be a
lot easier, but if you're going to make a lot of changes to a single
object, or you're going to be doing something really trick, you may
have to modify the object manually, by using cache_get() to get a
pointer to it, then using objsetattr(), objattr() and so on, and then
using cache_put() when you're done. IF YOU DON'T USE CACHE_PUT after
YOU HAVE CHANGED AN OBJECT IT WILL NOT GET UPDATED. Sorry to shout,
but that's important. If you just want to examine an object and NOT
change it, you don't need to use cache_put() afterwards. If you wind
up repeatedly performing the same set of operations on an object,
think about the interface to that set of operations and try to make
it generally useful and put it in objutil.c. No sense in having to
make everyone else rewrite code.

	Next tricky bit: if your command requires access to internal
data structures in either the network module, the cache, the db, or
the main MUD server module, DON'T put it in CMD, put it in the module.
This may be a pain, but it's necessary. If you write a TCP/IP specific
command, it should be isolated with the other TCP/IP specific code.
More importantly, WHATEVER YOU DO, DON'T DECLARE YOUR COMMAND IN ANY
OF THE HEADER FILES. The idea behind UnterMUD is to make it easy to
snap commands in and out, and having extraneous references to them
will get you beaten to death with a tire iron.

	WHEN YOU CODE YOUR COMMAND, KEEP EVERYTHING STATIC TO THAT
	----------------------------------------------------------
ONE FILE, OR YOU WILL BE SHOT.
------------------------------

	Ok, so now your command, whatever it is, is written. Take a
look at cmd.c and cmd.h and figure out how the Cmd struct is laid
out. It's pretty simple, really. Then make a forward declaration in
cmd.c, and an entry into the command table - please be so kind as
to #ifdef them if you are not sure everyone's going to be dying to
use your new command. Add the command file to the Makefile in CMD,
and it'll be compiled into the library. If someone turns the #ifdefs
on in cmd.c, suddenly your command will be a part of their environment.

	Please, for the sake of reason, try to do sensible things
with command parsing inside your command - IE: don't use UNIX-like
command flags in once place, and VMS-like slash delimiters in
another. In fact, don't try to do command delimiters at all, if
you can help it. It's my experience that tree-structured switches
(see the "build" command, for example) are easier to understand
anyhow. Besides, this is a game, not an operating system. It should
be deleted before it starts to look like an operating system.

	TEST EVERYTHING THOROUGHLY BEFORE YOU DARE RELEASE IT.
	------------------------------------------------------

mjr. '91