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:	moofuns.c
 * DESCRIPTION:	MOO builtin functions
 */

# ifdef FUNCDEF
FUNCDEF(1, "pass", 0, -1)
# else

/*
 * NAME:	bfun->pass()
 * DESCRIPTION:	call the inherited version of the executing verb
 */
varargs
MOOVAL b_pass(JS_PROTO, MOOVAL args...)
{
  MOOVAL pass(JS_PROTO, MOOVAL *args);

  JS_BEGIN;

  JS_PREP(1);
  RET = pass(JS_DATA(1), args);
  JS_END;

  return RET;

  JS_END;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "typeof", 1, 1)
# else

/*
 * NAME:	bfun->typeof()
 * DESCRIPTION:	return the (integer) type of the argument
 */
varargs
MOOVAL b_typeof(mixed *info, MOOVAL arg)
{
  return NUM(TYPEOF(arg));
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "tostr", 0, -1)
# else

/*
 * NAME:	bfun->tostr()
 * DESCRIPTION:	convert and concatenate arguments into a string
 */
varargs
MOOVAL b_tostr(mixed *info, MOOVAL args...)
{
  MOOVAL arg;
  string str;
  int i, sz;

  str = "";
  for (i = 0, sz = sizeof(args); i < sz; ++i)
    {
      switch (TYPEOF(arg = args[i]))
	{
	case T_NUM:
	  str += (string) NUMVAL(arg);
	  break;
	case T_STR:
	  str += STRVAL(arg);
	  break;
	case T_OBJ:
	  str += "#" + (string) OBJVAL(arg);
	  break;
	case T_ERR:
	  str += global->error_desc(ERRVAL(arg));
	  break;
	case T_LST:
	  str += "{list}";
	  break;
	case T_FLT:
	  str += flt2str(FLTVAL(arg));
	  break;
	case T_TBL:
	  str += "{table}";
	  break;
	case T_BUF:
	  {
	    string buf;
	    int i, c;

	    buf = BUFVAL(arg);

	    for (i = strlen(buf); i--; )
	      if (((c = buf[i]) < ' ' && c != '\t') || c > '~')
		buf = buf[.. i - 1] + buf[i + 1 ..];

	    str += buf;
	  }
	  break;

	default:
	  return RAISE(E_TYPE);	/* reserved for future types */
	}
    }

  return STR(str);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "tonum", 1, 1)
# else

/*
 * NAME:	bfun->tonum()
 * DESCRIPTION:	convert the argument into an integer
 */
varargs
MOOVAL b_tonum(mixed *info, MOOVAL arg)
{
  int num;

  switch (TYPEOF(arg))
    {
    case T_NUM:
      return arg;

    case T_OBJ:
      return NUM(OBJVAL(arg));

    case T_ERR:
      return NUM(ERRVAL(arg));

    case T_STR:
      {
	string str;
	int i, sz;

	/* this is unnecessarily complex, but provides
	   close simulation to LambdaMOO behavior */

	sz = strlen(str = STRVAL(arg));
	while (i < sz && (str[i] == ' ' || str[i] == '\t'))
	  ++i;
	sscanf(str[i ..], "%d%s", num, str);
	i = 0, sz = strlen(str);
	while (i < sz && (str[i] == ' ' || str[i] == '\t'))
	  ++i;

	if (i < sz)
	  return NUM(0);
	else
	  return NUM(num);
      }

    case T_FLT:
      if (catch(num = (int) FLTVAL(arg)))
	return RAISE(E_RANGE);
      else
	return NUM(num);

    default:
      return RAISE(E_TYPE);
    }
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "toobj", 1, 1)
# else

/*
 * NAME:	bfun->toobj()
 * DESCRIPTION:	convert the argument to an object value
 */
varargs
MOOVAL b_toobj(mixed *info, MOOVAL arg)
{
  int num;

  switch (TYPEOF(arg))
    {
    case T_NUM:
      return OBJ(NUMVAL(arg));

    case T_OBJ:
      return arg;

    case T_ERR:
      return OBJ(ERRVAL(arg));

    case T_STR:
      {
	string str;
	int i, sz;

	/* this is unnecessarily complex, but provides
	   close simulation to LambdaMOO behavior */

	sz = strlen(str = STRVAL(arg));
	while (i < sz && (str[i] == ' ' || str[i] == '\t'))
	  ++i;
	if (i < sz && str[i] == '#')
	  ++i;
	sscanf(str[i ..], "%d%s", num, str);
	i = 0, sz = strlen(str);
	while (i < sz && (str[i] == ' ' || str[i] == '\t'))
	  ++i;

	if (i < sz)
	  return OBJ(0);
	else
	  return OBJ(num);
      }

    case T_FLT:
      if (catch(num = (int) FLTVAL(arg)))
	return RAISE(E_RANGE);
      else
	return OBJ(num);

    default:
      return RAISE(E_TYPE);
    }
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "min", 1, -1)
# else

/*
 * NAME:	bfun->min()
 * DESCRIPTION:	return the minimum of many integer arguments
 */
varargs
MOOVAL b_min(mixed *info, MOOVAL arg1, MOOVAL etc...)
{
  mixed found;
  int i;

  switch (TYPEOF(arg1))
    {
    case T_NUM:
      found = NUMVAL(arg1);
      break;

    case T_FLT:
      found = FLTVAL(arg1);
      break;

    default:
      return RAISE(E_TYPE);
    }

  for (i = sizeof(etc); i--; )
    {
      MOOVAL arg;

      switch (TYPEOF(arg = etc[i]))
	{
	case T_NUM:
	  if ((float) NUMVAL(arg) < (float) found)
	    found = NUMVAL(arg);
	  break;

	case T_FLT:
	  if (FLTVAL(arg) < (float) found)
	    found = FLTVAL(arg);
	  break;

	default:
	  return RAISE(E_TYPE);
	}
    }

  if (typeof(found) == T_INT)
    return NUM(found);
  else
    return FLT(found);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "max", 1, -1)
# else

/*
 * NAME:	bfun->max()
 * DESCRIPTION:	return the maximum of many integer arguments
 */
varargs
MOOVAL b_max(mixed *info, MOOVAL arg1, MOOVAL etc...)
{
  mixed found;
  int i;

  switch (TYPEOF(arg1))
    {
    case T_NUM:
      found = NUMVAL(arg1);
      break;

    case T_FLT:
      found = FLTVAL(arg1);
      break;

    default:
      return RAISE(E_TYPE);
    }

  for (i = sizeof(etc); i--; )
    {
      MOOVAL arg;

      switch (TYPEOF(arg = etc[i]))
	{
	case T_NUM:
	  if ((float) NUMVAL(arg) > (float) found)
	    found = NUMVAL(arg);
	  break;

	case T_FLT:
	  if (FLTVAL(arg) > (float) found)
	    found = FLTVAL(arg);
	  break;

	default:
	  return RAISE(E_TYPE);
	}
    }

  if (typeof(found) == T_INT)
    return NUM(found);
  else
    return FLT(found);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "abs", 1, 1)
# else

/*
 * NAME:	bfun->abs()
 * DESCRIPTION:	compute absolute value
 */
