lpmoo-1.2/etc/
lpmoo-1.2/mudlib/
lpmoo-1.2/mudlib/etc/
lpmoo-1.2/mudlib/include/
lpmoo-1.2/mudlib/include/moo/
lpmoo-1.2/mudlib/lpc/
lpmoo-1.2/mudlib/std/auto/
lpmoo-1.2/mudlib/std/bfuns/
/*
 * NAME:	verb.c
 * DESCRIPTION:	inherited by all runtime MOO verb objects
 */

# define DEBUG  0

inherit "/std/core";
inherit "/std/data";
inherit "/std/bfuns";
inherit "/std/kfuns";
inherit "/std/string";

# if DEBUG
inherit "/std/vartext";
# else
# define var2str(arg)  ""
# endif

# include <objects.h>
# include <moo/data.h>
# include <moo/perms.h>
# include <moo/verb.h>

private	int	refs;		/* references to this object */
private	string	source;		/* tokenized source code for this verb */

	int	lineno;		/* current MOO source line number */

/*
 * NAME:	set_source()
 * DESCRIPTION:	receive source code for this verb
 */
void set_source(string code)
{
  source = code;
}

/*
 * NAME:	get_source()
 * DESCRIPTION:	return the source code for this verb
 */
string *get_source(int full_paren, int indent)
{
  return explode(DETOKEN->main(source, full_paren, indent), "\n");
}

/*
 * NAME:	dump_source()
 * DESCRIPTION:	return tokenized verb source (debugging)
 */
string dump_source(void)
{
  return " " + source;
}

/*
 * NAME:	ref()
 * DESCRIPTION:	create a reference to this object
 */
void ref(void)
{
  ++refs;
}

/*
 * NAME:	del()
 * DESCRIPTION:	delete a reference to this object; if last, self-destruct
 */
void del(void)
{
  if (! --refs)
    destruct_object(this_object());
}

/*
 * NAME:	get_lineno()
 * DESCRIPTION:	return the current MOO source line number
 */
int get_lineno(void)
{
  return lineno;
}

/*
 * NAME:	slist()
 * DESCRIPTION:	construct a spliced list value
 */
static varargs
MOOVAL slist(mixed *info, int *splices, MOOVAL elts...)
{
  int i;

  for (i = sizeof(splices); i--; )
    {
      int index;
      MOOVAL elt;

      elt = elts[index = splices[i]];
      if (! LSTP(elt))
	return RAISE(E_TYPE);

      elts = elts[.. index - 1] + elt + elts[index + 1 ..];
    }

  return LST(elts);
}

/*
 * NAME:	table()
 * DESCRIPTION:	construct a table value (with splices)
 */
static varargs
MOOVAL table(mixed *info, string splices, MOOVAL elts...)
{
  mapping table;
  int i;

  for (table = TNEW(), i = sizeof(elts); i; i -= 2)
    {
      MOOVAL key, value;

      key = elts[i - 2];

      if (splices && splices[i / 2 - 1] == '@')
	{
	  if (! TBLP(key))
	    return RAISE(E_TYPE);

	  TMERGE(table, TBLVAL(key));
	  continue;
	}

      value = elts[i - 1];

      TINSERT(table, key, value);
    }

  return TBL(table);
}

/*
 * NAME:	ambaggr()
 * DESCRIPTION:	construct an ambiguous aggregate (list or table, all splices)
 */
static varargs
MOOVAL ambaggr(mixed *info, MOOVAL elts...)
{
  mapping table;
  MOOVAL *list, elt;
  int i, type;

  for (table = TNEW(), list = LNEW(), i = sizeof(elts); i--; )
    {
      elt = elts[i];

      if (LSTP(elt))
	{
	  if (type == T_TBL)
	    return RAISE(E_TYPE);

	  type = T_LST;
	  elts = elts[.. i - 1] + elt + elts[i + 1 ..];
	}
      else if (TBLP(elt))
	{
	  if (type == T_LST)
	    return RAISE(E_TYPE);

	  type = T_TBL;
	  TMERGE(table, TBLVAL(elt));
	}
      else
	return RAISE(E_TYPE);
    }

  if (type == T_LST)
    return LST(elts);
  else
    return TBL(table);
}

/*
 * NAME:	buffer()
 * DESCRIPTION:	construct a buffer value
 */
