/*
* 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