varargs
MOOVAL b_abs(mixed *info, MOOVAL arg)
{
  if (NUMP(arg))
    return NUM(abs(NUMVAL(arg)));
  else if (FLTP(arg))
    return FLT(fabs(FLTVAL(arg)));
  else
    return RAISE(E_TYPE);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "sqrt", 1, 1)
# else

/*
 * NAME:	bfun->sqrt()
 * DESCRIPTION:	compute square root
 */
varargs
MOOVAL b_sqrt(mixed *info, MOOVAL arg)
{
  if (NUMP(arg))
    {
      int num;

      if ((num = NUMVAL(arg)) < 0)
	return RAISE(E_INVARG);

      return NUM((int) floor(sqrt((float) num) + 0.01));
    }
  else if (FLTP(arg))
    {
      float fnum;

      if ((fnum = FLTVAL(arg)) < 0.0)
	return RAISE(E_INVARG);

      return FLT(sqrt(fnum));
    }
  else
    return RAISE(E_TYPE);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "random", 1, 1)
# else

/*
 * NAME:	bfun->random()
 * DESCRIPTION:	return a pseudo-random number
 */
varargs
MOOVAL b_random(mixed *info, MOOVAL arg)
{
  int num;

  ASSERT(arg, NUM);

  if ((num = NUMVAL(arg)) <= 0)
    return RAISE(E_INVARG);
  else
    return NUM(random(num) + 1);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "time", 0, 0)
# else

/*
 * NAME:	bfun->time()
 * DESCRIPTION:	return the current time as an integer
 */
varargs
MOOVAL b_time(mixed *info)
{
  return NUM(time());
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "ctime", 0, 1)
# else

/*
 * NAME:	bfun->ctime()
 * DESCRIPTION:	convert an integer time into a readable string
 */
varargs
MOOVAL b_ctime(mixed *info, MOOVAL arg...)
{
  int seconds;

  if (sizeof(arg))
    {
      ASSERT(arg[0], NUM);
      seconds = NUMVAL(arg[0]);
    }
  else
    seconds = time();

  return STR(ctime(seconds) + " " + global->get_timezone());
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "length", 1, 1)
# else

/*
 * NAME:	bfun->length()
 * DESCRIPTION:	return the length of a string, list, table, or buffer
 */
varargs
MOOVAL b_length(mixed *info, MOOVAL arg)
{
  switch (TYPEOF(arg))
    {
    case T_STR:
      return NUM(strlen(STRVAL(arg)));
    case T_LST:
      return NUM(sizeof(LSTVAL(arg)));
    case T_TBL:
      return NUM(map_sizeof(TBLVAL(arg)));
    case T_BUF:
      return NUM(strlen(BUFVAL(arg)));
    default:
      return RAISE(E_TYPE);
    }
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "strsub", 3, 4)
# else

/*
 * NAME:	bfun->strsub()
 * DESCRIPTION:	perform generic string substitution
 */
varargs
MOOVAL b_strsub(mixed *info, MOOVAL arg1, MOOVAL arg2,
		             MOOVAL arg3, MOOVAL arg4)
{
  string subject, what, with, lower_subject;
  int i, sz, whatlen, withlen, case_matters;

  ASSERT(arg1, STR);
  ASSERT(arg2, STR);
  ASSERT(arg3, STR);

  subject = STRVAL(arg1);
  if (! strlen(what = STRVAL(arg2)))
    return RAISE(E_INVARG);

  with = STRVAL(arg3);
  case_matters = arg4 && TRUTHOF(arg4);

  if (! case_matters)
    {
      lower_subject = tolower(subject);
      what = tolower(what);
    }

  whatlen = strlen(what);
  withlen = strlen(with);
  for (i = 0, sz = strlen(subject); i < sz - whatlen + 1; ++i)
    {
      if (case_matters ? (subject[i .. i + whatlen - 1] == what) :
	  (lower_subject[i .. i + whatlen - 1] == what))
	{
	  subject = subject[.. i - 1] + with + subject[i + whatlen ..];
	  if (! case_matters)
	    lower_subject = lower_subject[.. i - 1] + with +
	      lower_subject[i + whatlen ..];

	  i += withlen - 1;
	  sz = sz - whatlen + withlen;
	}
    }

  return STR(subject);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "crypt", 1, 2)
# else

/*
 * NAME:	bfun->crypt()
 * DESCRIPTION:	return an encryption string
 */
varargs
MOOVAL b_crypt(mixed *info, MOOVAL arg1, MOOVAL etc...)
{
  string key, salt;

  ASSERT(arg1, STR);
  key = STRVAL(arg1);

  if (sizeof(etc))
    {
      ASSERT(etc[0], STR);
      salt = STRVAL(etc[0]);

      switch (strlen(salt))
	{
	case 0:
	  return STR("");
	case 1:
	  return STR(crypt(key, salt + salt));
	default:
	  return STR(crypt(key, salt));
	}
    }

  return STR(crypt(key));
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "index", 2, 3)
# else

/*
 * NAME:	bfun->index()
 * DESCRIPTION:	locate a substring
 */
varargs
MOOVAL b_index(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  string str1, str2;
  int i, sz, sz1, sz2;

  ASSERT(arg1, STR);
  ASSERT(arg2, STR);

  if (arg3 && TRUTHOF(arg3))
    {
      str1 = STRVAL(arg1);
      str2 = STRVAL(arg2);
    }
  else
    {
      str1 = tolower(STRVAL(arg1));
      str2 = tolower(STRVAL(arg2));
    }

  sz1 = strlen(str1);
  sz2 = strlen(str2);
  for (i = 0, sz = sz1 - sz2 + 1; i < sz; ++i)
    if (str1[i .. i + sz2 - 1] == str2)
      return NUM(i + 1);

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "rindex", 2, 3)
# else

/*
 * NAME:	bfun->rindex()
 * DESCRIPTION:	locate a substring from reverse
 */
varargs
MOOVAL b_rindex(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  string str1, str2;
  int i, sz1, sz2;

  ASSERT(arg1, STR);
  ASSERT(arg2, STR);

  if (arg3 && TRUTHOF(arg3))
    {
      str1 = STRVAL(arg1);
      str2 = STRVAL(arg2);
    }
  else
    {
      str1 = tolower(STRVAL(arg1));
      str2 = tolower(STRVAL(arg2));
    }

  sz1 = strlen(str1);
  sz2 = strlen(str2);
  for (i = sz1 - sz2; i >= 0; --i)
    if (str1[i .. i + sz2 - 1] == str2)
      return NUM(i + 1);

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "strcmp", 2, 2)
# else

/*
 * NAME:	bfun->strcmp()
 * DESCRIPTION:	perform case-sensitive string comparison
 */
varargs
MOOVAL b_strcmp(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  string str1, str2;

  ASSERT(arg1, STR);
  ASSERT(arg2, STR);

  str1 = STRVAL(arg1);
  str2 = STRVAL(arg2);

  if (str1 == str2)
    return NUM(0);
  else if (str1 < str2)
    return NUM(-1);
  else  /* str1 > str2 */
    return NUM(1);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "match", 2, 3)