static varargs
MOOVAL buffer(mixed *info, string splices, MOOVAL elts...)
{
  MOOVAL elt;
  string buf, c;
  int i, sz;

  buf = "";
  c   = "x";

  for (i = 0, sz = sizeof(elts); i < sz; ++i)
    {
      switch (TYPEOF(elt = elts[i]))
	{
	case T_NUM:
	  if (splices && splices[i] == '@')
	    return RAISE(E_TYPE);
	  c[0] = NUMVAL(elt);
	  buf += c;
	  break;

	case T_BUF:
	  if (! splices || splices[i] != '@')
	    return RAISE(E_TYPE);
	  buf += BUFVAL(elt);
	  break;

	default:
	  return RAISE(E_TYPE);
	}
    }

  return BUF(buf);
}

/*
 * NAME:	do_assignment()
 * DESCRIPTION:	perform generic indexed assignment
 */
private
MOOVAL do_assignment(mixed *addr, int index, MOOVAL rvalue,
		     int range_flag, MOOVAL *indices)
{
  mixed *handle;
  MOOVAL lo, hi, lvalue;
  int i, sz, handle_index;

  handle = addr;
  handle_index = index;

  for (i = 0, sz = sizeof(indices) - (range_flag + 1); i < sz; ++i)
    {
      lo     = indices[i];
      lvalue = addr[index];

      if (TBLP(lvalue))
	{
	  MOOVAL slot;

	  slot = TLOOKUP(TBLVAL(lvalue), lo);
	  if (STWP(slot))
	    return STW(E_RANGE);

	  lvalue = addr[index] = TBL(TBLVAL(lvalue) + TNEW());
	  addr   = TINSERT(TBLVAL(lvalue), lo, slot);
	  index  = 1;

	  continue;
	}

      if (! NUMP(lo) || ! LSTP(lvalue))
	return STW(E_TYPE);
      if (NUMVAL(lo) < 1 ||
	  NUMVAL(lo) > sizeof(LSTVAL(lvalue)))
	return STW(E_RANGE);

      addr  = addr[index] = LST(LSTVAL(lvalue) + LNEW());
      index = NUMVAL(lo) - 1;
    }

  lvalue = addr[index];

  switch (TYPEOF(lvalue))
    {
    case T_STR:
      if (range_flag)
	{
	  string old;
	  int b, e;

	  lo = indices[sz];
	  hi = indices[sz + 1];

	  if (! NUMP(lo) || ! NUMP(hi) || ! STRP(rvalue))
	    return STW(E_TYPE);

	  b   = NUMVAL(lo);
	  e   = NUMVAL(hi);
	  old = STRVAL(lvalue);

	  if (e < 0 || b > strlen(old) + 1)
	    return STW(E_RANGE);

	  if (--b < 0)
	    b = 0;
	  if (e > strlen(old))
	    e = strlen(old);

	  addr[index] = STR(old[.. b - 1] + STRVAL(rvalue) + old[e ..]);

	  return handle[handle_index];
	}
      else  /* ! range */
	{
	  string str;

	  str = STRVAL(lvalue);
	  lo  = indices[sz];

	  if (! NUMP(lo) || ! STRP(rvalue))
	    return STW(E_TYPE);
	  if (strlen(STRVAL(rvalue)) != 1)
	    return STW(E_INVARG);
	  if (NUMVAL(lo) < 1 ||
	      NUMVAL(lo) > strlen(str))
	    return STW(E_RANGE);

	  str[NUMVAL(lo) - 1] = STRVAL(rvalue)[0];
	  addr[index] = STR(str);

	  return handle[handle_index];
	}

    case T_BUF:
      if (range_flag)
	{
	  string old;
	  int b, e;

	  lo = indices[sz];
	  hi = indices[sz + 1];

	  if (! NUMP(lo) || ! NUMP(hi) || ! BUFP(rvalue))
	    return STW(E_TYPE);

	  b   = NUMVAL(lo);
	  e   = NUMVAL(hi);
	  old = BUFVAL(lvalue);

	  if (e < 0 || b > strlen(old) + 1)
	    return STW(E_RANGE);

	  if (--b < 0)
	    b = 0;
	  if (e > strlen(old))
	    e = strlen(old);

	  addr[index] = BUF(old[.. b - 1] + BUFVAL(rvalue) + old[e ..]);

	  return handle[handle_index];
	}
      else  /* ! range */
	{
	  string buf;

	  buf = BUFVAL(lvalue);
	  lo  = indices[sz];

	  if (! NUMP(lo) || ! NUMP(rvalue))
	    return STW(E_TYPE);
	  if (NUMVAL(lo) < 1 ||
	      NUMVAL(lo) > strlen(buf))
	    return STW(E_RANGE);

	  buf[NUMVAL(lo) - 1] = NUMVAL(rvalue);
	  addr[index] = BUF(buf);

	  return handle[handle_index];
	}

    case T_LST:
      if (range_flag)
	{
	  MOOVAL *old;
	  int b, e;

	  lo = indices[sz];
	  hi = indices[sz + 1];

	  if (! NUMP(lo) || ! NUMP(hi) || ! LSTP(rvalue))
	    return STW(E_TYPE);

	  b   = NUMVAL(lo);
	  e   = NUMVAL(hi);
	  old = LSTVAL(lvalue);

	  if (e < 0 || b > sizeof(old) + 1)
	    return STW(E_RANGE);

	  if (--b < 0)
	    b = 0;
	  if (e > sizeof(old))
	    e = sizeof(old);
	  --e;

	  addr[index] = LST(old[0 .. b - 1] +
			    LSTVAL(rvalue) +
			    old[e + 1 ..]);

	  return handle[handle_index];
	}
      else  /* ! range */
	{
	  lo = indices[sz];

	  if (! NUMP(lo))
	    return STW(E_TYPE);
	  if (NUMVAL(lo) < 1 ||
	      NUMVAL(lo) > sizeof(LSTVAL(lvalue)))
	    return STW(E_RANGE);

	  lvalue = LSTVAL(lvalue) + LNEW();
	  lvalue[NUMVAL(lo) - 1] = rvalue;
	  addr[index] = LST(lvalue);

	  return handle[handle_index];
	}

    case T_TBL:
      if (range_flag)
	return STW(E_TYPE);

      lo = indices[sz];

      lvalue = TBLVAL(lvalue) + TNEW();
      TINSERT(lvalue, lo, rvalue);
      addr[index] = TBL(lvalue);

      return handle[handle_index];

    default:
      return STW(E_TYPE);
    }
}

