/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/interp.c,v 1.15 90/09/28 12:23:30 rearl Exp $ */ /* * $Log: interp.c,v $ * Revision 1.15 90/09/28 12:23:30 rearl * Took out some useless stuff, added more speed enhancements, fixed * negative ROTATE operation. * * Revision 1.14 90/09/24 20:46:00 rearl * Pre-rewrite checkin. * * Revision 1.13 90/09/18 07:58:52 rearl * Changed lots of stuff, upper/lowercase lookup, speedups with register * declarations, fixed a few primitives. * * Revision 1.12 90/09/16 04:42:21 rearl * Preparation code added for disk-based MUCK. * * Revision 1.11 90/09/15 22:24:17 rearl * Put in negative operand ROTATE. Fixed a few COMPRESS property bugs. * * Revision 1.10 90/09/13 06:26:12 rearl * Added unreadable properties, ok_name() check in setname, EXECUTE. * * Revision 1.9 90/09/12 09:01:15 rearl * Added ELSE constructs as well as quoted functions with the EXECUTE * primitive. * * Revision 1.8 90/09/01 05:58:12 rearl * Fixed compress conflicts with SET<field>, also null string * possibility in SETNAME. * * Revision 1.7 90/08/27 03:27:36 rearl * Simplified type-checking, aborting, added some new primitives. * Fixed CONTENTS so it returns dbrefs in the correct order. * * Revision 1.6 90/08/06 18:04:41 rearl * EXPLODE and SUBST work with any delimit/replacement string of length > 0, * fixed NULL bug in strncmp, fixed some interpreter error messages. * * Revision 1.5 90/08/05 03:19:21 rearl * Redid matching routines. * * Revision 1.4 90/07/29 23:46:26 rearl * Added string primitives: strncmp, strcut, strlen. * * Revision 1.3 90/07/29 17:37:11 rearl * Added writeonly flag (for ROOM programs), debugging support, * fixed Wizard priveledges once again, but not permanently as yet. * * Revision 1.2 90/07/22 04:25:45 casie * Added pronoun_sub primitive for o-message-like % substitutions. * * Revision 1.1 90/07/19 23:03:47 casie * Initial revision * * */ #include "copyright.h" #include "config.h" #include <sys/types.h> #include "db.h" #include "inst.h" #include "externs.h" #include "match.h" #include "interface.h" #include "params.h" #include "strings.h" /* This package performs the interpretation of mud forth programs. It is a basically push pop kinda thing, but I'm making some stuff inline for maximum efficiency. Oh yeah, because it is an interpreted language, please do type checking during this time. While you're at it, any objects you are referencing should be checked against db_top. */ /* in cases of boolean expressions, we do return a value, the stuff that's on top of a stack when a mud-forth program finishes executing. In cases where they don't, leave a value, we just return a 0. Note: this stuff does not return string or whatnot. It at most can be relied on to return a boolean value. interp sets up a player's frames and so on and prepares it for execution. */ /* Some icky machine/compiler #defines. --jim */ /* #ifdef __GNUC__ #define INLINE inline #else #define INLINE #endif */ #define INLINE #ifdef MIPS typedef char * voidptr; #define MIPSCAST (char *) #else typedef void * voidptr; #define MIPSCAST #endif #define UPCASE(x) (uppercase[x]) #define DOWNCASE(x) (lowercase[x]) #define DoNullInd(x) ((x) ? (x) -> data : "") INLINE void push (struct inst *stack, int *top, int type, voidptr res); INLINE int valid_object(struct inst *oper); void dispatch(dbref player, dbref program, struct inst *pc, struct inst *arg, int *top, struct frame *fr); int interp(dbref player, dbref program, dbref source) { struct frame *fr; fr = DBFETCH(player)->run = (struct frame *) calloc(1, sizeof(struct frame)); if (!can_link_to(source, TYPE_EXIT, program) && (OWNER(source) != OWNER(program))) /* in case owner of source is quell */ { notify(player, "Program call: Permission denied."); return 0; } if (DBFETCH(program)->sp.program.start == 0) { /* try to compile it... */ DBSTORE(program, sp.program.first, read_program(program)); do_compile(player, program); free_prog_text(DBFETCH(program)->sp.program.first); } if (DBFETCH(program)->sp.program.start == 0) { /* compile failed... */ notify(player, "Program not compiled. Cannot run."); free((void *) fr); return 0; } fr -> system.top = 1; fr -> argument.top = 0; fr -> pc = DBFETCH(program)->sp.program.start; fr -> writeonly = ((Typeof(source) == TYPE_ROOM) || (FLAGS(player)&INTERACTIVE)); /* set basic variables */ fr -> variables[0].type = PROG_OBJECT; fr -> variables[0].data.number = player; fr -> variables[1].type = PROG_OBJECT; fr -> variables[1].data.number = DBFETCH(player)->location; fr -> variables[2].type = PROG_OBJECT; fr -> variables[2].data.number = source; push(fr->argument.st, &(fr->argument.top), PROG_STRING, match_args ? MIPSCAST alloc_prog_string(match_args) : 0); return (interp_loop(player, program, fr)); } /* clean up the stack. */ INLINE void prog_clean(struct frame *fr) { int i; fr -> system.top = 0; for (i = 0; i < fr -> argument.top; i++) CLEAR(&fr -> argument.st[i]); for (i = 0; i < MAX_VAR; i++) CLEAR(&fr -> variables[i]); fr -> argument.top = 0; fr -> pc = 0; } INLINE void reload(struct frame *fr, int atop, int stop) { fr -> argument.top = atop; fr -> system.top = stop; } INLINE int false (struct inst *p) { return ( (p -> type == PROG_STRING && (p -> data.string == 0 || !(*p -> data.string->data))) || (p -> type == PROG_INTEGER && p -> data.number == 0) || (p -> type == PROG_OBJECT && p -> data.objref == NOTHING) ); } static int err; static int already_created; INLINE void copyinst(struct inst *from, struct inst *to) { *to = *from; if (from -> type == PROG_STRING && from -> data.string) { from -> data.string->links++; } } #define abort_loop(S) { notify(player, S); reload(fr, atop, stop); prog_clean(fr); return 0; } int interp_loop(dbref player, dbref program, struct frame *fr) { register struct inst *pc; register int atop; register struct inst *arg; register struct inst *temp1; register struct inst *temp2; register struct inst *sys; register int stop; int tmp, writeonly; dbref obj; /* load everything into local stuff */ pc = fr -> pc; atop = fr -> argument.top; stop = fr -> system.top; arg = fr -> argument.st; sys = fr -> system.st; writeonly = fr -> writeonly; already_created = 0; if (!pc) { notify(player, "Program not compiled. Cannot run."); return 0; } err = 0; /* This is the 'natural' way to exit a function */ while (stop) { if (FLAGS(program) & DARK) { /* if trace mode -- lpb */ char *m; m = debug_inst(pc, arg, atop, program); notify(player, m); } switch (pc -> type) { case PROG_INTEGER: case PROG_ADD: case PROG_OBJECT: case PROG_VAR: case PROG_STRING: if (atop >= STACK_SIZE) abort_loop("Program Constant: Stack overflow."); copyinst(pc, arg + atop); pc++; atop++; break; case PROG_PRIMITIVE: /* All pc modifiers and stuff like that should stay here, everything else call with an independent dispatcher. */ switch (pc -> data.number) { case IN_IF: if (atop < 2) abort_loop("IF: Stack Underflow."); temp1 = arg + --atop; temp2 = arg + --atop; if (temp1->type != PROG_ADD) { CLEAR(temp2); abort_loop("Program internal error. Aborted."); } if ( false(temp2) ) pc = temp1->data.call; else pc++; CLEAR(temp2); break; case IN_JMP: if (atop < 1) abort_loop("Program internal error. Aborted."); temp1 = arg + --atop; if (temp1->type != PROG_ADD) abort_loop("Program internal error. Aborted."); pc = temp1->data.call; break; case IN_EXECUTE: if (atop < 1) abort_loop("Program word: Stack Underflow."); temp1 = arg + --atop; if (temp1->type != PROG_ADD) abort_loop("Program word: Program internal error."); if (stop >= STACK_SIZE) abort_loop("Program word: Stack Overflow"); sys[stop++].data.call = pc + 1; pc = temp1->data.call; break; case IN_CALL: if (atop < 1) abort_loop("CALL: Stack Underflow."); temp1 = arg + --atop; if (!valid_object(temp1) || Typeof(temp1->data.objref) != TYPE_PROGRAM) abort_loop("CALL: Invalid object."); obj = temp1->data.objref; if(OWNER(obj) != (((FLAGS(program) & STICKY) != 0) ? OWNER(program) : OWNER(player)) && !Linkable(obj) && !Wizard(program)) abort_loop("CALL: Permission denied."); if (stop >= STACK_SIZE) abort_loop("CALL: Stack Overflow."); if (atop >= STACK_SIZE) abort_loop("CALL: Stack Overflow."); if (DBFETCH(obj)->sp.program.start == 0) { /* try to compile it... */ DBSTORE(obj, sp.program.first, read_program(obj)); do_compile(player, obj); free_prog_text(DBFETCH(obj)->sp.program.first); } if (DBFETCH(obj)->sp.program.start == 0) { /* compile failed... */ abort_loop("Program not compiled."); } sys[stop++].data.call = pc + 1; pc = DBFETCH(obj)->sp.program.start; if(FLAGS(obj)&ARCHITECT) { tmp = atop; push(arg, &tmp, PROG_OBJECT, MIPSCAST &program); atop = tmp; } program = obj; break; case IN_PROGRAM: if (atop < 1) abort_loop("Program internal error -- aborted in_program."); temp1 = arg + --atop; if (!valid_object(temp1) || Typeof(temp1->data.objref) != TYPE_PROGRAM || (!(DBFETCH(temp1->data.objref)->sp.program.code))) abort_loop("Program internal error -- aborted. in_program!"); program = temp1->data.objref; pc++; break; case IN_RET: pc = sys[--stop].data.call; break; case IN_READ: if (writeonly) abort_loop("READ: Program is write-only."); FLAGS(player) |= INTERACTIVE; reload(fr, atop, stop); DBSTORE(player, run -> pc, pc + 1); DBSTORE(player, curr_prog, program); return 0; /*NOTREACHED*/ break; default: tmp = atop; dispatch(player, program, pc, arg, &tmp, fr); atop = tmp; pc++; break; } /* switch */ break; default: abort_loop("Program internal error. Aborted."); } /* switch */ if (err) { reload(fr, atop, stop); prog_clean(fr); return 0; } } /* while */ if (atop) { int retval; retval = !false(arg + atop - 1); reload(fr, atop, stop); prog_clean(fr); return retval; } reload(fr, atop, stop); prog_clean(fr); return 0; } void interp_err(dbref player, const char *msg1, const char *msg2) { char buf[BUFSIZ]; err++; notify(player, "Programmer Error. Tell whoever made this program the next message."); strcpy(buf, msg1); strcat(buf, ": "); strcat(buf, msg2); notify(player, buf); } INLINE void push (struct inst *stack, int *top, int type, voidptr res) { stack[*top].type = type; switch (type) { case PROG_VAR: case PROG_INTEGER: stack[*top].data.number = *(int *)res; break; case PROG_STRING: stack[*top].data.string = (struct shared_string *)res; break; case PROG_OBJECT: stack[*top].data.objref = *(dbref *)res; break; case PROG_CON: stack[*top].data.con = (struct descriptor_data *)res; break; case PROG_ADD: stack[*top].data.call = (struct inst *) res; break; } (*top)++; } INLINE void copyobj(dbref player, dbref old, dbref new) { struct object *oldp = DBFETCH(old); struct object *newp = DBFETCH(new); NAME(new) = alloc_string(NAME(old)); newp->attributes = copy_attr(old); newp->properties = copy_prop(old); newp->key = copy_bool(oldp->key); newp->exits = NOTHING; newp->contents = NOTHING; newp->location = NOTHING; newp->next = NOTHING; /* printf("Player: %d, loc %d, new: %d\n",player,DBFETCH(player)->location, new); */ moveto(new, (DBFETCH(player)->location==NOTHING)?player: DBFETCH(player)->location); sprintf(buf, "#%d", (int) new); add_attr(player, "It", buf); DBDIRTY(new); } INLINE int valid_object(struct inst *oper) { return ((oper->type == PROG_OBJECT) #ifdef RECYCLE && (Typeof(oper->data.objref) != TYPE_GARBAGE) #else /* RECYCLE */ && (oper->data.objref < db_top) #endif /* RECYCLE */ && (oper->data.objref >= 0)); } INLINE int is_home(struct inst *oper) { return (oper->type == PROG_OBJECT && oper->data.objref == HOME); } INLINE int permissions(dbref player, dbref thing) { if (thing == player || thing == HOME) return 1; switch (Typeof(thing)) { case TYPE_PLAYER: return 0; case TYPE_EXIT: return ((OWNER(thing) == player) || (OWNER(thing) == NOTHING)); case TYPE_ROOM: case TYPE_THING: case TYPE_PROGRAM: return (OWNER(thing) == player); } return 0; } INLINE int arith_type(struct inst *op1, struct inst *op2) { return ((op1->type == PROG_INTEGER && op2->type == PROG_INTEGER) /* real stuff */ || (op1->type == PROG_VAR && op2->type == PROG_INTEGER)); /* offset array */ } #define CHECKOP(N) { if ((*top) < (N)) { interp_err(player, insttotext(pc), "Stack underflow."); return; } nargs = (N); } #define POP() (arg + --(*top)) #define abort_interp(C) { interp_err(player, insttotext(pc), (C)); \ switch(nargs) { \ case 4: CLEAR(oper4); \ case 3: CLEAR(oper3); \ case 2: CLEAR(oper2); \ case 1: CLEAR(oper1); } \ return; } /* Regular primitive dispatcher. Basically one HUGE switch. */ void dispatch(dbref player, dbref program, struct inst *pc, struct inst *arg, int *top, struct frame *fr) { register struct inst *oper1, *oper2, *oper3, *oper4; struct inst temp1, temp2, temp3; struct inst *add, *sys; int result; struct shared_string *string; char buf[BUFFER_LEN]; dbref ref; dbref uid; int nargs = 0; /* DO NOT TOUCH THIS VARIABLE */ int tmp; long ltmp; int wizard; int mucker; int stop; stop = fr -> system.top; sys = fr -> system.st; wizard = (Wizard(program)); #ifndef MUCKER_ALL mucker = (Wizard(program) || FLAGS(program)&MUCKER); #else mucker = 1; #endif /* MUCKER_ALL */ uid = (((FLAGS(program) & STICKY) != 0) ? OWNER(program) : player); switch (pc -> data.number) { case IN_ADD: case IN_SUBTRACT: case IN_MULTIPLY: case IN_DIVIDE: case IN_MOD: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (!arith_type(oper2, oper1)) abort_interp("Invalid argument type."); if (pc -> data.number == IN_ADD) result = oper1->data.number + oper2->data.number; else if (pc -> data.number == IN_SUBTRACT) result = oper2->data.number - oper1->data.number; else if (pc -> data.number == IN_MULTIPLY) result = oper1->data.number * oper2->data.number; else if (pc -> data.number == IN_MOD) { if (oper1->data.number) result = oper2->data.number % oper1->data.number; else result = 0; } else { if (oper1->data.number) result = oper2->data.number / oper1->data.number; else result = 0; } CLEAR(oper1); CLEAR(oper2); push(arg, top, oper2->type, MIPSCAST &result); break; case IN_POP: CHECKOP(1); oper1 = POP(); CLEAR(oper1); break; case IN_DUP: CHECKOP(1); copyinst(&arg[*top - 1], &arg[*top]); (*top)++; break; case IN_NUMBERP: CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_STRING || !oper1->data.string) result = 0; else result = number(oper1->data.string->data); CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_STRINGCMP: case IN_STRCMP: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_STRING || oper2->type != PROG_STRING) abort_interp("Non-string argument."); if (oper1->data.string == oper2->data.string) result = 0; else if (!(oper2->data.string && oper1->data.string)) result = oper1->data.string ? -1 : 1; else { if (pc -> data.number == IN_STRCMP) result = strcmp(oper2->data.string->data, oper1->data.string->data); else /* IN_STRINGCMP */ result = string_compare(oper2->data.string->data, oper1->data.string->data); } CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_STRINGNCMP: case IN_STRNCMP: CHECKOP(3); oper1 = POP(); oper2 = POP(); oper3 = POP(); if (oper1->type != PROG_INTEGER) abort_interp("Non-integer argument."); if (oper2->type != PROG_STRING || oper3->type != PROG_STRING) abort_interp("Non-string argument."); if (oper2->data.string == oper3->data.string) result = 0; else if (!(oper3->data.string && oper2->data.string)) result = oper2->data.string ? -1 : 1; else if (pc -> data.number == IN_STRNCMP) result = strncmp(oper3->data.string->data, oper2->data.string->data, oper1->data.number); else result = strncasecmp(oper3->data.string->data, oper2->data.string->data, oper1->data.number); CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_STRCUT: CHECKOP(2); temp1 = *(oper1 = POP()); temp2 = *(oper2 = POP()); if (temp1.type != PROG_INTEGER) abort_interp("Non-integer argument (2)"); if (temp1.data.number < 0) abort_interp("Argument must be a positive integer."); if (temp2.type != PROG_STRING) abort_interp("Non-string argument (1)"); if (!temp2.data.string) { push(arg, top, PROG_STRING, 0); push(arg, top, PROG_STRING, 0); } else { if (temp1.data.number > temp2.data.string->length) { temp2.data.string->links++; push(arg, top, PROG_STRING, MIPSCAST temp2.data.string); push(arg, top, PROG_STRING, 0); } else { bcopy(temp2.data.string->data, buf, temp1.data.number); buf[temp1.data.number] = '\0'; push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); if (temp2.data.string->length > temp1.data.number) { bcopy(temp2.data.string->data + temp1.data.number, buf, temp2.data.string->length - temp1.data.number + 1); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); } else { push(arg, top, PROG_STRING, 0); } } } CLEAR(&temp1); CLEAR(&temp2); break; case IN_STRLEN: CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_STRING) abort_interp("Non-string argument."); if (!oper1->data.string) result = 0; else result = oper1->data.string->length; CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_STRCAT: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_STRING || oper2->type != PROG_STRING) abort_interp("Non-string argument."); if (!oper1->data.string && !oper2->data.string) string = NULL; else if (!oper2->data.string) { oper1->data.string->links++; string = oper1->data.string; } else if (!oper1->data.string) { oper2->data.string->links++; string = oper2->data.string; } else if (oper1->data.string->length + oper2->data.string->length > (BUFFER_LEN) - 1) { abort_interp("Operation would result in overflow."); } else { bcopy(oper2->data.string->data, buf, oper2->data.string->length); bcopy(oper1->data.string->data, buf + oper2->data.string->length, oper1->data.string->length + 1); string = alloc_prog_string(buf); } CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_STRING, MIPSCAST string); break; case IN_AND: case IN_OR: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (pc -> data.number == IN_AND) result = !false(oper1) && !false(oper2); else result = !false(oper1) || !false(oper2); CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_NOT: CHECKOP(1); oper1 = POP(); result = false(oper1); CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_NOTIFY: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (!valid_object(oper2)) abort_interp("Invalid object (1)"); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (2)"); if (oper1->data.string) notify(oper2->data.objref, oper1->data.string->data); CLEAR(oper1); CLEAR(oper2); break; case IN_NOTIFY_EXCEPT: CHECKOP(3); oper1 = POP(); oper2 = POP(); oper3 = POP(); if (!valid_object(oper3)) abort_interp("Non-room argument (1)"); if (oper2->type != PROG_OBJECT) abort_interp("Invalid object argument (2)"); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (3)"); if (oper1->data.string) notify_except(DBFETCH(oper3->data.objref)->contents, oper2->data.objref, oper1->data.string->data); CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); break; case IN_ADDPENNIES: CHECKOP(2); oper1 = POP(); oper2 = POP(); if(!mucker) abort_interp("Permission denied."); if (!valid_object(oper2)) abort_interp("Invalid object."); if (oper1->type != PROG_INTEGER) abort_interp("Non-integer argument (2)"); ref = oper2->data.objref; if (Typeof(ref) == TYPE_PLAYER) { result = DBFETCH(ref)->sp.player.pennies + oper1->data.number; if ((result > MAX_PENNIES) && !wizard) abort_interp("Would exceed MAX_PENNIES."); if ((result < 0) && !wizard) abort_interp("Amount would be negative."); DBFETCH(ref)->sp.player.pennies += oper1->data.number; DBDIRTY(ref); } else if (Typeof(ref) == TYPE_THING) { if (!wizard) abort_interp("Permission denied."); result = DBFETCH(ref)->sp.thing.value + oper1->data.number; if (result < 1) abort_interp("Result must be positive."); DBFETCH(ref)->sp.thing.value += oper1->data.number; DBDIRTY(ref); } else { abort_interp("Invalid object type."); } CLEAR(oper1); CLEAR(oper2); break; case IN_AT: CHECKOP(1); temp1 = *(oper1 = POP()); if (temp1.type != PROG_VAR || temp1.data.number >= MAX_VAR) abort_interp("Non-variable argument."); copyinst(&(fr -> variables[temp1.data.number]), &arg[(*top)++]); CLEAR(&temp1); break; case IN_BANG: CHECKOP(2); oper1 = POP(); oper2 = POP(); if(oper1->type != PROG_VAR || oper1->data.number >= MAX_VAR || oper1->data.number < 0) abort_interp("Non-variable argument (2)"); CLEAR(&fr -> variables[oper1->data.number]); copyinst(oper2, &(fr -> variables[oper1->data.number])); CLEAR(oper1); CLEAR(oper2); break; case IN_GETPROPVAL: case IN_GETPROPSTR: case IN_REMOVE_PROP: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (2)"); if (!oper1->data.string) abort_interp("Empty string argument (2)"); if (!valid_object(oper2)) abort_interp("Non-object argument (1)"); if (pc -> data.number == IN_REMOVE_PROP) { if (!wizard && (!permissions(uid, oper2->data.objref) && (*oper1->data.string->data != PROP_WRITABLE))) abort_interp("Permission denied."); remove_property(oper2->data.objref, oper1->data.string->data); CLEAR(oper1); CLEAR(oper2); } else { const char *temp; if ((*oper1->data.string->data == PROP_PRIVATE || *oper1->data.string->data == PROP_WIZARD) && !permissions(uid, oper2->data.objref) && !wizard) abort_interp("Permission denied."); temp = get_property_class(oper2->data.objref, oper1->data.string->data); if (pc -> data.number == IN_GETPROPVAL) { result = temp ? atoi(temp) : 0; CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &result); } else { CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(temp)); } } break; case IN_SETPROP: CHECKOP(3); oper1 = POP(); oper2 = POP(); oper3 = POP(); if ((oper1->type != PROG_STRING) && (oper1->type != PROG_INTEGER)) abort_interp("Non-string/non-integer argument (3)"); if (oper2->type != PROG_STRING) abort_interp("Non-string argument (2)"); if (!oper2->data.string) abort_interp("Empty string argument (2)"); if (!valid_object(oper3)) abort_interp("Non-object argument (1)"); if (!wizard && (*oper2->data.string->data != PROP_WRITABLE) && !permissions(uid, oper3->data.objref)) abort_interp("Permission denied."); if (!wizard && (*oper2->data.string->data == PROP_WIZARD)) if(!get_property_class(oper3->data.objref, oper2->data.string->data)) abort_interp("Permission denied."); { const char *temp; if(oper1->type == PROG_INTEGER) { sprintf(buf, "%d", oper1->data.number); temp = alloc_string(buf); add_property(oper3->data.objref, oper2->data.string->data, temp); free((void *) temp); } else { temp = oper1->data.string ? oper1->data.string->data : 0; if(!temp) remove_property(oper3->data.objref, oper2->data.string->data); else add_property(oper3->data.objref, oper2->data.string->data, temp); } } CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); break; case IN_MOVETO: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (!(valid_object(oper1) && valid_object(oper2)) && !is_home(oper1)) abort_interp("Non-object argument."); { dbref victim, dest; victim = oper2->data.objref; dest = oper1->data.objref; if (Typeof(dest) == TYPE_EXIT || Typeof(victim) == TYPE_EXIT) abort_interp("Argument is an exit."); if (!(FLAGS(victim) & JUMP_OK) && !permissions(uid, victim) && !wizard) abort_interp("Object can't be moved."); switch (Typeof(victim)) { case TYPE_PLAYER: case TYPE_PROGRAM: case TYPE_THING: if (Typeof(dest) != TYPE_ROOM && Typeof(dest) != TYPE_PLAYER && Typeof(dest) != TYPE_THING) abort_interp("Bad destination."); /* Check permissions */ if(is_ok(victim) && is_ok(dest)) /* might be home. */ if(parent_loop_check(victim,dest)) abort_interp("Would create a loop."); if (!wizard) { if (!(FLAGS(DBFETCH(victim)->location) & JUMP_OK) && (uid != OWNER(DBFETCH(victim)->location))) abort_interp("Source not JUMP_OK."); if (!is_home(oper1) && !(FLAGS(dest) & JUMP_OK) && (uid != OWNER(dest))) abort_interp("Destination not JUMP_OK."); } moveto(victim,dest); break; case TYPE_ROOM: if (Typeof(dest) != TYPE_ROOM) abort_interp("Bad destination."); if (victim == GLOBAL_ENVIRONMENT) abort_interp("Permission denied."); if (dest == HOME) { dest = GLOBAL_ENVIRONMENT; } else { if (!wizard && !permissions(uid, victim) || !can_link_to(uid, NOTYPE, dest)) abort_interp("Permission denied."); if (parent_loop_check(victim, dest)) { abort_interp("Parent room would create a loop."); } } moveto(victim, dest); break; default: abort_interp("Invalid object type (1)"); } } CLEAR(oper1); CLEAR(oper2); break; case IN_PENNIES: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid argument."); switch(Typeof(oper1->data.objref)) { case TYPE_PLAYER: result = DBFETCH(oper1->data.objref)->sp.player.pennies; break; case TYPE_THING: result = DBFETCH(oper1->data.objref)->sp.thing.value; break; default: abort_interp("Invalid argument."); } CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_LESSTHAN: case IN_GREATHAN: case IN_EQUAL: case IN_LESSEQ: case IN_GREATEQ: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (!(oper1->type == PROG_INTEGER && oper2->type == PROG_INTEGER)) abort_interp("Invalid argument type."); switch (pc -> data.objref) { case IN_LESSTHAN: result = oper2->data.number < oper1->data.number; break; case IN_GREATHAN: result = oper2->data.number > oper1->data.number; break; case IN_EQUAL: result = oper1->data.number == oper2->data.number; break; case IN_LESSEQ: result = oper2->data.number <= oper1->data.number; break; case IN_GREATEQ: result = oper2->data.number >= oper1->data.number; break; } CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_RANDOM: result = random(); if ((*top) >= STACK_SIZE) abort_interp("Stack overflow."); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_INTOSTR: CHECKOP(1); oper1 = POP(); switch(oper1->type) { case PROG_INTEGER: sprintf(buf, "%d", oper1->data.number); break; case PROG_OBJECT: sprintf(buf, "#%d", (int) oper1->data.objref); break; default: abort_interp("Non-integer/non-dbref argument."); } CLEAR(oper1); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); break; case IN_DBCOMP: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_OBJECT || oper2->type != PROG_OBJECT) abort_interp("Invalid argument type."); result = oper1->data.objref == oper2->data.objref; CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_DBREF: CHECKOP(1); oper1 = POP(); switch(oper1->type) { case PROG_STRING: if(oper1->data.string) { if(*(oper1->data.string->data) = '#') ref = (dbref) atoi(oper1->data.string->data + 1); } else { ref = (dbref) -1; } break; case PROG_INTEGER: ref = (dbref) oper1->data.number; break; default: abort_interp("Non-string/non-integer argument."); } CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; case IN_ATOI: CHECKOP(1); oper1 = POP(); if(oper1->type != PROG_STRING) abort_interp("Non-string argument."); result = (oper1->data.string ? atoi(oper1->data.string->data) : 0); CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_INT: CHECKOP(1); oper1 = POP(); switch(oper1->type) { case PROG_STRING: result = (oper1->data.string ? atoi(oper1->data.string->data) : 0); break; case PROG_VAR: result = oper1->data.number; break; case PROG_OBJECT: result = (int) oper1->data.objref; break; default: abort_interp("Invalid argument type."); } CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_VAR: CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_INTEGER) abort_interp("Non-integer argument."); result = oper1->data.number; CLEAR(oper1); push(arg, top, PROG_VAR, MIPSCAST &result); break; case IN_SWAP: CHECKOP(2); oper1 = POP(); temp2 = *(oper2 = POP()); arg[(*top)++] = *oper1; arg[(*top)++] = temp2; /* don't clean! */ break; case IN_CONTENTS: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid argument type."); ref = DBFETCH(oper1->data.objref)->contents; CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; case IN_EXITS: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid object."); ref = oper1->data.objref; if (!wizard && !permissions(uid, ref)) abort_interp("Permission denied."); switch(Typeof(ref)) { case TYPE_PLAYER: case TYPE_ROOM: case TYPE_THING: ref = DBFETCH(ref)->exits; break; default: abort_interp("Invalid object."); } CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; case IN_NEXT: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid object."); ref = DBFETCH(oper1->data.objref)->next; CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; default: switch (pc -> data.number) { case IN_NAME: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid argument type."); ref = oper1->data.objref; if(NAME(ref)) { strcpy(buf, NAME(ref)); } else { buf[0] = '\0'; } CLEAR(oper1); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); break; case IN_SETNAME: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (!valid_object(oper2)) abort_interp("Invalid argument type (1)"); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (2)"); ref = oper2->data.objref; if (!wizard && !permissions(uid, ref)) abort_interp("Permission denied."); { const char *b = DoNullInd(oper1->data.string); if (!ok_name(b)) abort_interp("Invalid name."); if (Typeof(ref) == TYPE_PLAYER) abort_interp("Permission denied."); if (NAME(ref)) free((void *) NAME(ref)); NAME(ref) = alloc_string(b); } CLEAR(oper1); CLEAR(oper2); break; case IN_EXPLODE: CHECKOP(2); temp1 = *(oper1 = POP()); temp2 = *(oper2 = POP()); if (temp1.type != PROG_STRING) abort_interp("Non-string argument (2)"); if (temp2.type != PROG_STRING) abort_interp("Non-string argument (1)"); if (!temp1.data.string) abort_interp("Empty string argument (2)"); { int i; const char *delimit = temp1.data.string->data; if (!temp2.data.string) { result = 1; CLEAR(&temp1); CLEAR(&temp2); push(arg, top, PROG_STRING, 0); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; } else { result = 0; bcopy(temp2.data.string->data, buf, temp2.data.string->length + 1); for (i = temp2.data.string->length - 1; i >= 0; i--) { if (!strncmp(buf + i, delimit, temp1.data.string->length)) { buf[i] = '\0'; if (*top >= STACK_SIZE) abort_interp("Stack Overflow."); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf + i + temp1.data.string->length)); result++; } } if (*top >= STACK_SIZE) abort_interp("Stack Overflow."); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); result++; } } if (*top >= STACK_SIZE) abort_interp("Stack Overflow."); CLEAR(&temp1); CLEAR(&temp2); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_MATCH: CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_STRING) abort_interp("Non-string argument."); if (!oper1->data.string) abort_interp("Empty string argument."); { struct match_data md; init_match(player, oper1->data.string->data, NOTYPE, &md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); match_me(&md); match_here(&md); match_home(&md); if(Arch(uid) || wizard) { match_absolute(&md); match_player(&md); } ref = match_result(&md); } CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; case IN_RMATCH: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_STRING) abort_interp("Invalid argument (2)"); if (oper2->type != PROG_OBJECT || Typeof(oper2->data.objref) == TYPE_PROGRAM || Typeof(oper2->data.objref) == TYPE_EXIT) abort_interp("Invalid argument (1)"); { struct match_data md; init_match(player, DoNullInd(oper1->data.string), TYPE_THING, &md); match_rmatch(oper2->data.objref, &md); ref = match_result(&md); } CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; #ifdef COPYOBJ case IN_COPYOBJ: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid object."); if (already_created) abort_interp("Can't create/destroy any more objects."); ref = oper1->data.objref; if (!mucker) abort_interp("Permission denied."); /* no copyobj for !M progs */ if (Typeof(ref) != TYPE_THING) abort_interp("Invalid object type."); already_created++; { dbref newobj; newobj = new_object(); /* *DBFETCH(newobj)= *DBFETCH(ref);*/ bcopy(DBFETCH(ref),DBFETCH(newobj),sizeof(*DBFETCH(newobj))); copyobj(player, ref, newobj); CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &newobj); } break; #endif /* COPYOBJ */ case IN_SUBST: CHECKOP(3); oper1 = POP(); oper2 = POP(); oper3 = POP(); if (!oper1->data.string) abort_interp("Empty string argument (3)"); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (3)"); if (oper2->type != PROG_STRING) abort_interp("Non-string argument (2)"); if (oper3->type != PROG_STRING) abort_interp("Non-string argument (1)"); { int i = 0, j = 0; const char *match; const char *replacement; char xbuf[BUFFER_LEN]; buf[0] = '\0'; if (oper3->data.string) { bcopy(oper3->data.string->data, xbuf, oper3->data.string->length + 1); match = oper1->data.string->data; replacement = DoNullInd(oper2->data.string); while (xbuf[i]) { if (!strncmp(xbuf + i, match, oper1->data.string->length)) { strcat(buf, replacement); i += oper1->data.string->length; j += *replacement ? oper2->data.string->length : 0; } else { buf[j++] = xbuf[i++]; buf[j] = '\0'; } } } } CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); break; case IN_INSTR: case IN_RINSTR: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_STRING) abort_interp("Invalid argument type (2)"); if(!(oper1->data.string)) abort_interp("Empty string argument (2)"); if (oper2->type != PROG_STRING) abort_interp("Non-string argument (1)"); if (!oper2->data.string) { result = 0; } else { const char *remaining = oper2->data.string->data; const char *match = oper1->data.string->data; int step = (pc -> data.number == IN_INSTR) ? 1 : -1; if (pc -> data.number == IN_RINSTR) remaining += oper2->data.string->length - 1; result = 0; do { if (!strncmp(remaining, match, oper1->data.string->length)) { result = remaining - oper2->data.string->data + 1; break; } remaining += step; } while (remaining >= oper2->data.string->data && *remaining); } CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_SET: case IN_FLAGP: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_STRING) abort_interp("Invalid argument type (2)"); if(!(oper1->data.string)) abort_interp("Empty string argument (2)"); if (!valid_object(oper2)) abort_interp("Invalid object."); ref = oper2->data.objref; result = ((*oper1->data.string->data == '!') && (pc->data.number == IN_SET)); { const char *flag = oper1->data.string->data; if (result) flag++; ltmp = lookup_flag(flag); } if (pc -> data.number == IN_SET) { if (!ltmp) abort_interp("Unrecognized flag."); if ((!wizard && !permissions(uid, ref)) || restricted(program, ref, ltmp)) abort_interp("Permission denied."); if (!result) { FLAGS(ref) |= ltmp; DBDIRTY(ref); } else { FLAGS(ref) &= ~ltmp; DBDIRTY(ref); } CLEAR(oper1); CLEAR(oper2); } else { result = (ltmp && ((FLAGS(ref) & ltmp) != 0)); CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &result); } break; case IN_PLAYERP: case IN_THINGP: case IN_ROOMP: case IN_PROGRAMP: case IN_EXITP: CHECKOP(1); oper1 = POP(); /* if (!valid_object(oper1) && !is_home(oper1)) abort_interp("Invalid argument type."); */ ref = oper1->data.objref; switch (pc -> data.number) { case IN_PLAYERP: result = (Typeof(ref) == TYPE_PLAYER); break; case IN_THINGP: result = (Typeof(ref) == TYPE_THING); break; case IN_ROOMP: result = (Typeof(ref) == TYPE_ROOM); break; case IN_PROGRAMP: result = (Typeof(ref) == TYPE_PROGRAM); break; case IN_EXITP: result = (Typeof(ref) == TYPE_EXIT); break; } CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_OKP: CHECKOP(1); oper1 = POP(); result = (valid_object(oper1)); CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_LOCATION: case IN_OWNER: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid object."); if (pc -> data.number == IN_LOCATION) ref = DBFETCH(oper1->data.objref)->location; else ref = OWNER(oper1->data.objref); CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; case IN_OVER: CHECKOP(2); copyinst(&arg[*top - 2], &arg[*top]); (*top)++; break; case IN_PICK: CHECKOP(1); temp1 = *(oper1 = POP()); if (temp1.type != PROG_INTEGER || temp1.data.number <= 0) abort_interp("Operand not a positive integer."); CHECKOP(temp1.data.number); copyinst(&arg[*top - temp1.data.number], &arg[*top]); (*top)++; break; case IN_PUT: CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_INTEGER || oper1->data.number <= 0) abort_interp("Operand not a positive integer."); tmp = oper1->data.number; CHECKOP(tmp); CLEAR(&arg[*top - tmp]); copyinst(oper2, &arg[*top - tmp]); CLEAR(oper1); CLEAR(oper2); break; case IN_ROT: CHECKOP(3); oper1 = POP(); oper2 = POP(); temp3 = *(oper3 = POP()); arg[(*top)++] = *oper2; arg[(*top)++] = *oper1; arg[(*top)++] = temp3; break; case IN_ROTATE: CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_INTEGER) abort_interp("Invalid argument type."); tmp = oper1->data.number; /* Depth on stack */ CHECKOP(abs(tmp)); if (tmp > 0) { temp2 = arg[*top - tmp]; for (; tmp > 0; tmp--) arg[*top - tmp] = arg[*top - tmp + 1]; arg[*top - 1] = temp2; } else if (tmp < 0) { temp2 = arg[*top - 1]; for (tmp = -1; tmp > oper1->data.number; tmp--) arg[*top + tmp] = arg[*top + tmp - 1]; arg[*top + tmp] = temp2; } CLEAR(oper1); break; case IN_GETLINK: CHECKOP(1); oper1 = POP(); if (!valid_object(oper1)) abort_interp("Invalid object."); if (Typeof(oper1->data.objref) == TYPE_PROGRAM) abort_interp("Illegal object referenced."); switch (Typeof(oper1->data.objref)) { case TYPE_EXIT: ref = (DBFETCH(oper1->data.objref)->sp.exit.ndest) ? (DBFETCH(oper1->data.objref)->sp.exit.dest)[0] : NOTHING; break; case TYPE_PLAYER: ref = DBFETCH(oper1->data.objref)->link; break; case TYPE_THING: ref = DBFETCH(oper1->data.objref)->link; break; case TYPE_ROOM: ref = DBFETCH(oper1->data.objref)->link; break; default: ref = NOTHING; break; } CLEAR(oper1); push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; case IN_PRONOUN_SUB: CHECKOP(2); oper1 = POP(); oper2 = POP(); /* oper1 is a string, oper2 a dbref */ if (!valid_object(oper2)) abort_interp("Invalid argument (1)"); if (oper1->type != PROG_STRING) abort_interp("Invalid argument (2)"); CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_STRING, (oper1->data.string) ? MIPSCAST alloc_prog_string(pronoun_substitute(oper2->data.objref, oper1->data.string->data, uid)) : MIPSCAST alloc_prog_string("")); break; case IN_PRONOUN_EVAL: CHECKOP(3); oper3 = POP(); oper1 = POP(); oper2 = POP(); /* oper1 is a string, oper2 a dbref */ if (!valid_object(oper2)) abort_interp("Invalid argument (1)"); if (oper1->type != PROG_STRING) abort_interp("Invalid argument (2)"); if(!valid_object(oper3)) abort_interp("Invalid argument (3)"); if (!wizard && !permissions(uid, oper3->data.objref)) abort_interp("Permission denied."); CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); push(arg, top, PROG_STRING, (oper1->data.string) ? MIPSCAST alloc_prog_string(pronoun_substitute(oper2->data.objref, oper1->data.string->data, oper3->data.objref)) : MIPSCAST alloc_prog_string("")); break; case IN_HALT: CHECKOP(1); oper1 = POP(); if(!valid_object(oper1)) abort_interp("Invalid object"); if(Typeof(oper1->data.objref) != TYPE_THING && Typeof(oper1->data.objref) != TYPE_PLAYER) abort_interp("Invalid object type."); if(!permissions(uid, oper1->data.objref)) abort_interp("Permission denied."); halt_long(oper1->data.objref); { char buf[BUFFER_LEN]; sprintf(buf, "%s halted.",unparse_object(OWNER(oper1->data.objref), oper1->data.objref)); notify(OWNER(oper1->data.objref), buf); } CLEAR(oper1); break; case IN_TRIGOBJ: CHECKOP(2); oper1 = POP(); oper2 = POP(); if(oper2->type != PROG_OBJECT) abort_interp("Non-dbref argument (1)"); if(!valid_object(oper2)) abort_interp("Invalid object."); if(oper1->type!=PROG_STRING) abort_interp("Non-string argument (2)"); if(!wizard && !permissions(OWNER(program), oper2->data.objref)) abort_interp("Permission denied."); if(Typeof(oper2->data.objref) != TYPE_PLAYER && Typeof(oper2->data.objref) != TYPE_THING) abort_interp("Invalid object type."); if(God(oper2->data.objref)) abort_interp("Permission denied."); if(!oper1->data.string || !oper1->data.string->data) abort_interp("Empty string argument."); trigobj(oper2->data.objref,oper1->data.string->data,player); CLEAR(oper1); CLEAR(oper2); break; case IN_SYSTIME: if ((*top) >= STACK_SIZE) abort_interp("Stack overflow."); { time_t lt; lt = time((time_t *) 0); push(arg, top, PROG_INTEGER, MIPSCAST <); } break; case IN_TIME: if ((*top) + 2 >= STACK_SIZE) abort_interp("Stack overflow."); { time_t lt; struct tm *delta; lt = time((time_t *) 0); delta = localtime(<); result = delta -> tm_sec; push(arg, top, PROG_INTEGER, MIPSCAST &result); result = delta -> tm_min; push(arg, top, PROG_INTEGER, MIPSCAST &result); result = delta -> tm_hour; push(arg, top, PROG_INTEGER, MIPSCAST &result); } break; case IN_STRFTIME: CHECKOP(2); oper1 = POP(); oper2 = POP(); if(oper1->type != PROG_STRING) abort_interp("Non-string argument (2)"); if(oper2->type != PROG_INTEGER) abort_interp("Non-integer argument (1)"); muck_strftime(buf, (size_t) BUFFER_LEN, oper1->data.string->data, (time_t) oper2->data.number); CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); break; case IN_ONLINE: { struct descriptor_data *d; result = 0; for(d = descriptor_list; d; d = d->next) { if(d->connected) { ref = d->player; if(*top >= STACK_SIZE) abort_interp("Stack Overflow."); push(arg, top, PROG_OBJECT, MIPSCAST &ref); result++; } } if(*top >= STACK_SIZE) abort_interp("Stack Overflow."); push(arg, top, PROG_INTEGER, MIPSCAST &result); } break; case IN_AWAKEP: CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_OBJECT) abort_interp("Invalid argument type."); result = check_awake(oper1->data.objref); CLEAR(oper1); push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_CONNECTIONS: case IN_CONCOUNT: { struct descriptor_data *d; result = 0; for(d = descriptor_list; d; d = d -> next) { if(d->connected) { if(pc -> data.number == IN_CONNECTIONS) { if(*top >= STACK_SIZE) abort_interp("Stack Overflow."); push(arg, top, PROG_CON, MIPSCAST d); } result++; } } if(*top >= STACK_SIZE) abort_interp("Stack Overflow."); push(arg, top, PROG_INTEGER, MIPSCAST &result); } break; case IN_CONBOOT: CHECKOP(1); oper1 = POP(); if (oper1 -> type != PROG_CON) abort_interp("Non-descriptor argument."); if (!wizard) abort_interp("Permission denied."); #ifdef GOD_PRIV if (is_god(oper1->data.con -> player)) abort_interp("Permission denied."); #else if (Wizard(oper1->data.con -> player)) abort_interp("Permission denied."); #endif /* GOD_PRIV */ process_output(oper1->data.con); shutdownsock(oper1->data.con); CLEAR(oper1); break; case IN_CONDBREF: case IN_CONHOST: case IN_CONIDLE: case IN_CONTIME: CHECKOP(1); oper1 = POP(); if (oper1-> type != PROG_CON) abort_interp("Non-descriptor argument."); if(pc -> data.number == IN_CONDBREF) { ref = oper1->data.con -> player; push(arg, top, PROG_OBJECT, MIPSCAST &ref); } else if(pc -> data.number == IN_CONIDLE) { result = time((long *) 0) - (oper1->data.con -> last_time); push(arg, top, PROG_INTEGER, MIPSCAST &result); } else if(pc -> data.number == IN_CONTIME) { result = oper1->data.con -> connected_at; push(arg, top, PROG_INTEGER, MIPSCAST &result); } else { /* IN_CONHOST */ if(!wizard) abort_interp("Permission denied."); sprintf(buf, "%s", oper1->data.con -> hostname); push(arg, top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); } break; case IN_PROG: if ((*top) >= STACK_SIZE) abort_interp("Stack Overflow."); ref = program; push(arg, top, PROG_OBJECT, MIPSCAST &ref); break; /* IN_SELF doesn't work right */ /* case IN_SELF: if ((*top) >= STACK_SIZE) abort_interp("Stack Overflow."); add = (sys[stop].data.call - 2) -> data.call; push(arg, top, PROG_ADD, MIPSCAST add); break; */ case IN_DEPTH: if ((*top) >= STACK_SIZE) abort_interp("Stack Overflow."); result = *top; push(arg, top, PROG_INTEGER, MIPSCAST &result); break; case IN_WILD_MATCH: CHECKOP(2); oper1=POP(); oper2=POP(); if(oper1->type != PROG_STRING) abort_interp("Non-string argument (2)"); if(oper2->type != PROG_STRING) abort_interp("Non-string argument (1)"); if(!oper1->data.string || !oper1->data.string->data || !oper2->data.string || !oper2->data.string->data) abort_interp("Empty string argument."); { int tmp; puts("About to wild match"); tmp = wild_match(oper1->data.string->data, oper2->data.string->data); puts("Done wild match"); CLEAR(oper1); CLEAR(oper2); push(arg, top, PROG_INTEGER, MIPSCAST &tmp); for(tmp = 0; tmp <= 9; tmp++) if(wptr[tmp]) awptr[tmp] = alloc_string(wptr[tmp]); /* Ok, we got the junk copied so that pronoun_sub can read it */ } break; case IN_CHECKFUNC: CHECKOP(1); /* this does nothing for the momnet */ /* oper1=POP(); if(oper1->type!=PROG_STRING) abort_interp("Non string argument"); if(!oper1->data.string || !oper1->data.string->data) push(arg,top,PROG_STRING,MIPSCAST alloc_prog_string("")); else { char *y; y=check_arg(uncompress(oper1->data.string->data),player,global_cause); if(y) push(arg,top,PROG_STRING,MIPSCAST alloc_prog_string(y)); else push(arg,top,PROG_STRING,MIPSCAST alloc_prog_string("")); } CLEAR(oper1); */ break; default: abort_interp("Unrecognized primitive."); /*NOTREACHED*/ break; } break; } }