# else

/*
 * NAME:	bfun->match()
 * DESCRIPTION:	perform regular expression matching
 */
varargs
MOOVAL b_match(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  MOOVAL results;

  ASSERT(arg1, STR);
  ASSERT(arg2, STR);

  results = moo_regexp(arg1, arg2, 0, arg3 && TRUTHOF(arg3));
  return STWP(results) ? RAISE(STWVAL(results)) : results;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "rmatch", 2, 3)
# else

/*
 * NAME:	bfun->rmatch()
 * DESCRIPTION:	perform regular expression matching from reverse
 */
varargs
MOOVAL b_rmatch(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  MOOVAL results;

  ASSERT(arg1, STR);
  ASSERT(arg2, STR);

  results = moo_regexp(arg1, arg2, 1, arg3 && TRUTHOF(arg3));
  return STWP(results) ? RAISE(STWVAL(results)) : results;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "substitute", 2, 2)
# else

/*
 * NAME:	bfun->substitute()
 * DESCRIPTION:	perform string substitution based on match() results
 */
varargs
MOOVAL b_substitute(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  string template, subject;
  mixed *subs, *replacements;
  int start, end, i, j, sz, subjlen, *tags;

  ASSERT(arg1, STR);
  ASSERT(arg2, LST);

  template = STRVAL(arg1);
  subs     = LSTVAL(arg2);

  if (sizeof(subs) != 4 ||
      ! NUMP(subs[0]) || ! NUMP(subs[1]) ||
      ! LSTP(subs[2]) || ! STRP(subs[3]))
    return RAISE(E_INVARG);

  start = NUMVAL(subs[0]) - 1;
  end   = NUMVAL(subs[1]) - 1;
  replacements = LSTVAL(subs[2]);
  subject = STRVAL(subs[3]);
  subjlen = strlen(subject);

  if (start < 0 || end > subjlen - 1 || end < start - 1 ||
      sizeof(replacements) != 9)
    return RAISE(E_INVARG);

  tags = allocate(18);
  for (i = j = 0; i < 9; ++i, j += 2)
    {
      MOOVAL *list;
      int min, max;

      if (! LSTP(replacements[i]) ||
	  sizeof(list = LSTVAL(replacements[i])) != 2)
	return RAISE(E_INVARG);

      min = list[0];
      max = list[1];

      if ((min < 1 || min > subjlen + 1 ||
	   max < min - 1 || max > subjlen) &&
	  (min != 0 || max != -1))
	return RAISE(E_INVARG);

      tags[j]     = min - 1;
      tags[j + 1] = max - 1;
    }

  for (i = 0, sz = strlen(template); i < sz; ++i)
    {
      if (template[i] == '%')
	{
	  string sub;
	  int index, min, max, char;

	  if (i == sz - 1)
	    return RAISE(E_INVARG);

	  char = template[i + 1];
	  switch (char)
	    {
	    case '%':
	      template = template[.. i] + template[i + 2 ..];
	      --sz;
	      continue;

	    case '0':
	      sub = subject[start .. end];
	      break;

	    case '1': case '2': case '3': case '4': case '5':
	    case '6': case '7': case '8': case '9':
	      index = 2 * (char - '1');
	      min = tags[index];
	      if (min < 0)
		sub = "";
	      else
		{
		  max = tags[index + 1];
		  sub = subject[min .. max];
		}
	      break;

	    default:
	      return RAISE(E_INVARG);
	    }

	  template = template[.. i - 1] + sub + template[i + 2 ..];
	  sz += strlen(sub) - 2;
	  i  += strlen(sub) - 1;
	}
    }

  return STR(template);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "listinsert", 2, 3)
# else

/*
 * NAME:	bfun->listinsert()
 * DESCRIPTION:	insert an item into a list and return the new list
 */
varargs
MOOVAL b_listinsert(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL etc...)
{
  MOOVAL *newlist;
  int index;

  ASSERT(arg1, LST);
  newlist = LSTVAL(arg1);

  if (sizeof(etc))
    {
      ASSERT(etc[0], NUM);
      index = NUMVAL(etc[0]);
      if (index < 1)
	index = 1;
      else if (index > sizeof(newlist))
	index = sizeof(newlist) + 1;
    }
  else
    index = 1;

  return LST(newlist[.. index - 2] + ({ arg2 }) + newlist[index - 1 ..]);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "listappend", 2, 3)
# else

/*
 * NAME:	bfun->listappend()
 * DESCRIPTION:	append an item to a list and return the new list
 */
varargs
MOOVAL b_listappend(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL etc...)
{
  MOOVAL *newlist;
  int index;

  ASSERT(arg1, LST);
  newlist = LSTVAL(arg1);

  if (sizeof(etc))
    {
      ASSERT(etc[0], NUM);
      index = NUMVAL(etc[0]);
      if (index < 1)
	index = 0;
      else if (index > sizeof(newlist))
	index = sizeof(newlist);
    }
  else
    index = sizeof(newlist);

  return LST(newlist[.. index - 1] + ({ arg2 }) + newlist[index ..]);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "listdelete", 2, 2)
# else

/*
 * NAME:	bfun->listdelete()
 * DESCRIPTION:	remote an item from a list and return the new list
 */
varargs
MOOVAL b_listdelete(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  MOOVAL *newlist;
  int index;

  ASSERT(arg1, LST);
  ASSERT(arg2, NUM);

  newlist = LSTVAL(arg1);
  index   = NUMVAL(arg2);

  if (index < 1 || index > sizeof(newlist))
    return RAISE(E_RANGE);
  else
    return LST(newlist[.. index - 2] + newlist[index ..]);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "listset", 3, 3)
# else

/*
 * NAME:	bfun->listset()
 * DESCRIPTION:	alter an item in a list and return the new list
 */
varargs
MOOVAL b_listset(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  MOOVAL *newlist;
  int index;

  ASSERT(arg1, LST);
  ASSERT(arg3, NUM);

  newlist = LSTVAL(arg1);
  index   = NUMVAL(arg3);

  if (index < 1 || index > sizeof(newlist))
    return RAISE(E_RANGE);
  else
    return LST(newlist[.. index - 2] + ({ arg2 }) + newlist[index ..]);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "setadd", 2, 2)
# else

/*
 * NAME:	bfun->setadd()
 * DESCRIPTION:	treat a list as a set and add a new member
 */
varargs
MOOVAL b_setadd(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  MOOVAL *newlist;
  int i;

  ASSERT(arg1, LST);
  newlist = LSTVAL(arg1);

  for (i = sizeof(newlist); i--; )
    {
      if (EQUALP(arg2, newlist[i]))
	return LST(newlist);
    }

  return LST(newlist + ({ arg2 }) );
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "setremove", 2, 2)
# else

/*
 * NAME:	bfun->setremove()
 * DESCRIPTION:	treat a list as a set and remove a member
 */
