/* Copyright (c) 1993 Stephen F. White */
#include "cool.h"
#include "proto.h"
#include "servers.h"
#include "netio.h"
#include "execute.h"
void op_shutdown (void)
{
if (!is_wizard (frame.this)) {
raise (E_PERM);
} else {
server_running = 0;
pushn (0);
}
}
void op_sync(void)
{
if (!is_wizard (frame.this)) {
raise (E_PERM);
} else {
cache_sync ();
pushn (0);
}
}
void op_writelog (void)
{
Var arg;
arg = pop ();
if (frame.this.id != SYS_OBJ && !is_wizard (frame.this)) {
raise (E_PERM);
} else if (arg.type != STR) {
raise (E_ARGTYPE);
} else {
writelog ();
fprintf (stderr, "%s\n", arg.v.str->str);
pushn (0);
}
var_free (arg);
}
void op_disconnect(void)
{
Var arg;
switch (nargs) {
case 0:
disconnect(frame.this.id);
pushn(0);
break;
case 1:
arg = pop();
if (arg.type != NUM) {
var_free(arg);
raise(E_TYPE);
} else if (!is_wizard(frame.this)) {
raise(E_PERM);
} else {
disconnect_fd(arg.v.num);
pushn (0);
}
break;
}
}
void op_raise (void)
{
Var e;
List *raise_args;
e = pop ();
if (e.type != ERR) {
var_free (e);
raise (E_ARGTYPE);
(void) pop ();
} else {
ex_state = RAISED;
raise_args = make_raise_args (e.v.err);
raise_args->el[1].v.str = add_traceback_header (raise_args->el[1].v.str,
e.v.err);
send_raise (raise_args);
}
}
void op_pass (void)
{
Objid parent;
Var args;
parent.server = 0;
parent.id = frame.m->code[frame.pc++];
args = pop_args(count_args());
send_message_and_block (frame.this, frame.this,
string_dup (sym_get (frame.on, frame.m->name)), args.v.list, parent);
}
void op_hasparent (void)
{
Var parent;
parent = pop ();
if (parent.type != OBJ) {
var_free (parent);
raise (E_ARGTYPE);
} else {
pushn (hasparent (this, parent.v.obj));
}
}
void op_objsize (void)
{
pushn (size_object (this));
}
void op_spew_method (void)
{
Var name, ret;
Method *m;
name = pop ();
if (name.type != STR) {
var_free (name);
raise (E_ARGTYPE);
} else {
if ((m = find_method (this, name.v.str->str))) {
ret.type = STR;
ret.v.str = decode_method (this, m, 2);
push (ret);
} else {
raise (E_METHODNF);
}
}
var_free (name);
}
void op_list_method (void)
{
Var name, lineno, brackets, indent, ret;
Method *m;
lineno.type = brackets.type = indent.type = NUM;
lineno.v.num = 1;
brackets.v.num = 0;
indent.v.num = 2;
switch (nargs) {
case 4:
indent = pop ();
case 3:
brackets = pop ();
case 2:
lineno = pop ();
case 1:
name = pop ();
}
if (name.type != STR || indent.type != NUM || brackets.type != NUM
|| lineno.type != NUM) {
var_free (name);
var_free (indent);
var_free (brackets);
var_free (lineno);
raise (E_ARGTYPE);
} else {
if ((m = find_method (this, name.v.str->str))) {
ret.type = STR;
ret.v.str = string_new (0);
ret.v.str = decompile_method (ret.v.str, this, m, lineno.v.num,
brackets.v.num, indent.v.num, 0, 0, 0);
push (ret);
} else {
raise (E_METHODNF);
}
}
var_free (name);
}
void op_decompile (void)
{
Var ret;
ret.type = STR;
ret.v.str = decompile_object (this);
push (ret);
}
void op_find_method (void)
{
Var arg, ret;
Object *where;
arg = pop ();
if (arg.type != STR) {
raise (E_ARGTYPE);
} else {
(void) find_method_recursive (this, arg.v.str->str, &where);
ret.type = OBJ;
if (where) {
ret.v.obj = where->id;
} else {
ret.v.obj.server = 0;
ret.v.obj.id = NOTHING;
}
push (ret);
} /* if */
var_free (arg);
}
void op_this (void)
{
Var v;
v.type = OBJ;
v.v.obj = frame.this;
push (v);
}
void op_player (void)
{
Var v;
v.type = OBJ;
v.v.obj = frame.player;
push (v);
}
void op_caller (void)
{
Var v;
v.type = OBJ;
v.v.obj = frame.caller;
push (v);
}
void op_args (void)
{
Var v;
v.type = LIST;
v.v.list = list_dup (frame.args);
push (v);
}
void op_setplayer (void)
{
Var newplayer;
newplayer = pop ();
if (newplayer.type != OBJ) {
raise (E_ARGTYPE);
} else {
frame.player = newplayer.v.obj;
}
var_free (newplayer);
}
void op_program(void)
{
while (nargs--) {
var_free(pop());
}
pushn (0);
}
static Playerid progr;
static const char *mem_code;
static int code_pos, mem_eof;
static int mem_getc (void);
static void mem_ungetc (int c);
static void mem_perror (const char *s);
static int mem_getc (void)
{
if (mem_code[code_pos]) {
return mem_code[code_pos++];
} else {
mem_eof = 1;
return EOF;
}
}
static void mem_ungetc (int c)
{
if (code_pos > 0 && !mem_eof) {
code_pos--;
}
}
static void mem_perror (const char *s)
{
tell(progr, s, 1 );
}
void op_compile (void)
{
Var obj, method, pcode;
Object *o;
pcode = pop ();
if (pcode.type != STR) {
var_free (pcode);
while (--nargs) {
method = pop ();
var_free (method);
}
raise (E_ARGTYPE);
return;
}
mem_code = pcode.v.str->str;
code_pos = 0;
mem_eof = 0;
progr = frame.this.id;
switch (nargs) {
case 1: /* program some objects */
pushn (compile (progr, mem_getc, mem_ungetc, mem_perror, 0, 0, 0, 0, 0));
break;
case 2: /* invalid */
method = pop ();
var_free (method);
raise (E_RANGE);
break;
case 3: /* program a single method */
method = pop ();
obj = pop ();
if (obj.type != OBJ || method.type != STR) {
raise (E_ARGTYPE);
} else if (!(o = retrieve (obj.v.obj))) {
raise (E_OBJNF);
} else if (!can_program(frame.player, obj.v.obj)) {
raise (E_PERM);
} else if (!valid_ident (method.v.str->str)) {
raise (E_METHODNF); /* not quite the right error, but hey */
} else {
pushn (compile (progr, mem_getc, mem_ungetc, mem_perror, 1, o,
method.v.str, 0, 0));
}
var_free (obj);
var_free (method);
this = retrieve (frame.this); /* in case we recompiled "this" */
break;
}
var_free (pcode);
}
void op_verb (void)
{
Var verb, method, prep;
int verbno, methodno, prepno;
method = pop ();
prep = pop ();
verb = pop ();
if (verb.type != STR || prep.type != STR || method.type != STR) {
var_free (verb);
var_free (prep);
var_free (method);
raise (E_ARGTYPE);
} else {
verbno = sym_add (this, verb.v.str);
if (prep.v.str->str[0]) {
prepno = sym_add (this, prep.v.str);
} else {
string_free (prep.v.str);
prepno = -1;
}
methodno = sym_add (this, method.v.str);
verb_add (this, verbno, prepno, methodno);
cache_put (this, frame.this.id);
pushn (0);
}
}
void op_rmverb (void)
{
Var verb;
verb = pop ();
if (verb.type != STR) {
raise (E_ARGTYPE);
} else {
if (verb_rm(this, verb.v.str->str)) {
pushn(0);
} else {
raise(E_VERBNF);
}
cache_put (this, frame.this.id);
}
var_free (verb);
}
void op_rmmethod (void)
{
Var method;
method = pop ();
if (method.type != STR) {
raise (E_ARGTYPE);
} else {
raise (rm_method (this, method.v.str->str));
cache_put (this, frame.this.id);
}
var_free (method);
}
void op_rmvar (void)
{
Var varname;
varname = pop ();
if (varname.type != STR) {
raise (E_ARGTYPE);
} else {
raise (var_rm_global (this, varname.v.str->str));
cache_put (this, frame.this.id);
}
var_free (varname);
}
void op_listinsert (void)
{
Var list, value, pos;
pos.type = NUM;
pos.v.num = -1;
if (nargs > 2) {
pos = pop ();
}
value = pop ();
list = pop ();
if (list.type != LIST || pos.type != NUM) {
var_free (pos);
var_free (list);
var_free (value);
raise (E_ARGTYPE);
} else if (pos.v.num > list.v.list->len) {
raise (E_RANGE);
} else {
list.v.list = list_insert (list.v.list, value, pos.v.num);
push (list);
}
}
void op_listappend (void)
{
Var list, value, pos;
pos.type = NUM;
pos.v.num = -1;
if (nargs > 2) {
pos = pop ();
}
value = pop ();
list = pop ();
if (list.type != LIST || pos.type != NUM) {
var_free (pos);
var_free (list);
var_free (value);
raise (E_ARGTYPE);
} else if (pos.v.num > list.v.list->len) {
var_free(pos); var_free(list); var_free(value);
raise (E_RANGE);
} else {
list.v.list = list_append (list.v.list, value, pos.v.num);
push (list);
}
}
void op_listdelete (void)
{
Var pos; /* position to delete */
Var list; /* list to delete it from */
pos = pop ();
list = pop ();
if (list.type != LIST || pos.type != NUM) {
var_free (pos);
var_free (list);
raise (E_ARGTYPE);
} else if (pos.v.num < 1 || pos.v.num > list.v.list->len) {
var_free (list);
raise (E_RANGE);
} else {
list.v.list = list_delete (list.v.list, pos.v.num);
push (list);
}
}
void op_listassign (void)
{
Var pos; /* position to assign */
Var value; /* value to assign it */
Var list; /* list to modify */
pos = pop ();
value = pop ();
list = pop ();
if (list.type != LIST || pos.type != NUM) {
var_free (pos);
var_free (list);
var_free (value);
raise (E_ARGTYPE);
} else if (pos.v.num < 1 || pos.v.num > list.v.list->len) {
var_free (list);
var_free (value);
raise (E_RANGE);
} else {
list.v.list = list_assign (list.v.list, value, pos.v.num);
push (list);
}
}
void op_sort(void)
{
int reverseflag = 0;
Var list, reverse, ret;
if (nargs > 1) {
reverse = pop();
reverseflag = ISTRUE(reverse);
var_free(reverse);
}
list = pop();
if (list.type != LIST) {
var_free(list);
raise(E_ARGTYPE);
} else {
ret.type = LIST;
ret.v.list = list_sort(list.v.list, reverseflag);
push(ret);
}
}
void op_strsub(void)
{
Var source, what, with, caseflag, ret;
caseflag.type = NUM; caseflag.v.num = 0;
if (nargs > 3) {
caseflag = pop ();
}
with = pop ();
what = pop ();
source = pop ();
if (source.type != STR || what.type != STR || with.type != STR) {
raise (E_ARGTYPE);
} else {
ret.type = STR;
ret.v.str = strsub (source.v.str->str, what.v.str->str, with.v.str->str,
ISTRUE (caseflag));
push (ret);
}
var_free (source);
var_free (what);
var_free (with);
var_free (caseflag);
}
void op_psub (void)
{
Var source, ret;
source = pop ();
if (source.type != STR) {
raise (E_ARGTYPE);
} else {
ret.type = STR;
ret.v.str = psub (source.v.str->str);
push (ret);
}
var_free (source);
}
void op_servers (void)
{
Var servlist;
servlist.type = LIST;
servlist.v.list = list_dup (server_list);
push (servlist);
}
void op_ps (void)
{
Var v;
v.type = LIST; v.v.list = ps();
push (v);
} /* op_ps() */
void op_kill (void)
{
Var pid;
int r;
pid = pop ();
if (pid.type != NUM) {
var_free (pid);
raise (E_ARGTYPE);
} else {
r = cmkill (pid.v.num, frame.caller);
switch (r) {
case 0:
case -1:
pushn (r);
break;
case -2:
raise (E_PERM);
break;
}
} /* if */
} /* op_kill() */
void op_set_parse(void)
{
Var id, oid;
oid = pop(); id = pop();
if (oid.type != OBJ || id.type != NUM) {
var_free(oid); var_free(id);
raise(E_ARGTYPE);
} else if (!is_wizard(frame.this)) {
raise(E_PERM);
} else {
set_parse(id.v.num, oid.v.obj.id);
pushn(0);
}
}