tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore.  All rights reserved. */
/* builtins.c,v 2.6 1995/06/13 00:22:33 dmoore Exp */
#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "db.h"
#include "params.h"
#include "buffer.h"
#include "externs.h"

#include "builtins.h"		/* Generated by mkbuiltin.sh */

/* Call everyone with the first arg, the second arg, and the whole line. */
typedef void (*comm_func)(const dbref, const char*, const char *, const char*);

struct command {
    const char *name;
    int min_match;
    comm_func func;
};

static struct command builtins[] = {
#include "builtintab.h"		/* Generated by mkcommandtab.sh */
};


static int commandcmp(const void *k, const void *d)
{
    const char *key = k;
    const struct command *data = d;

    /* Make uncase sensitive. */
    return muck_strnicmp(key, data->name, data->min_match);
}


static comm_func lookup_command(const char *key)
{
    struct command *result;

    result = bsearch(key, builtins, sizeof(builtins)/sizeof(struct command),
		     sizeof(struct command), commandcmp);
    if (result && muck_strprefix(result->name, key)) {
	return result->func;
    } else {
	return 0;
    }
}


/* This routine expands a leading /"/ or /:/ into /say / and /pose /.
   Always returns a pointer into a static buffer. */
static char *fix_cookies(const char *str)
{
    static Buffer buf;

    switch (*str) {
#include "cookies.h"		/* Generated from builtins/cookies. */
    default:
	Bufcpy(&buf, str);
	break;
    }

    return Buftext(&buf);
}


/* Returns a pointer to a static buffer which contains a copy of the
   everything after the first word of the command. */
static char *get_full_args(const char *command)
{
    static Buffer buf;
    const char *p = command;

    while (*p && !isspace(*p)) p++;
    if (*p) p++;

    Bufcpy(&buf, p);
    return Buftext(&buf);
}


/* Splits a string into three parts.  The command (first word),
   and two arguments (seperated by '=').  Sets arg1 and arg2 to
   point to the appropriate places.  Works entirely within the
   string passed via command. */
static void split_args(char *command, char **arg1, char **arg2)
{
    char *p = command;
    char *q;

    *arg1 = "";
    *arg2 = "";

    if (!p || !*p) return;

    /* Skip to first space, and truncate off as command. */
    while (*p && !isspace(*p)) p++;
    if (!*p) return;
    *p++ = '\0';

    while (*p && isspace(*p)) p++; /* Eat some spaces. */
    *arg1 = p;			/* Mark arg1 start. */

    /* Skip to '=' and truncate off arg1. */
    while (*p && (*p != ARG_DELIMITER)) p++;
    q = p;
    if (*p) {
	/* There is an arg2. */
	*p++ = '\0';
	while (*p && isspace(*p)) p++; /* eat some spaces. */
	*arg2 = p;		/* Mark arg2 start. */
    }

    /* Strip trailing spaces from arg1. */
    for (q--; isspace(*q); q--) *q = '\0';
}



void process_command(const dbref player, const char *comm, int comm_len)
{
    char *command, *arg1, *arg2, *full_args;
    comm_func func;

    if (!comm) {
	/* Should never happen. */
	log_status("FATAL: process_command was called with a null string.");
	panic("null string sent to process_command");
    }

#ifdef LOG_WIZARD_COMMANDS
    if (Wizard(player) && !HasFlag(player, IN_EDITOR)) {
	dbref loc = GetLoc(player);
	log_command("%u in %u:%s %s", player, player, loc, loc,
		    HasFlag(player, IN_PROGRAM) ? " [interactive]" : "",
		    comm);
    }
#endif /* LOG_WIZARD_COMMANDS */
#ifdef LOG_COMMANDS
    if (!HasFlag(player, IN_EDITOR)) {
	dbref loc = GetLoc(player);
	log_command("%u in %u:%s %s", player, player, loc, loc,
		    HasFlag(player, IN_PROGRAM) ? " [interactive]" : "",
		    comm);
    }
#endif /* LOG_COMMANDS */
#ifdef LOG_LAST_COMMAND
    if (!HasFlag(player, IN_EDITOR)) {
	dbref loc = GetLoc(player);
	log_last_command("%u in %u:%s %s", player, player, GetOwner(loc), loc,
			 HasFlag(player, IN_PROGRAM) ? " [interactive]" : "",
			 comm);
    }
#endif /* LOG_LAST_COMMAND */

    if (HasFlag(player, IN_EDITOR)) {
	editor(player, comm, comm_len);
	return;
    }

    if (HasFlag(player, IN_PROGRAM)) {
	interactive(player, comm);
	return;
    }
    
    /* Eat any leading white space. */
    while (*comm && isspace(*comm)) comm++;

    command = fix_cookies(comm);

    if (try_move(player, command)) {
	/* Exact exit match. */
	return;
    }

    full_args = get_full_args(command);
    split_args(command, &arg1, &arg2);

    func = lookup_command(command);
    if (func) {
	/* Command is a known builtin. */
	func(player, arg1, arg2, full_args);
	return;
    }

    /* Only get here if we couldn't match an exit, and it's not builtin. */
    notify(player, "Huh?  (Type \"help\" for help.)");

#ifdef LOG_FAILED_COMMANDS
    if (!controls(player, GetLoc(player), 0)) {
	dbref loc = GetLoc(player);
	dbref owner = GetOwner(loc);
	log_status("HUH: from %u in %u[%u]: %s",
		   player, player, loc, loc, owner, owner, comm);
    }
#endif /* LOG_FAILED_COMMANDS */
}