varargs
MOOVAL b_setremove(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  MOOVAL *newlist;
  int i, sz;

  ASSERT(arg1, LST);
  newlist = LSTVAL(arg1);

  for (i = 0, sz = sizeof(newlist); i < sz; ++i)
    {
      if (EQUALP(arg2, newlist[i]))
	return LST(newlist[.. i - 1] + newlist[i + 1 ..]);
    }

  return LST(newlist);
}
# endif

# ifdef FUNCDEF
FUNCDEF(1, "create", 1, 2)
# else

/*
 * NAME:	bfun->create()
 * DESCRIPTION:	create and return a new MOO object
 */
varargs
MOOVAL b_create(JS_PROTO, MOOVAL arg1, MOOVAL etc...)
{
  object ob, parent, owner;
  int nowner;

  JS_BEGIN;

  ASSERT(arg1, OBJ);

  if (! (parent = MOOOBJ(OBJVAL(arg1))))
    return RAISE(E_PERM);

  if (sizeof(etc))
    {
      ASSERT(etc[0], OBJ);
      nowner = OBJVAL(etc[0]);

      if (PROGRAMMER(info) != nowner &&
	  ! WIZARDP(info))
	return RAISE(E_PERM);
    }
  else
    nowner = PROGRAMMER(info);

  JS_PREP(1);
  RET = parent->create_child(JS_DATA(1), nowner);
  JS_END;

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

  JS_END;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "chparent", 2, 2)
# else

/*
 * NAME:	bfun->chparent()
 * DESCRIPTION:	reparent and object
 */
varargs
MOOVAL b_chparent(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob, newparent;
  int objnum, result;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, OBJ);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  if ((objnum = OBJVAL(arg2)) != -1)
    {
      if (! (newparent = MOOOBJ(objnum)) ||
	  ! newparent->fertile(info))
	return RAISE(E_PERM);
    }
  else
    newparent = 0;

  result = ob->chparent(newparent, info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "valid", 1, 1)
# else

/*
 * NAME:	bfun->valid()
 * DESCRIPTION:	verify whether an object value points to a real object
 */
varargs
MOOVAL b_valid(mixed *info, MOOVAL arg)
{
  ASSERT(arg, OBJ);

  return MOOOBJ(OBJVAL(arg)) ? NUM(1) : NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "parent", 1, 1)
# else

/*
 * NAME:	bfun->parent()
 * DESCRIPTION:	return the parent of an object
 */
varargs
MOOVAL b_parent(mixed *info, MOOVAL arg)
{
  object ob;

  ASSERT(arg, OBJ);
  GET_VALID_OBJ(ob, OBJVAL(arg));

  return (ob = ob->get_parent()) ? OBJ_OBJNUM(ob) : OBJ(-1);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "children", 1, 1)
# else

/*
 * NAME:	bfun->children()
 * DESCRIPTION:	return the children of an object as a list
 */
varargs
MOOVAL b_children(mixed *info, MOOVAL arg)
{
  object ob;

  ASSERT(arg, OBJ);
  GET_VALID_OBJ(ob, OBJVAL(arg));

  return OBJLIST2MOO(ob->get_children());
}
# endif

# ifdef FUNCDEF
FUNCDEF(1, "recycle", 1, 1)
# else

/*
 * NAME:	bfun->recycle()
 * DESCRIPTION:	destroy a MOO object
 */
varargs
MOOVAL b_recycle(JS_PROTO, MOOVAL arg)
{
  object ob;
  int ret;

  JS_BEGIN;

  ASSERT(arg, OBJ);

  GET_VALID_OBJ(ob, OBJVAL(arg));

  JS_PREP(1);
  RET = ob->recycle(JS_DATA(1));
  JS_END;

  return (RET == E_NONE) ? NUM(0) : RAISE(RET);

  JS_END;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "max_object", 0, 0)
# else

/*
 * NAME:	bfun->max_object()
 * DESCRIPTION:	return the highest numbered object value
 */
varargs
MOOVAL b_max_object(mixed *info)
{
  return OBJ(global->get_max_object());
}
# endif

# ifdef FUNCDEF
FUNCDEF(1, "move", 2, 2)
# else

/*
 * NAME:	bfun->move()
 * DESCRIPTION:	alter objects' .location and .contents
 */
varargs
MOOVAL b_move(JS_PROTO, MOOVAL arg1, MOOVAL arg2)
{
  object what, where;
  int objnum;

  JS_BEGIN;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, OBJ);

  GET_VALID_OBJ(what, OBJVAL(arg1));

  if ((objnum = OBJVAL(arg2)) == -1)
    where = 0;
  else
    GET_VALID_OBJ(where, objnum);

  JS_PREP(1);
  RET = what->move(JS_DATA(1), where);
  JS_END;

  return (RET == E_NONE) ? NUM(0) : RAISE(RET);

  JS_END;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "properties", 1, 1)
# else

/*
 * NAME:	bfun->properties()
 * DESCRIPTION:	return the names of properties defined on an object
 */
varargs
MOOVAL b_properties(mixed *info, MOOVAL arg)
{
  MOOVAL list;
  object ob;

  ASSERT(arg, OBJ);
  GET_VALID_OBJ(ob, OBJVAL(arg));

  list = ob->get_properties(info);
  return STWP(list) ? RAISE(STWVAL(list)) : list;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "property_info", 2, 2)
# else

/*
 * NAME:	bfun->property_info()
 * DESCRIPTION:	return auxiliary information about a property
 */
varargs
MOOVAL b_property_info(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  mixed pinfo;
  object ob;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  pinfo = ob->get_property_info(STRVAL(arg2), info);
  return STWP(pinfo) ? RAISE(STWVAL(pinfo)) : pinfo;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "set_property_info", 3, 3)
# else

/*
 * NAME:	bfun->set_property_info()
 * DESCRIPTION:	change the auxiliary information about a property
 */
varargs
MOOVAL b_set_property_info(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  object ob;
  int nowner, result;
  string nperms;
  MOOVAL *list;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);
  ASSERT(arg3, LST);

  list = LSTVAL(arg3);
  if (sizeof(list) != 2 ||
      ! OBJP(list[0]) ||
      ! STRP(list[1]))
    return RAISE(E_TYPE);

  nowner = OBJVAL(list[0]);
  nperms = STRVAL(list[1]);

  if (! MOOOBJ(nowner))
    return RAISE(E_INVARG);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->set_property_info(STRVAL(arg2), nowner, nperms, info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "add_property", 4, 4)
# else

/*
 * NAME:	bfun->add_property()
 * DESCRIPTION:	create a new property on an object
 */
varargs
MOOVAL b_add_property(mixed *info, MOOVAL arg1, MOOVAL arg2,
		                MOOVAL arg3, MOOVAL arg4)
{
  object ob;
  int nowner, result;
  string nperms;
  MOOVAL *list;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);
  ASSERT(arg4, LST);

  list = LSTVAL(arg4);
  if (sizeof(list) != 2 ||
      ! OBJP(list[0]) ||
      ! STRP(list[1]))
    return RAISE(E_TYPE);

  nowner = OBJVAL(list[0]);
  nperms = STRVAL(list[1]);

  if (! MOOOBJ(nowner))
    return RAISE(E_INVARG);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->add_property(STRVAL(arg2), arg3, nowner, nperms, info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "delete_property", 2, 2)