# ifndef INLINE_PUSHVAR
/*
 * NAME:	var()
 * DESCRIPTION:	get variable contents
 */
static
MOOVAL var(mixed *info, int var_index)
{
  return info[I_VARDEFS][var_index - VAR_OFFSET] == '0' ?
    RAISE(E_VARNF) : VARS[var_index];
}
# endif

/*
 * NAME:	avar()
 * DESCRIPTION:	perform simple variable assignment
 */
static
MOOVAL avar(mixed *info, int var_index, MOOVAL rvalue)
{
  if (var_index >= VAR_OFFSET)
    info[I_VARDEFS][var_index - VAR_OFFSET] = '1';

  return VARS[var_index] = rvalue;
}

/*
 * NAME:	avari()
 * DESCRIPTION:	perform indexed variable assignment
 */
static
MOOVAL avari(mixed *info, int var_index, int range_flag,
	     MOOVAL *indices, MOOVAL rvalue)
{
  MOOVAL ret;

  if (var_index >= VAR_OFFSET &&
      info[I_VARDEFS][var_index - VAR_OFFSET] == '0')
    RAISE(E_VARNF);

  ret = do_assignment(VARS, var_index, rvalue, range_flag, indices);
  if (STWP(ret))
    {
      VARS[var_index] = RAISE(STWVAL(ret));
      info[I_VARDEFS][var_index - VAR_OFFSET] = '1';
    }

  return rvalue;
}

/*
 * NAME:	aprop()
 * DESCRIPTION:	perform simple property assignment
 */
static
MOOVAL aprop(mixed *info, MOOVAL mobj, MOOVAL pname, MOOVAL rvalue)
{
  object ob;
  MOOVAL ret;

  if (! OBJP(mobj) || ! STRP(pname))
    return RAISE(E_TYPE);

  if (! (ob = MOOOBJ(OBJVAL(mobj))))
    return RAISE(E_INVIND);

  ret = ob->set_property(STRVAL(pname), rvalue, info);

  return ret != E_NONE ? RAISE(ret) : rvalue;
}

/*
 * NAME:	apropi()
 * DESCRIPTION:	perform indexed property assignment
 */
static
MOOVAL apropi(mixed *info, MOOVAL mobj, MOOVAL pname, int range_flag,
	     MOOVAL *indices, MOOVAL rvalue)
{
  MOOVAL current;
  object ob;
  int ret;

  if (! OBJP(mobj) || ! STRP(pname))
    return RAISE(E_TYPE);

  if (! (ob = MOOOBJ(OBJVAL(mobj))))
    return RAISE(E_INVIND);

  current = ob->get_property(STRVAL(pname), info);
  if (STWP(current))
    return RAISE(STWVAL(current));

  current = do_assignment( ({ current }), 0, rvalue, range_flag, indices);
  if (STWP(current))
    current = RAISE(STWVAL(current));

  ret = ob->set_property(STRVAL(pname), current, info);

  return ret != E_NONE ? RAISE(ret) : rvalue;
}

