/* Copyright (c) 1993 Stephen F. White */
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
#include <sys/time.h>
#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_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, GENPTR what2)
{
GENPTR *progwhat = MALLOC(GENPTR, 2);
progwhat[0] = (GENPTR) 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,
(GENPTR) 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() */