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