# else

/*
 * NAME:	bfun->delete_property()
 * DESCRIPTION:	remove a property from an object
 */
varargs
MOOVAL b_delete_property(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  int result;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->delete_property(STRVAL(arg2), info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "is_clear_property", 2, 2)
# else

/*
 * NAME:	bfun->is_clear_property()
 * DESCRIPTION:	indicate whether an object's inherited property is clear
 */
varargs
MOOVAL b_is_clear_property(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  MOOVAL result;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->is_clear_property(STRVAL(arg2), info);
  return STWP(result) ? RAISE(STWVAL(result)) : result;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "clear_property", 2, 2)
# else

/*
 * NAME:	bfun->clear_property()
 * DESCRIPTION:	clear an inherited property slot
 */
varargs
MOOVAL b_clear_property(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  int result;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->clear_property(STRVAL(arg2), info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "verbs", 1, 1)
# else

/*
 * NAME:	bfun->verbs()
 * DESCRIPTION:	return a list of verbs defined on an object
 */
varargs
MOOVAL b_verbs(mixed *info, MOOVAL arg)
{
  object ob;
  mixed vinfo;

  ASSERT(arg, OBJ);

  GET_VALID_OBJ(ob, OBJVAL(arg));

  vinfo = ob->get_verbs(info);
  return STWP(vinfo) ? RAISE(STWVAL(vinfo)) : vinfo;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "verb_info", 2, 2)
# else

/*
 * NAME:	bfun->verb_info()
 * DESCRIPTION:	return auxiliary information about a verb
 */
varargs
MOOVAL b_verb_info(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  mixed vinfo;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  vinfo = ob->get_verb_info(STRVAL(arg2), info);
  return STWP(vinfo) ? RAISE(STWVAL(vinfo)) : vinfo;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "set_verb_info", 3, 3)
# else

/*
 * NAME:	bfun->set_verb_info()
 * DESCRIPTION:	change auxiliary information about a verb
 */
varargs
MOOVAL b_set_verb_info(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  object ob;
  int owner, result;
  string perms, names;
  MOOVAL *list;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);
  ASSERT(arg3, LST);

  list = LSTVAL(arg3);
  if (sizeof(list) != 3 ||
      ! OBJP(list[0]) ||
      ! STRP(list[1]) ||
      ! STRP(list[2]))
    return RAISE(E_TYPE);

  owner = OBJVAL(list[0]);
  perms = STRVAL(list[1]);
  names = STRVAL(list[2]);

  if (! MOOOBJ(owner))
    return RAISE(E_INVARG);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->set_verb_info(STRVAL(arg2), owner, perms, names, info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "verb_args", 2, 2)
# else

/*
 * NAME:	bfun->verb_args()
 * DESCRIPTION:	return the arguments associated with a verb
 */
varargs
MOOVAL b_verb_args(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  mixed vinfo;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  vinfo = ob->get_verb_args(STRVAL(arg2), info);
  return STWP(vinfo) ? RAISE(STWVAL(vinfo)) : vinfo;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "set_verb_args", 3, 3)
# else

/*
 * NAME:	bfun->set_verb_args()
 * DESCRIPTION:	modify the arguments associated with a verb
 */
varargs
MOOVAL b_set_verb_args(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  MOOVAL *list;
  object ob;
  string dobj, prep, iobj;
  int result;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);
  ASSERT(arg3, LST);

  list = LSTVAL(arg3);
  if (sizeof(list) != 3 ||
      ! STRP(list[0]) ||
      ! STRP(list[1]) ||
      ! STRP(list[2]))
    return RAISE(E_TYPE);

  dobj = STRVAL(list[0]);
  prep = STRVAL(list[1]);
  iobj = STRVAL(list[2]);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->set_verb_args(STRVAL(arg2), dobj, prep, iobj, info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "add_verb", 3, 3)
# else

/*
 * NAME:	bfun->add_verb()
 * DESCRIPTION:	create a new verb for an object
 */
varargs
MOOVAL b_add_verb(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  MOOVAL *list1, *list2;
  object ob;
  int owner, result;
  string perms, names, dobj, prep, iobj;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, LST);
  ASSERT(arg3, LST);

  list1 = LSTVAL(arg2);
  list2 = LSTVAL(arg3);

  if (sizeof(list1) != 3 ||
      ! OBJP(list1[0]) ||
      ! STRP(list1[1]) ||
      ! STRP(list1[2]) ||
      sizeof(list2) != 3 ||
      ! STRP(list2[0]) ||
      ! STRP(list2[1]) ||
      ! STRP(list2[2]))
    return RAISE(E_TYPE);

  owner = OBJVAL(list1[0]);
  perms = STRVAL(list1[1]);
  names = STRVAL(list1[2]);

  if (! MOOOBJ(owner))
    return RAISE(E_INVARG);

  dobj = STRVAL(list2[0]);
  prep = STRVAL(list2[1]);
  iobj = STRVAL(list2[2]);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->add_verb(owner, perms, names, dobj, prep, iobj, info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "delete_verb", 2, 2)
# else

/*
 * NAME:	bfun->delete_verb()
 * DESCRIPTION:	remove a verb from an object
 */
varargs
MOOVAL b_delete_verb(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  int result;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->delete_verb(STRVAL(arg2), info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "verb_code", 2, 4)
# else

/*
 * NAME:	bfun->verb_code()
 * DESCRIPTION:	return the source code for a verb as a list of strings
 */
varargs
MOOVAL b_verb_code(mixed *info, MOOVAL arg1, MOOVAL arg2,
		             MOOVAL arg3, MOOVAL etc...)
{
  object ob;
  MOOVAL result;
  int full_paren, indent;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  full_paren = arg3 && TRUTHOF(arg3);
  indent     = sizeof(etc) ? TRUTHOF(etc[0]) : 1;

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->get_verb_code(STRVAL(arg2), full_paren, indent, info);

  return STWP(result) ? RAISE(STWVAL(result)) : result;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "set_verb_code", 3, 3)
# else

/*
 * NAME:	bfun->set_verb_code()
 * DESCRIPTION:	compile MOO source into a new verb program
 */
varargs
MOOVAL b_set_verb_code(mixed *info, MOOVAL arg1, MOOVAL arg2, MOOVAL arg3)
{
  object ob;
  string *code;
  int i;
  mixed result;
  MOOVAL *list;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);
  ASSERT(arg3, LST);

  if (! programmerp(PROGRAMMER(info)))
    return RAISE(E_PERM);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  list = LSTVAL(arg3);
  for (code = allocate(i = sizeof(list)); i--; code[i] = STRVAL(list[i]))
    if (! STRP(list[i]))
      return RAISE(E_TYPE);

  result = ob->set_verb_code(STRVAL(arg2), code, info);

  return STWP(result) ? RAISE(STWVAL(result)) : result;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "players", 0, 0)
# else

/*
 * NAME:	bfun->players()
 * DESCRIPTION:	return a list of all player objects
 */
varargs
MOOVAL b_players(mixed *info)
{
  return OBJLIST2MOO(global->all_players());
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "is_player", 1, 1)
# else

/*
 * NAME:	bfun->is_player()
 * DESCRIPTION:	indicate whether an object is also a player
 */
varargs
MOOVAL b_is_player(mixed *info, MOOVAL arg)
{
  object ob;

  ASSERT(arg, OBJ);
  GET_VALID_OBJ(ob, OBJVAL(arg));

  return NUM(ob->is_player() != 0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "set_player_flag", 2, 2)
# else

/*
 * NAME:	bfun->set_player_flag()
 * DESCRIPTION:	change the player status of an object
 */
varargs
MOOVAL b_set_player_flag(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;

  ASSERT(arg1, OBJ);
  GET_VALID_OBJ(ob, OBJVAL(arg1));

  if (! WIZARDP(info))
    return RAISE(E_PERM);

  ob->set_player_flag(TRUTHOF(arg2));

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "connected_players", 0, 0)
# else

/*
 * NAME:	bfun->connected_players()
 * DESCRIPTION:	return a list of all currently connected players
 */
varargs
MOOVAL b_connected_players(mixed *info)
{
  return OBJLIST2MOO(global->connected_players());
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "connected_seconds", 1, 1)
# else

/*
 * NAME:	bfun->connected_seconds()
 * DESCRIPTION:	return the number of seconds a player has been connected
 */
varargs
MOOVAL b_connected_seconds(mixed *info, MOOVAL arg)
{
  object ob, user;

  ASSERT(arg, OBJ);
  GET_VALID_OBJ(ob, OBJVAL(arg));

  if (! (user = global->get_connection_obj(ob)))
    return RAISE(E_INVARG);

  return NUM(user->get_connected_seconds());
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "idle_seconds", 1, 1)
# else

/*
 * NAME:	bfun->idle_seconds()
 * DESCRIPTION:	return the number of seconds a player has been idle
 */
varargs
MOOVAL b_idle_seconds(mixed *info, MOOVAL arg)
{
  object ob;
  int id;

  ASSERT(arg, OBJ);

  if (ob = MOOOBJ(id = OBJVAL(arg)))
    ob = global->get_connection_obj(ob);
  else
    ob = global->get_unlogged_in(id);

  return ob ? NUM(ob->get_idle_seconds()) : RAISE(E_INVARG);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "notify", 2, 2)
# else

/*
 * NAME:	bfun->notify()
 * DESCRIPTION:	send a line of output to a connection
 */
varargs
MOOVAL b_notify(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  int id;

  ASSERT(arg1, OBJ);
  if (! STRP(arg2) && ! BUFP(arg2))
    return RAISE(E_TYPE);

  id = OBJVAL(arg1);

  if (PROGRAMMER(info) != id &&
      ! WIZARDP(info))
    return RAISE(E_PERM);

  if (ob = MOOOBJ(id))
    ob = global->get_connection_obj(ob);
  else
    ob = global->get_unlogged_in(id);

  if (ob)  /* not an error if ob doesn't exist */
    {
      if (BUFP(arg2))
	ob->send(BUFVAL(arg2));
      else
	ob->notify(STRVAL(arg2));
    }

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "boot_player", 1, 1)
# else

/*
 * NAME:	bfun->boot_player()
 * DESCRIPTION:	terminate a connection
 */
varargs
MOOVAL b_boot_player(mixed *info, MOOVAL arg)
{
  object ob;
  int id;

  ASSERT(arg, OBJ);
  id = OBJVAL(arg);

  if (PROGRAMMER(info) != id &&
      ! WIZARDP(info))
    return RAISE(E_PERM);

  global->boot_player(id);

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "connection_name", 1, 1)
# else

/*
 * NAME:	bfun->connection_name()
 * DESCRIPTION:	return the TCP/IP connection name of a connection
 */
varargs
MOOVAL b_connection_name(mixed *info, MOOVAL arg)
{
  object ob;
  int id;

  ASSERT(arg, OBJ);
  id = OBJVAL(arg);

  if (PROGRAMMER(info) != id &&
      ! WIZARDP(info))
    return RAISE(E_PERM);

  if (ob = MOOOBJ(id))
    ob = global->get_connection_obj(ob);
  else
    ob = global->get_unlogged_in(id);

  return ob ? STR(ob->get_connection_name()) : RAISE(E_INVARG);
}
# endif

# ifndef FUNCDEF
/*
 * NAME:	make_jumpstack()
 * DESCRIPTION:	create a jumpstack to resume a suspend() or read()
 */
private
mixed *make_jumpstack(JS_PROTO, mixed **trace)
{
  object obj;
  string func;
  mixed *frame;
  int i;

  debug("Making jumpstack...");

  js = ({ bjump, 0, 0, 0 });

  for (i = sizeof(trace); i--; )
    {
      mixed *args;

      frame = trace[i];

      debug("... " + frame[0] + "->" + frame[2] + "()");

      args = frame[5 ..];
      args[3] = js;
      js = ({ frame[7], find_object(frame[0]), frame[2], args });

      if (! frame[7])  /* stop at JS_INIT */
	break;
    }

  return js;
}
# endif

# ifdef FUNCDEF
FUNCDEF(1, "open_network_connection", 2, 3)
# else

/*
 * NAME:	bfun->open_network_connection()
 * DESCRIPTION:	initiate an outbound network connection
 */
varargs
MOOVAL b_open_network_connection(JS_PROTO, MOOVAL arg1, MOOVAL arg2,
				           MOOVAL etc...)
{
  object conn, listener;
  string host;
  int port;

  JS_BEGIN;

  if (! WIZARDP(info) ||
      (info[I_FLAGS] & IF_FROMLPC) ||
      ! DRIVER->query_net() ||
      ! CONFIG->query(CF_OUTBOUND_NET))
    return RAISE(E_PERM);

  /* only TCP/IP is supported in this implementation */

  ASSERT(arg1, STR);
  ASSERT(arg2, NUM);

  if (sizeof(etc))
    {
      ASSERT(etc[0], OBJ);
      GET_VALID_OBJ(listener, OBJVAL(etc[0]));
    }
  else
    GET_VALID_OBJ(listener, 0);  /* default to #0 */

  conn = DRIVER->init_connection(clone_object(OUTBOUND), listener);
  conn->seed_onc(JS_DATA(1), make_jumpstack(JS_DATA(1), call_trace()),
		 STRVAL(arg1), NUMVAL(arg2));

  global->register_task(info, -1, conn, 0);

  info[I_LINENO] = info[I_VERBOBJ]->get_lineno();
  error("K!" + "Task is waiting for connection");

  JS_JUMP(1);
  /* connection has pushed unlogged-in object id or error */

  RET = POP();
  return ERRP(RET) ? RAISE(ERRVAL(RET)) : RET;

  JS_END;
}
# endif

# ifdef FUNCDEF
FUNCDEF(1, "eval", 1, 1)
# else

/*
 * NAME:	bfun->eval()
 * DESCRIPTION:	evaluate anonymous MOO code
 */
varargs
MOOVAL b_eval(JS_PROTO, MOOVAL arg)
{
  object vobj;
  mixed *ast;
  int flags;

  JS_BEGIN;

  ASSERT(arg, STR);

  if (! programmerp(PROGRAMMER(info)))
    return RAISE(E_PERM);

  if (info[I_DEPTH] == 1)
    return RAISE(E_MAXREC);

  ast = parser->main(STRVAL(arg));
  if (! ast[0])
    return LST( ({ NUM(0), STRLIST2MOO(ast[1]) }) );

  vobj = global->compile_verb(ast[1], 0);

  /* don't call vobj->ref(); let it self-destruct after executing */

  flags = IF_DEBUG |
          (WIZARDP(info) ? IF_WIZARD : 0) |
	  (info[I_FLAGS] & IF_FROMLPC);

  if (info)
    info[I_LINENO] = this_object()->get_lineno();

  info = ({ flags, PROGRAMMER(info),
	    ({ OBJ(info[I_PLAYER]),	/* player */
	       OBJ(-1),			/* this */
	       OBJ(info[I_THIS]),	/* caller */
	       LST(LNEW()),		/* args */
	       STR(""),			/* argstr */
	       STR(""),			/* verb */
	       OBJ(-1),			/* dobj */
	       STR(""),			/* dobjstr */
	       STR(""),			/* prepstr */
	       OBJ(-1),			/* iobj */
	       STR(""),			/* iobjstr */
	       STD_VARS }),
	    0, "", -1, info[I_PLAYER], info[I_TASKID], 0, vobj, 0,
	    info[I_DEPTH] - 1, info });

  JS_PREP(1);
  RET = vobj->main(JS_DATA(1));
  JS_END;

  return LST( ({ NUM(1), RET }) );

  JS_END;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "set_task_perms", 1, 1)
# else

/*
 * NAME:	bfun->set_task_perms()
 * DESCRIPTION:	change the permissions of the running task
 */
varargs
MOOVAL b_set_task_perms(mixed *info, MOOVAL arg)
{
  int prog;

  ASSERT(arg, OBJ);

  if (PROGRAMMER(info) != (prog = OBJVAL(arg)))
    {
      if (! WIZARDP(info))
	return RAISE(E_PERM);

      if (wizardp(info[I_PRGMR] = prog))
	info[I_FLAGS] |= IF_WIZARD;
      else
	info[I_FLAGS] &= ~IF_WIZARD;
    }

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "caller_perms", 0, 0)
# else

/*
 * NAME:	bfun->caller_perms()
 * DESCRIPTION:	return the permissions of the calling verb
 */
varargs
MOOVAL b_caller_perms(mixed *info)
{
  return info[I_LINK] ? OBJ(PROGRAMMER(info[I_LINK])) : OBJ(-1);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "ticks_left", 0, 0)
# else

/*
 * NAME:	bfun->ticks_left()
 * DESCRIPTION:	return the number of ticks left for the current task
 */
varargs
MOOVAL b_ticks_left(mixed *info)
{
  /* scaled to range 0 - CF_FG_TICKS */

  return NUM((int) ((float) CONFIG->query(CF_FG_TICKS) /
		    (float) CONFIG->query(CF_MAX_EXEC) *
		    (float) get_exec_cost()));
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "seconds_left", 0, 0)
# else

/*
 * NAME:	bfun->seconds_left()
 * DESCRIPTION:	return the number of seconds left for the current task
 */
varargs
MOOVAL b_seconds_left(mixed *info)
{
  return NUM((int) ((float) get_exec_cost() /
		    (float) DRIVER->get_ticks_second()));
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "task_id", 0, 0)
# else

/*
 * NAME:	bfun->task_id()
 * DESCRIPTION:	return the current task's unique integer id
 */
varargs
MOOVAL b_task_id(mixed *info)
{
  return NUM(info[I_TASKID]);
}
# endif

# ifdef FUNCDEF
FUNCDEF(1, "suspend", 1, 1)
# else

/*
 * NAME:	bfun->suspend()
 * DESCRIPTION:	suspend the current task for a given delay
 */
varargs
MOOVAL b_suspend(JS_PROTO, MOOVAL arg)
{
  int delay;
  object ob;
  string func;

  JS_BEGIN;

  ASSERT(arg, NUM);

  if ((delay = NUMVAL(arg)) < 0)
    return RAISE(E_INVARG);

  if (info[I_FLAGS] & IF_FROMLPC)
    return RAISE(E_PERM);

  debug("Entry to suspend(): SP == " + SP);

  js = make_jumpstack(JS_DATA(1), call_trace());

  global->register_task(info, delay, this_object(),
			call_out("cont_suspend", delay, JS_DATA(1)));

  info[I_LINENO] = this_object()->get_lineno();

  while (info[I_LINK])
    info = info[I_LINK];

  info[I_FLAGS] |= IF_SUSPENDED;

  error("K!" + "Task suspended");

  JS_JUMP(1);  /* jump here upon resume */

  debug("Exit from suspend(): SP == " + SP);

  return NUM(0);

  JS_END;
}
# endif

# ifndef FUNCDEF
/*
 * NAME:	cont_suspend()
 * DESCRIPTION:	called to continue suspended execution
 */
void cont_suspend(JS_PROTO)
{
  global->task_started(info[I_TASKID]);

  debug("Calling \"" + object_name(js[1]) + "\"->" + js[2] + "()");

  if (js[1])
    call_other(js[1], js[2], js[3]...);
  else  /* object disappeared? */
    global->remove_refs(info);
}
# endif

# ifdef FUNCDEF
FUNCDEF(1, "read", 0, 2)
# else

/*
 * NAME:	bfun->read()
 * DESCRIPTION:	read a line of input from a network connection
 */
varargs
MOOVAL b_read(JS_PROTO, MOOVAL etc...)
{
  object ob, user;
  int id, binary;
  string data;

  JS_BEGIN;

  if (sizeof(etc))
    {
      ASSERT(etc[0], OBJ);

      if (ob = MOOOBJ(id = OBJVAL(etc[0])))
	user = global->get_connection_obj(ob);
      else
	user = global->get_unlogged_in(id);

      if (! user)
	return RAISE(E_INVARG);

      if (((! ob || PROGRAMMER(info) != ob->get_owner()) && ! WIZARDP(info)) ||
	  (info[I_FLAGS] & IF_FROMLPC))
	return RAISE(E_PERM);
    }
  else
    {
      mixed *frame;

      if (! WIZARDP(info) ||
	  (info[I_FLAGS] & IF_FROMLPC))
	return RAISE(E_PERM);

      frame = info;
      while (frame[I_LINK])
	frame = frame[I_LINK];

      if (frame[I_FLAGS] & IF_SUSPENDED)
	return RAISE(E_PERM);

      if (! (user = global->get_connection_obj(MOOOBJ(frame[I_PLAYER]))))
	return RAISE(E_INVARG);
    }

  binary = (sizeof(etc) == 2 && TRUTHOF(etc[1]));

  /* check pending input buffer */
  if (binary)
    {
      if (data = user->get_data())
	return BUF(data);
    }
  else
    {
      if (data = user->get_line())
	return STR(data);
    }

  if (user->seed_read(JS_DATA(1), binary,
		      make_jumpstack(JS_DATA(1), call_trace())) != E_NONE)
    return RAISE(E_INVARG);

  global->register_task(info, -1, user, 0);

  info[I_LINENO] = info[I_VERBOBJ]->get_lineno();
  error("K!" + "Task is reading");

  JS_JUMP(1);
  /* connection has put line string or error on the stack */

  RET = stack[SP + 1];
  return ERRP(RET) ? RAISE(ERRVAL(RET)) : RET;

  JS_END;
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "queued_tasks", 0, 0)
# else

/*
 * NAME:	bfun->queued_tasks()
 * DESCRIPTION:	return a list of pending tasks
 */
varargs
MOOVAL b_queued_tasks(mixed *info)
{
  return global->get_queued_tasks(info);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "kill_task", 1, 1)
# else

/*
 * NAME:	bfun->kill_task()
 * DESCRIPTION:	abort execution of a pending or the current task
 */
varargs
MOOVAL b_kill_task(mixed *info, MOOVAL arg)
{
  int task, result;

  ASSERT(arg, NUM);

  if ((task = NUMVAL(arg)) == info[I_TASKID])  /* kill THIS task */
    {
      global->remove_refs(info);
      error("K!" + "Task killed");
    }

  result = global->kill_task(task, info);
  return (result == E_NONE) ? NUM(0) : RAISE(result);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "callers", 0, 1)
# else

/*
 * NAME:	bfun->callers()
 * DESCRIPTION:	return a stack trace of the current task
 */
varargs
MOOVAL b_callers(mixed *info, MOOVAL etc...)
{
  MOOVAL *list;
  mixed *frame;
  int size, i;

  if (sizeof(etc))
    {
      mixed *task_info;
      int task;

      ASSERT(etc[0], NUM);
      task = NUMVAL(etc[0]);

      if (task != info[I_TASKID])  /* not THIS task */
	{
	  task_info = global->task_info(task);
	  if (! task_info)
	    return RAISE(E_INVARG);

	  if (! WIZARDP(info) &&
	      PROGRAMMER(info) != PROGRAMMER(task_info))
	    return RAISE(E_PERM);

	  info = task_info;
	}
    }

  for (frame = info[I_LINK]; frame; frame = frame[I_LINK])
    ++size;

  list = allocate(size);

  for (frame = info[I_LINK]; frame; frame = frame[I_LINK])
    list[i++] = LST( ({ OBJ(frame[I_THIS]),
			STR(frame[I_NAME]),
			OBJ(frame[I_PRGMR]),
			(frame[I_HOSTOBJ] ?
			 OBJ_OBJNUM(frame[I_HOSTOBJ]) : OBJ(-1)),
			OBJ(frame[I_PLAYER]),
		      }) );

  return LST(list);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "output_delimiters", 1, 1)
# else

/*
 * NAME:	bfun->output_delimiters()
 * DESCRIPTION:	return a connection's current output delimiters
 */
varargs
MOOVAL b_output_delimiters(mixed *info, MOOVAL arg)
{
  object ob;
  string *delims;
  int id;

  ASSERT(arg, OBJ);
  id = OBJVAL(arg);

  if (PROGRAMMER(info) != id &&
      ! WIZARDP(info))
    return RAISE(E_PERM);

  if (ob = MOOOBJ(id))
    ob = global->get_connection_obj(ob);
  else
    ob = global->get_unlogged_in(id);

  if (! ob)
    return RAISE(E_INVARG);

  delims = ob->get_delimiters();

  return LST( ({ delims[0] ? STR(delims[0]) : STR(""),
		 delims[1] ? STR(delims[1]) : STR("") }) );
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "server_version", 0, 0)
# else

/*
 * NAME:	bfun->server_version()
 * DESCRIPTION:	return the current LambdaMOO server version string
 */
varargs
MOOVAL b_server_version(mixed *info)
{
  return STR(CONFIG->query(CF_MOO_VERSION));
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "server_log", 1, 2)
# else

/*
 * NAME:	bfun->server_log()
 * DESCRIPTION:	record a message in the MOO server log
 */
varargs
MOOVAL b_server_log(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  ASSERT(arg1, STR);

  if (! WIZARDP(info))
    return RAISE(E_PERM);

  global->log_msg((arg2 && TRUTHOF(arg2) ? "*** > " : "> ") + STRVAL(arg1));

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "renumber", 1, 1)
# else

/*
 * NAME:	bfun->renumber()
 * DESCRIPTION:	change an object's numerical index
 */
varargs
MOOVAL b_renumber(mixed *info, MOOVAL arg)
{
  object ob;

  ASSERT(arg, OBJ);
  GET_VALID_OBJ(ob, OBJVAL(arg));

  return WIZARDP(info) ? OBJ(global->renumber(ob)) : RAISE(E_PERM);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "reset_max_object", 0, 0)
# else

/*
 * NAME:	bfun->reset_max_object()
 * DESCRIPTION:	lower max_object() to be the highest used object
 */
varargs
MOOVAL b_reset_max_object(mixed *info)
{
  if (! WIZARDP(info))
    return RAISE(E_PERM);

  global->reset_max_object();

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "memory_usage", 0, 0)
# else

/*
 * NAME:	bfun->memory_usage()
 * DESCRIPTION:	(don't) return useful information about memory usage
 */
varargs
MOOVAL b_memory_usage(mixed *info)
{
  /* DGD doesn't offer memory statistics quite as LambdaMOO does, so
     we pretend no statistics are available. More useful statistics are
     available with dgd_status(). */

  return LST(LNEW());
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "dump_database", 0, 1)
# else

/*
 * NAME:	bfun->dump_database()
 * DESCRIPTION:	write a state dump or text dump
 */
varargs
MOOVAL b_dump_database(mixed *info, MOOVAL text)
{
  if (! WIZARDP(info))
    return RAISE(E_PERM);

  global->dump_database(text && TRUTHOF(text));

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "shutdown", 1, 1)
# else

/*
 * NAME:	bfun->shutdown()
 * DESCRIPTION:	cause the server to shutdown
 */
varargs
MOOVAL b_shutdown(mixed *info, MOOVAL arg)
{
  ASSERT(arg, STR);

  if (! WIZARDP(info))
    return RAISE(E_PERM);

  global->shutdown("shutdown() called by " +
		   global->user_description(PROGRAMMER(info)) +
		   ": " + STRVAL(arg));

  return NUM(0);
}
# endif

# ifdef FUNCDEF
FUNCDEF(0, "disassemble", 2, 2)
# else

/*
 * NAME:	bfun->disassemble()
 * DESCRIPTION:	break down verb code into interpreter symbols
 */
varargs
MOOVAL b_disassemble(mixed *info, MOOVAL arg1, MOOVAL arg2)
{
  object ob;
  MOOVAL result;

  ASSERT(arg1, OBJ);
  ASSERT(arg2, STR);

  GET_VALID_OBJ(ob, OBJVAL(arg1));

  result = ob->get_disassembled_code(STRVAL(arg2), info);
  return STWP(result) ? RAISE(STWVAL(result)) : result;
}
# endif