/
teeny/db/
teeny/dbm/
teeny/doc/
teeny/includes/
#include <stdio.h>
#include <ctype.h>

#include "teeny.h"
#include "match.h"

/*
Copyright(C) 1990, Andrew Molitor, All Rights Reserved.
This software may be freely used, modified, and redistributed,
as long as this copyright message is left intact, and this
software is not used to develop any commercial product, or used
in any product that is provided on a pay-for-use basis.

No warranties whatsoever. This is not guaranteed to compile, nor,
in the event that it does compile to binaries, are these binaries
guaranteed to perform any function whatsoever.
*/

/*
	The basic command interpreter for TeenyMUD. A big switch. Bwah hah hah.
*/

/* Another nifty idea shamelessly stolen from TinyMUD */

#define Matched(s,l) {if(!stringprefix(cmd,(s))) goto l;}

/* A macro to instantly parse the command, given suitably set up pointers */

#define Parse {if(first != NULL) first_end[1] = '\0';}

handle_cmd(player,cmd)

int player;	/* Object number of the player doing this.  */
char *cmd;	/* The command, should be a single line, whitespace trimmed */

{
	char *first;		/* First char of arg 1*/
	char *first_end;	/* Terminate arg 1 at first_end[1] */
	char *second;		/* Same deal */
	char *p;
	int list,here;
	struct match *exlist;
	int count;
#ifdef LOGCOMMANDS
	char logwork[16];
#endif

	/* This is slightly wasteful, but what the hell. An extra pass */
	/* Isn't THAT expensive, and I'm feeling lazy. Cope. */

	p = cmd;
	while(*p){
		if(!isprint(*p)) *p = ' ';
		p++;
	}
	while(isspace(*cmd) && *cmd) cmd++;
	if(!(*cmd))
		return; /* There's no intelligent life here Jim. */

	lock_cache(); /* Lock up the cache so things stay in memory */

#ifdef LOGCOMMANDS
	write(2,"CMD: Plyr #",11);
	p = ty_itoa(logwork,player);
	*p++ = ' ';*p = '\0';
	write(2,logwork,(p-logwork));
	write(2,cmd,strlen(cmd));
	write(2,"\n",1);
#endif
	/* Check for hotwired single-char commands */

	if(*cmd == ':'){
		do_pose(player,cmd+1);
		return;
	}
	if(*cmd == '\"'){
		do_say(player,cmd+1);
		return;
	}

	/* Check a couple things. */

	if(strcmp(cmd,"home") == 0){
		do_home(player);
		return;
	}

	/* Is this an exit? If so, cope with it. */

	if(get_int_elt(player,LOC,&here) == -1){
		warning("handle_cmd", "bad location ref on player");
		notify_player(player,"I can't find your location!\n");
		return;
	}
	if(get_int_elt(here,EXITS,&list) == -1){
		warning("handle_cmd","bad exits list here.");
		do_huh(player);
	}

	if((exlist = match_exits(cmd,list,&count)) != NULL){

		/* Ok. We have a list of exits. Cope with 'em. */

		do_go_attempt(player,here,exlist);
		free_match_list(exlist);
		return;
	}

	/* Smash the command up, prepare to parse out args if required */

	first = second = first_end = NULL;

	p = cmd;
	while(!isspace(*p) && *p) p++;	/* Skip over the command */
	first = p;

	while(isspace(*p) && *p) p++;	/* Skip to arg 1 */
	*first = '\0';
	if(!(*p)){			/* There is no arg 1 */
		first = NULL;
		goto parse;
	}
	first = p;

	while(*p != '=' && *p) p++;	/* Skip to end of arg 1 */
	first_end = p-1;		/* Not the terminator, last char */
	if(!(*p))
		goto parse;

	/* Back first_end up. We don't like trailing whitespace */

	while(isspace(*first_end)) first_end--;

	p++;	/* Skip the '=' */
	while(isspace(*p) && *p) p++;	/* Skip to arg 2 */
	if(!(*p))
		goto parse;

	second = p;
	while(*p) p++;			/* Skip to end of arg 2 */
	p--;
	while(isspace(*p)) p--;		/* Back up over trailing whitespace. */
	p[1] = '\0';
	
	/* Go to it */
parse:

	switch(cmd[0]){

	case '@':
		handle_at_cmd(cmd+1,player,first,first_end,second);
		break;
	case 'd':
	case 'D':	/* drop */
		Matched("drop",boom);
		do_drop(player,first);
		break;
	case 'e':
	case 'E':	/* examine */
		Matched("examine",boom);
		do_examine(player,first);
		break;
	case 'g':
	case 'G':
		switch(cmd[1]){
		case 'e':         
		case 'E':	/* get */
			Matched("get",boom);
			do_take(player,first);
			break;
		case 'i':
		case 'I':	/* give */
			Matched("give",boom);
			Parse;
			do_give(player,first,second);
			break;
		case 'o':
		case 'O':	/* go */
			Matched("go",boom);
			do_go(player,first);
			break;
		case 'r':
		case 'R':	/* gripe */
			Matched("gripe",boom);
			notify_player(player
				,"Your complaint has been duly noted.\n");
			break;
		default:
			goto boom;
		}
		break;
	case 'h':
	case 'H':
		switch(cmd[1]){
		case 'e':
		case 'E':	/* help */
			Matched("help",boom);
			do_help(player);
			break;
		default:
			goto boom;
		}
		break;
	case 'i':
	case 'I':	/* inventory */
		Matched("inventory",boom);
		do_inventory(player);
		break;
	case 'k':
	case 'K':	/* kill */
		Matched("kill",boom);
		Parse;
		do_kill(player,first,second);
		break;
	case 'l':
	case 'L':	/* look */
		Matched("look",boom);
		do_look(player,first);
		break;
	case 'm':
	case 'M':	/* move */
		Matched("move",boom);
		do_go(player,first);
		break;
	case 'n':
	case 'N':	/* news */
		Matched("news",boom);
		do_news(player);
		break;
	case 'p':
	case 'P':	/* page */
		Matched("page",boom);
		do_page(player,first);
		break;
	case 'r':
	case 'R':
		switch(cmd[1]){
		case 'e':
		case 'E':	/* read */
			Matched("read",boom);
			do_look(player,first);
			break;
		case 'o':
		case 'O':	/* rob */
			Matched("rob",boom);
			do_rob(player,first);
			break;
		default:
			goto boom;
		}
		break;
	case 's':
	case 'S':
		switch(cmd[1]){
		case 'a':
		case 'A':	/* say */
			Matched("say",boom);
			do_say(player,first);
			break;
		case 'c':
		case 'C':	/* score */
			Matched("score",boom);
			do_score(player);
			break;
		default:
			goto boom;
		}
		break;
	case 't':
	case 'T':
		switch(cmd[1]){
		case 'a':
		case 'A':	/* take */
			Matched("take",boom);
			do_take(player,first);
			break;
		case 'h':
		case 'H':	/* throw */
			Matched("throw",boom);
			do_drop(player,first);
			break;
		default:
			goto boom;
		}
		break;
	case 'w':
	case 'W':	/* whisper */
		Matched("whisper",boom);
		Parse;
		do_whisper(player,first,second);
		break;
	default:
		goto boom;
	}

	if(mudstat() != DUMPING)
		unlock_cache();
	cache_trim(); /* This never hurts, and we must do it here */
	return;

boom:	/* no valid command, or something equally awful */

	do_huh(player);
	if(mudstat() != DUMPING)
		unlock_cache();
	cache_trim();
	return;
}