/*
 * NAME:	argcheck()
 * DESCRIPTION:	verify the number of arguments to a builtin function
 */
static
int argcheck(MOOVAL *args, int min, int max)
{
  int size;

  return (size = sizeof(args)) >= min && (max < 0 || size <= max);
}

/*
 * NAME:	verbcall()
 * DESCRIPTION:	call a verb
 */
MOOVAL verbcall(JS_PROTO, MOOVAL mobj, MOOVAL vname, MOOVAL args)
{
  MOOVAL pvar;
  object ob;

  JS_BEGIN;

  if (STRP(mobj))  /* call LPC from MOO */
    {
      string func;

      if (! STRP(vname))
	return RAISE(E_TYPE);
      if (! WIZARDP(info))
	return RAISE(E_PERM);

      if (catch(ob = load_object(STRVAL(mobj))) || ! ob)
	return RAISE(E_INVIND);
      if (! function_object(func = STRVAL(vname), ob))
	return RAISE(E_VERBNF);

      return lpc2moo(call_other(ob, func, moo2lpc(args)...));
    }

  if (! STRP(vname) || ! OBJP(mobj))
    return RAISE(E_TYPE);
  if (! (ob = MOOOBJ(OBJVAL(mobj))))
    return RAISE(E_INVIND);

  pvar = VARS[V_PLAYER];

  JS_PREP(1);
  RET = ob->call_verb(JS_DATA(1), tolower(STRVAL(vname)),
		      ({ (WIZARDP(info) && OBJP(pvar)) ?
			   pvar : OBJ(info[I_PLAYER]),	/* player */
			 mobj,				/* this */
			 OBJ(info[I_THIS]),		/* caller */
			 args,				/* args */
			 VARS[V_ARGSTR],		/* argstr */
			 vname,				/* verb */
			 VARS[V_DOBJ],			/* dobj */
			 VARS[V_DOBJSTR],		/* dobjstr */
			 VARS[V_PREPSTR],		/* prepstr */
			 VARS[V_IOBJ],			/* iobj */
			 VARS[V_IOBJSTR],		/* iobjstr */
		         STD_VARS }) );
  JS_END;

  return STWP(RET) ? RAISE(STWVAL(RET)) : RET;

  JS_END;
}

/*
 * NAME:	prep_fork
 * DESCRIPTION:	prepare a fork
 */
static
void prep_fork(mixed *stack, mixed *info, int fork_id)
{
  int task_id, delay;
  mixed *finfo;

  finfo = info + ({ });

  finfo[I_VARS]   += ({ });
  finfo[I_TASKID]  = task_id = NUMVAL(POP());
  finfo[I_DEPTH]   = global->get_max_depth();
  finfo[I_LINENO]  = lineno;
  finfo[I_LINK]    = 0;

  delay = NUMVAL(POP());

  global->register_task(finfo, delay, this_object(),
			call_out("fork" + (string) fork_id, delay,
				 stack, finfo));
  ref();
}

/*
 * NAME:	pass()
 * DESCRIPTION:	call the inherited version of a verb
 */
MOOVAL pass(JS_PROTO, MOOVAL *args)
{
  object host, parent;
  MOOVAL ret, pvar;

  JS_BEGIN;

  if (! (host = info[I_HOSTOBJ]) ||
      ! (parent = host->get_parent()))
    return RAISE(E_VERBNF);

  pvar = VARS[V_PLAYER];

  JS_PREP(1);
  RET = parent->call_verb(JS_DATA(1), tolower(info[I_NAME]),
			  ({ (WIZARDP(info) && OBJP(pvar)) ?
			       pvar : OBJ(info[I_PLAYER]),	/* player */
			      OBJ(info[I_THIS]),		/* this */
			      OBJ(info[I_THIS]),		/* caller */
			      LST(args),			/* args */
			      VARS[V_ARGSTR],			/* argstr */
			      STR(info[I_NAME]),		/* verb */
			      VARS[V_DOBJ],			/* dobj */
			      VARS[V_DOBJSTR],			/* dobjstr */
			      VARS[V_PREPSTR],			/* prepstr */
			      VARS[V_IOBJ],			/* iobj */
			      VARS[V_IOBJSTR],			/* iobjstr */
			      STD_VARS }) );
  JS_END;

  return STWP(RET) ? RAISE(STWVAL(RET)) : RET;

  JS_END;
}

/*
 * NAME:	abort_task()
 * DESCRIPTION:	called from the global object to abort a call_out()
 */
void abort_task(int dgd_task_id)
{
  remove_call_out(dgd_task_id);
}