/* 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 {
frame.pc++; /* ignore nargs */
server_running = 0;
pushn (0);
}
}
void op_dump (void)
{
frame.pc++; /* ignore nargs */
if (!is_wizard (frame.this)) {
raise (E_PERM);
} else {
cache_sync ();
pushn (0);
}
}
void op_writelog (void)
{
Var arg;
arg = pop ();
frame.pc++; /* ignore nargs */
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_boot (void)
{
frame.pc++; /* ignore nargs */
boot (frame.this.id);
pushn (0);
}
void op_raise (void)
{
Var e;
List *raise_args;
frame.pc++; /* ignore nargs */
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)
{
int nargs;
Objid parent;
Var args;
nargs = frame.m->code[frame.pc++];
parent.server = 0;
parent.id = frame.m->code[frame.pc++];
args = pop_args (nargs);
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;
frame.pc++; /* skip nargs */
parent = pop ();
if (parent.type != OBJ) {
var_free (parent);
raise (E_ARGTYPE);
} else {
pushn (hasparent (this, parent.v.obj));
}
}
void op_objsize (void)
{
frame.pc++; /* skip nargs */
pushn (size_object (this));
}
void op_spew_method (void)
{
Var name, ret;
Method *m;
frame.pc++; /* skip nargs */
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)
{
int nargs = frame.m->code[frame.pc++];
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;
frame.pc++; /* skip nargs */
ret.type = STR;
ret.v.str = decompile_object (this);
push (ret);
}
void op_find_method (void)
{
Var arg, ret;
Object *where;
frame.pc++; /* skip nargs */
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);
}
static void do_programming (Playerid id, int what1, void *what2)
{
void **progwhat = MALLOC (void *, 2);
progwhat[0] = (void *) what1;
progwhat[1] = what2;
if (start_programming (id, progwhat)) {
tell (id, "Couldn't enter programming mode -- can't open temp file.");
} else {
tell (id, "Entering programming mode. Use \".\" to end input.");
}
}
void op_program (void)
{
Var obj, method;
switch (frame.m->code[frame.pc++]) {
case 0: /* program some objects */
do_programming (frame.this.id, -1, 0);
pushn (0);
break;
case 1: /* invalid */
method = pop ();
var_free (method);
raise (E_RANGE);
break;
case 2: /* program a single method */
method = pop ();
obj = pop ();
if (obj.type != OBJ || method.type != STR) {
raise (E_ARGTYPE);
} else if (!valid (obj.v.obj)) {
raise (E_OBJNF);
} else if (!can_program (frame.this, 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 {
do_programming (frame.this.id, obj.v.obj.id,
(void *) string_dup (method.v.str));
pushn (0);
}
var_free (obj);
var_free (method);
break;
}
}
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);
}
void op_compile (void)
{
Var obj, method, pcode;
int nargs = frame.m->code[frame.pc++];
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.this, 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;
frame.pc++; /* ignore nargs */
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;
frame.pc++;
verb = pop ();
if (verb.type != STR) {
raise (E_ARGTYPE);
} else {
pushn (verb_rm (this, verb.v.str->str));
cache_put (this, frame.this.id);
}
var_free (verb);
}
void op_rmmethod (void)
{
Var method;
frame.pc++;
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;
frame.pc++;
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)
{
int nargs = frame.m->code[frame.pc++];
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)
{
int nargs = frame.m->code[frame.pc++];
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_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 ();
frame.pc++; /* skip nargs */
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 ();
frame.pc++; /* skip nargs */
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_strsub (void)
{
int nargs;
Var source, what, with, caseflag, ret;
caseflag.type = NUM;
caseflag.v.num = 0;
nargs = frame.m->code[frame.pc++];
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 ();
frame.pc++; /* skip nargs */
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);
frame.pc++; /* skip nargs */
push (servlist);
}
void op_ps (void)
{
Var v;
frame.pc++; /* skip nargs */
v.type = LIST;
v.v.list = ps ();
push (v);
} /* op_ps() */
void op_kill (void)
{
Var pid;
int r;
frame.pc++; /* skip nargs */
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() */