handle_at_cmd(cmd,player,first,first_end,second)

char *cmd;
int player;
char *first,*first_end,*second;

{
	switch(cmd[0]){
	case 'b':
	case 'B':	/* @boot */
		Matched("boot",atboom);
		do_boot(player,first);
		break;
	case 'c':
	case 'C':
		switch(cmd[1]){
		case 'h':
		case 'H':	/* @chown */
			Matched("chown",atboom);
			Parse;
			do_chown(player,first,second);
			break;
		case 'r':
		case 'R':	/* @create */
			Matched("create",atboom);
			Parse;
			do_create(player,first,second);
			break;
		default:
			goto atboom;
		}
		break;
	case 'd':
	case 'D':
		switch(cmd[1]){
		case 'i':
		case 'I':	/* @dig */
			Matched("dig",atboom);
			do_dig(player,first);
			break;
		case 'u':
		case 'U':	/* @dump */
			Matched("dump",atboom);
			do_dump(player);
			break;
		case 'e':
		case 'E':	/* @describe */
			Matched("describe",atboom);
			Parse;
			do_set_string(player,first,second,DESC);
			break;
		default:
			goto atboom;
		}
		break;
	case 'f':
	case 'F':
		switch(cmd[1]){
		case 'a':
		case 'A':	/* @fail */
			Matched("fail",atboom);
			Parse;
			do_set_string(player,first,second,FAIL);
			break;
		case 'o':
		case 'O':	/* @force */
			Matched("force",atboom);
			Parse;
			do_force(player,first,second);
			break;
		default:
			goto atboom;
		}
		break;
	case 'l':
	case 'L':
		switch(cmd[1]){
		case 'o':
		case 'O':	/* @lock */
			Matched("lock",atboom);
			Parse;
			do_lock(player,first,second);
			break;
		case 'i':
		case 'I':	/* @link */
			Matched("link",atboom);
			Parse;
			do_link(player,first,second);
			break;
		default:
			goto atboom;
		}
		break;
	case 'n':
	case 'N':
		switch(cmd[1]){
		case 'a':
		case 'A':	/* @name */
			Matched("name",atboom);
			Parse;
			do_set_string(player,first,second,NAME);
			break;
		case 'e':
		case 'E':	/* @newpassword */
			Matched("newpassword",atboom);
			Parse;
			do_newpassword(player,first,second);
			break;
		default:
			goto atboom;
		}
		break;
	case 'o':
	case 'O':
		switch(cmd[1]){
		case 'f':
		case 'F':	/* @ofail */
			Matched("ofail",atboom);
			Parse;
			do_set_string(player,first,second,OFAIL);
			break;
		case 'p':
		case 'P':	/* @open */
			Matched("open",atboom);
			Parse;
			do_open(player,first,second);
			break;
		case 's':
		case 'S':	/* @osuccess */
			Matched("osuccess",atboom);
			Parse;
			do_set_string(player,first,second,OSUC);
			break;
		default:
			goto atboom;
		}
		break;
	case 'p':
	case 'P':
		switch(cmd[1]){
		case 'a':
		case 'A':	/* @password */
			Matched("password",atboom);
			Parse;
			do_password(player,first,second);
			break;
		default:
			goto atboom;
		}
		break;
	case 'r':
	case 'R':	/* @recycle */
		Matched("recycle",atboom);
		do_recycle(player,first);
		break;
	case 's':
	case 'S':
		switch(cmd[1]){
		case 'e':
		case 'E':	/* @set */
			Matched("set",atboom);
			Parse;
			do_set(player,first,second);
			break;
		case 'h':
		case 'H':	/* @shutdown */
			Matched("shutdown",atboom);
			do_shutdown(player);
			break;
		case 't':
		case 'T':	/* @stats */
			Matched("stats",atboom);
			do_stats(player);
			break;
		case 'u':
		case 'U':	/* @success */
			Matched("success",atboom);
			Parse;
			do_set_string(player,first,second,SUC);
			break;
		default:
			goto atboom;
		}
		break;
	case 't':
	case 'T':
		switch(cmd[1]){
		case 'e':
		case 'E':	/* @teleport */
			Matched("teleport",atboom);
			Parse;
			do_teleport(player,first,second);
			break;
		case 'o':
		case 'O':	/* @toad */
			Matched("toad",atboom);
			do_toad(player,first);
			break;
		default:
			goto atboom;
		}
		break;
	case 'u':
	case 'U':
		if(stringprefix(cmd,"unlink")){		/* @unlink */
			do_unlink(player,first);
		} else if(stringprefix(cmd,"unlock")){	/* @unlock */
			do_unlock(player,first);
		} else {
			goto atboom;
		}
		break;
	case 'w':
	case 'W':	/* @wall */
		Matched("wall",atboom);
		do_wall(player,first);
		break;
	default:
		goto atboom;
	};

	return;
atboom: /* No valid command, or something equally awful */

	do_huh(player);
	return;
}