void prim_pick(PRIM_PROTOTYPE) { CHECKOP(1); temp1 = *(oper1 = POP()); if (temp1.type != PROG_INTEGER || temp1.data.number <= 0) abort_interp("Operand not a positive integer."); CHECKOP_READONLY(temp1.data.number); copyinst(&arg[*top - temp1.data.number], &arg[*top]); (*top)++; }
void prim_bang(PRIM_PROTOTYPE) { CHECKOP(2); oper1 = POP(); oper2 = POP(); if ((oper1->type != PROG_VAR) && (oper1->type != PROG_LVAR)) abort_interp("Non-variable argument (2)"); if (oper1->data.number >= MAX_VAR || oper1->data.number < 0) abort_interp("Variable number out of range. (2)"); if (oper1->type == PROG_LVAR) { CLEAR(&(CurrVar[oper1->data.number])); copyinst(oper2, &(CurrVar[oper1->data.number])); } else { CLEAR(&(fr->variables[oper1->data.number])); copyinst(oper2, &(fr->variables[oper1->data.number])); } CLEAR(oper1); CLEAR(oper2); }
void prim_tuck(PRIM_PROTOTYPE) { CHECKOFLOW(1); CHECKOP(2); oper1 = POP(); temp2 = *(oper2 = POP()); arg[(*top)++] = *oper1; arg[(*top)++] = temp2; copyinst(&arg[*top - 2], &arg[*top]); (*top)++; }
int array_next(stk_array *arr, array_iter *item) { if (!arr || !arr->items) { return 0; } switch (arr->type) { case ARRAY_PACKED:{ int idx; if (item->type == PROG_STRING) { CLEAR(item); return 0; } else if (item->type == PROG_FLOAT) { if (item->data.fnumber < 0.0) { idx = 0; } else { idx = (int) (item->data.fnumber + 1.0); } } else { idx = item->data.number + 1; } CLEAR(item); if (idx >= arr->items) { return 0; } else if (idx < 0) { idx = 0; } item->type = PROG_INTEGER; item->data.number = idx; return 1; break; } case ARRAY_DICTIONARY:{ array_tree *p; p = array_tree_next_node(arr->data.dict, item); CLEAR(item); if (!p) return 0; copyinst(&p->key, item); return 1; } default:{ break; } } return 0; }
void prim_put(PRIM_PROTOTYPE) { 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); }
stk_array * array_decouple(stk_array *arr) { stk_array *new2; if (!arr) { return NULL; } new2 = new_array(); new2->pinned = arr->pinned; new2->type = arr->type; switch (arr->type) { case ARRAY_PACKED:{ int i; new2->items = arr->items; new2->data.packed = (array_data *) malloc(sizeof(array_data) * arr->items); for (i = arr->items; i-- > 0;) { copyinst(&arr->data.packed[i], &new2->data.packed[i]); } return new2; break; } case ARRAY_DICTIONARY:{ array_iter idx; array_data *val; if (array_first(arr, &idx)) { do { val = array_getitem(arr, &idx); array_setitem(&new2, &idx, val); } while (array_next(arr, &idx)); } return new2; break; } default: break; } return NULL; }
void prim_dupn(PRIM_PROTOTYPE) { CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_INTEGER) abort_interp("Operand is not an integer."); result = oper1->data.number; if (result < 0) abort_interp("Operand is negative."); EXPECT_READ_STACK(result); CLEAR(oper1); nargs = 0; CHECKOFLOW(result); for (int i = result; i > 0; i--) { copyinst(&arg[*top - result], &arg[*top]); (*top)++; } }
void prim_shallow_copy(PRIM_PROTOTYPE) { EXPECT_READ_STACK(1); CHECKOFLOW(1); if (arg[*top - 1].type != PROG_ARRAY) { copyinst(&arg[*top - 1], &arg[*top]); (*top)++; } else { stk_array *nu; stk_array *arr = arg[*top - 1].data.array; if (!arr) { nu = new_array_packed(0, fr->pinning); } else { nu = array_decouple(arr); } PushArrayRaw(nu); } }
/* cake */ array_tree * array_tree_alloc_node(array_iter *key) { array_tree *new_node; new_node = (array_tree *) malloc(sizeof(array_tree)); if (!new_node) { fprintf(stderr, "array_tree_alloc_node(): Out of Memory!\n"); abort(); } AVL_LF(new_node) = NULL; AVL_RT(new_node) = NULL; new_node->height = 1; copyinst(key, AVL_KEY(new_node)); new_node->data.type = PROG_INTEGER; new_node->data.data.number = 0; return new_node; }
void localvar_dupall(struct frame *fr, struct frame *oldfr) { if (!fr || !oldfr) { panic("localvar_dupall(): NULL frame passed !"); } struct localvars *orig = oldfr->lvars; struct localvars **targ = &fr->lvars; while (orig) { int count = MAX_VAR; *targ = (struct localvars*)malloc(sizeof(struct localvars)); while (count-- > 0) copyinst(&orig->lvars[count], &(*targ)->lvars[count]); (*targ)->prog = orig->prog; (*targ)->next = NULL; (*targ)->prev = targ; targ = &((*targ)->next); orig = orig->next; } }
struct inst * interp_loop(dbref player, dbref program, struct frame *fr, int rettyp) { register struct inst *pc; register int atop; register struct inst *arg; register struct inst *temp1; register struct inst *temp2; register struct stack_addr *sys; register int instr_count; register int stop; int i = 0, tmp, writeonly, mlev; static struct inst retval; char dbuf[BUFFER_LEN]; int instno_debug_line = get_primitive("debug_line"); fr->level = ++interp_depth; /* increment interp level */ /* 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; fr->brkpt.isread = 0; if (!pc) { struct line *tmpline; tmpline = PROGRAM_FIRST(program); PROGRAM_SET_FIRST(program, (struct line *) read_program(program)); do_compile(-1, OWNER(program), program, 0); free_prog_text(PROGRAM_FIRST(program)); PROGRAM_SET_FIRST(program, tmpline); pc = fr->pc = PROGRAM_START(program); if (!pc) { abort_loop_hard("Program not compilable. Cannot run.", NULL, NULL); } PROGRAM_INC_PROF_USES(program); PROGRAM_INC_INSTANCES(program); } ts_useobject(program); err = 0; instr_count = 0; mlev = ProgMLevel(program); gettimeofday(&fr->proftime, NULL); /* This is the 'natural' way to exit a function */ while (stop) { /* Abort program if player/thing running it is recycled */ if ((player < 0) || (player >= db_top) || ((Typeof(player) != TYPE_PLAYER) && (Typeof(player) != TYPE_THING))) { reload(fr, atop, stop); prog_clean(fr); interp_depth--; calc_profile_timing(program,fr); return NULL; } fr->instcnt++; instr_count++; if ((fr->multitask == PREEMPT) || (FLAGS(program) & BUILDER)) { if (mlev == 4) { if (tp_max_ml4_preempt_count) { if (instr_count >= tp_max_ml4_preempt_count) abort_loop_hard("Maximum preempt instruction count exceeded", NULL, NULL); } else instr_count = 0; } else { /* else make sure that the program doesn't run too long */ if (instr_count >= tp_max_instr_count) abort_loop_hard("Maximum preempt instruction count exceeded", NULL, NULL); } } else { /* if in FOREGROUND or BACKGROUND mode, '0 sleep' every so often. */ if ((fr->instcnt > tp_instr_slice * 4) && (instr_count >= tp_instr_slice)) { fr->pc = pc; reload(fr, atop, stop); PLAYER_SET_BLOCK(player, (!fr->been_background)); add_muf_delay_event(0, fr->descr, player, NOTHING, NOTHING, program, fr, (fr->multitask == FOREGROUND) ? "FOREGROUND" : "BACKGROUND"); interp_depth--; calc_profile_timing(program,fr); return NULL; } } if (((FLAGS(program) & ZOMBIE) || fr->brkpt.force_debugging) && !fr->been_background && controls(player, program) ) { fr->brkpt.debugging = 1; } else { fr->brkpt.debugging = 0; } if (FLAGS(program) & DARK || (fr->brkpt.debugging && fr->brkpt.showstack && !fr->brkpt.bypass)) { if ((pc->type != PROG_PRIMITIVE) || (pc->data.number != instno_debug_line)) { char *m = debug_inst(fr, 0, pc, fr->pid, arg, dbuf, sizeof(dbuf), atop, program); notify_nolisten(player, m, 1); } } if (fr->brkpt.debugging) { short breakflag = 0; if (stop == 1 && !fr->brkpt.bypass && pc->type == PROG_PRIMITIVE && pc->data.number == IN_RET ) { /* Program is about to EXIT */ notify_nolisten(player, "Program is about to EXIT.", 1); breakflag = 1; } else if (fr->brkpt.count) { for (i = 0; i < fr->brkpt.count; i++) { if ((!fr->brkpt.pc[i] || pc == fr->brkpt.pc[i]) && /* pc matches */ (fr->brkpt.line[i] == -1 || (fr->brkpt.lastline != pc->line && fr->brkpt.line[i] == pc->line)) && /* line matches */ (fr->brkpt.level[i] == -1 || stop <= fr->brkpt.level[i]) && /* level matches */ (fr->brkpt.prog[i] == NOTHING || fr->brkpt.prog[i] == program) && /* program matches */ (fr->brkpt.linecount[i] == -2 || (fr->brkpt.lastline != pc->line && fr->brkpt.linecount[i]-- <= 0)) && /* line count matches */ (fr->brkpt.pccount[i] == -2 || (fr->brkpt.lastpc != pc && fr->brkpt.pccount[i]-- <= 0)) /* pc count matches */ ) { if (fr->brkpt.bypass) { if (fr->brkpt.pccount[i] == -1) fr->brkpt.pccount[i] = 0; if (fr->brkpt.linecount[i] == -1) fr->brkpt.linecount[i] = 0; } else { breakflag = 1; break; } } } } if (breakflag) { char *m; char buf[BUFFER_LEN]; if (fr->brkpt.dosyspop) { program = sys[--stop].progref; pc = sys[stop].offset; } add_muf_read_event(fr->descr, player, program, fr); reload(fr, atop, stop); fr->pc = pc; fr->brkpt.isread = 0; fr->brkpt.breaknum = i; fr->brkpt.lastlisted = 0; fr->brkpt.bypass = 0; fr->brkpt.dosyspop = 0; PLAYER_SET_CURR_PROG(player, program); PLAYER_SET_BLOCK(player, 0); interp_depth--; if (!fr->brkpt.showstack) { m = debug_inst(fr, 0, pc, fr->pid, arg, dbuf, sizeof(dbuf), atop, program); notify_nolisten(player, m, 1); } if (pc <= PROGRAM_CODE(program) || (pc - 1)->line != pc->line) { list_proglines(player, program, fr, pc->line, 0); } else { m = show_line_prims(fr, program, pc, 15, 1); snprintf(buf, sizeof(buf), " %s", m); notify_nolisten(player, buf, 1); } calc_profile_timing(program,fr); return NULL; } fr->brkpt.lastline = pc->line; fr->brkpt.lastpc = pc; fr->brkpt.bypass = 0; } if (mlev < 3) { if (fr->instcnt > (tp_max_instr_count * ((mlev == 2) ? 4 : 1))) abort_loop_hard("Maximum total instruction count exceeded.", NULL, NULL); } switch (pc->type) { case PROG_INTEGER: case PROG_FLOAT: case PROG_ADD: case PROG_OBJECT: case PROG_VAR: case PROG_LVAR: case PROG_SVAR: case PROG_STRING: case PROG_LOCK: case PROG_MARK: case PROG_ARRAY: if (atop >= STACK_SIZE) abort_loop("Stack overflow.", NULL, NULL); copyinst(pc, arg + atop); pc++; atop++; break; case PROG_LVAR_AT: case PROG_LVAR_AT_CLEAR: { struct inst *tmp; struct localvars *lv; if (atop >= STACK_SIZE) abort_loop("Stack overflow.", NULL, NULL); if (pc->data.number >= MAX_VAR || pc->data.number < 0) abort_loop("Scoped variable number out of range.", NULL, NULL); lv = localvars_get(fr, program); tmp = &(lv->lvars[pc->data.number]); copyinst(tmp, arg + atop); if (pc->type == PROG_LVAR_AT_CLEAR) { CLEAR(tmp); tmp->type = PROG_INTEGER; tmp->data.number = 0; } pc++; atop++; } break; case PROG_LVAR_BANG: { struct inst *the_var; struct localvars *lv; if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); if (pc->data.number >= MAX_VAR || pc->data.number < 0) abort_loop("Scoped variable number out of range.", NULL, NULL); lv = localvars_get(fr, program); the_var = &(lv->lvars[pc->data.number]); CLEAR(the_var); temp1 = arg + --atop; *the_var = *temp1; pc++; } break; case PROG_SVAR_AT: case PROG_SVAR_AT_CLEAR: { struct inst *tmp; if (atop >= STACK_SIZE) abort_loop("Stack overflow.", NULL, NULL); tmp = scopedvar_get(fr, 0, pc->data.number); if (!tmp) abort_loop("Scoped variable number out of range.", NULL, NULL); copyinst(tmp, arg + atop); if (pc->type == PROG_SVAR_AT_CLEAR) { CLEAR(tmp); tmp->type = PROG_INTEGER; tmp->data.number = 0; } pc++; atop++; } break; case PROG_SVAR_BANG: { struct inst *the_var; if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); the_var = scopedvar_get(fr, 0, pc->data.number); if (!the_var) abort_loop("Scoped variable number out of range.", NULL, NULL); CLEAR(the_var); temp1 = arg + --atop; *the_var = *temp1; pc++; } break; case PROG_FUNCTION: { int i = pc->data.mufproc->args; if (atop < i) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < i) abort_loop("Stack protection fault.", NULL, NULL); if (fr->skip_declare) fr->skip_declare = 0; else scopedvar_addlevel(fr, pc, pc->data.mufproc->vars); while (i-->0) { struct inst *tmp; temp1 = arg + --atop; tmp = scopedvar_get(fr, 0, i); if (!tmp) abort_loop_hard("Internal error: Scoped variable number out of range in FUNCTION init.", temp1, NULL); CLEAR(tmp); copyinst(temp1, tmp); CLEAR(temp1); } pc++; } break; case PROG_IF: if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (false_inst(temp1)) pc = pc->data.call; else pc++; CLEAR(temp1); break; case PROG_EXEC: if (stop >= STACK_SIZE) abort_loop("System Stack Overflow", NULL, NULL); sys[stop].progref = program; sys[stop++].offset = pc + 1; pc = pc->data.call; fr->skip_declare = 0; /* Make sure we DON'T skip var decls */ break; case PROG_JMP: /* Don't need to worry about skipping scoped var decls here. */ /* JMP to a function header can only happen in IN_JMP */ pc = pc->data.call; break; case PROG_TRY: if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_INTEGER || temp1->data.number < 0) abort_loop("Argument is not a positive integer.", temp1, NULL); if (fr->trys.top && atop - fr->trys.st->depth < temp1->data.number) abort_loop("Stack protection fault.", NULL, NULL); if (temp1->data.number > atop) abort_loop("Stack Underflow.", temp1, NULL); fr->trys.top++; fr->trys.st = push_try(fr->trys.st); fr->trys.st->depth = atop - temp1->data.number; fr->trys.st->call_level = stop; fr->trys.st->for_count = 0; fr->trys.st->addr = pc->data.call; pc++; CLEAR(temp1); 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_JMP: if (atop < 1) abort_loop("Stack underflow. Missing address.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_ADD) abort_loop("Argument is not an address.", temp1, NULL); if (temp1->data.addr->progref >= db_top || temp1->data.addr->progref < 0 || (Typeof(temp1->data.addr->progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", temp1, NULL); if (program != temp1->data.addr->progref) { abort_loop("Destination outside current program.", temp1, NULL); } if (temp1->data.addr->data->type == PROG_FUNCTION) { fr->skip_declare = 1; } pc = temp1->data.addr->data; CLEAR(temp1); break; case IN_EXECUTE: if (atop < 1) abort_loop("Stack Underflow. Missing address.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_ADD) abort_loop("Argument is not an address.", temp1, NULL); if (temp1->data.addr->progref >= db_top || temp1->data.addr->progref < 0 || (Typeof(temp1->data.addr->progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", temp1, NULL); if (stop >= STACK_SIZE) abort_loop("System Stack Overflow", temp1, NULL); sys[stop].progref = program; sys[stop++].offset = pc + 1; if (program != temp1->data.addr->progref) { program = temp1->data.addr->progref; fr->caller.st[++fr->caller.top] = program; mlev = ProgMLevel(program); PROGRAM_INC_INSTANCES(program); } pc = temp1->data.addr->data; CLEAR(temp1); break; case IN_CALL: if (atop < 1) abort_loop("Stack Underflow. Missing dbref argument.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; temp2 = 0; if (temp1->type != PROG_OBJECT) { temp2 = temp1; if (atop < 1) abort_loop("Stack Underflow. Missing dbref of func.", temp1, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp2->type != PROG_STRING) abort_loop("Public Func. name string required. (2)", temp1, temp2); if (!temp2->data.string) abort_loop("Null string not allowed. (2)", temp1, temp2); } if (temp1->type != PROG_OBJECT) abort_loop("Dbref required. (1)", temp1, temp2); if (!valid_object(temp1) || Typeof(temp1->data.objref) != TYPE_PROGRAM) abort_loop("Invalid object.", temp1, temp2); if (!(PROGRAM_CODE(temp1->data.objref))) { struct line *tmpline; tmpline = PROGRAM_FIRST(temp1->data.objref); PROGRAM_SET_FIRST(temp1->data.objref, (struct line *) read_program(temp1->data.objref)); do_compile(-1, OWNER(temp1->data.objref), temp1->data.objref, 0); free_prog_text(PROGRAM_FIRST(temp1->data.objref)); PROGRAM_SET_FIRST(temp1->data.objref, tmpline); if (!(PROGRAM_CODE(temp1->data.objref))) abort_loop("Program not compilable.", temp1, temp2); } if (ProgMLevel(temp1->data.objref) == 0) abort_loop("Permission denied", temp1, temp2); if (mlev < 4 && OWNER(temp1->data.objref) != ProgUID && !Linkable(temp1->data.objref)) abort_loop("Permission denied", temp1, temp2); if (stop >= STACK_SIZE) abort_loop("System Stack Overflow", temp1, temp2); sys[stop].progref = program; sys[stop].offset = pc + 1; if (!temp2) { pc = PROGRAM_START(temp1->data.objref); } else { struct publics *pbs; int tmpint; pbs = PROGRAM_PUBS(temp1->data.objref); while (pbs) { tmpint = string_compare(temp2->data.string->data, pbs->subname); if (!tmpint) break; pbs = pbs->next; } if (!pbs) abort_loop("PUBLIC or WIZCALL function not found. (2)", temp2, temp2); if (mlev < pbs->mlev) abort_loop("Insufficient permissions to call WIZCALL function. (2)", temp2, temp2); pc = pbs->addr.ptr; } stop++; if (temp1->data.objref != program) { calc_profile_timing(program,fr); gettimeofday(&fr->proftime, NULL); program = temp1->data.objref; fr->caller.st[++fr->caller.top] = program; PROGRAM_INC_INSTANCES(program); mlev = ProgMLevel(program); } PROGRAM_INC_PROF_USES(program); ts_useobject(program); CLEAR(temp1); if (temp2) CLEAR(temp2); break; case IN_RET: if (stop > 1 && program != sys[stop - 1].progref) { if (sys[stop - 1].progref >= db_top || sys[stop - 1].progref < 0 || (Typeof(sys[stop - 1].progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", NULL, NULL); calc_profile_timing(program,fr); gettimeofday(&fr->proftime, NULL); PROGRAM_DEC_INSTANCES(program); program = sys[stop - 1].progref; mlev = ProgMLevel(program); fr->caller.top--; } scopedvar_poplevel(fr); pc = sys[--stop].offset; break; case IN_CATCH: case IN_CATCH_DETAILED: { int depth; if (!(fr->trys.top)) abort_loop_hard("Internal error. TRY stack underflow.", NULL, NULL); depth = fr->trys.st->depth; while (atop > depth) { temp1 = arg + --atop; CLEAR(temp1); } while (fr->trys.st->for_count-->0) { CLEAR(&fr->fors.st->cur); CLEAR(&fr->fors.st->end); fr->fors.top--; fr->fors.st = pop_for(fr->fors.st); } fr->trys.top--; fr->trys.st = pop_try(fr->trys.st); if (pc->data.number == IN_CATCH) { /* IN_CATCH */ if (fr->errorstr) { arg[atop].type = PROG_STRING; arg[atop++].data.string = alloc_prog_string(fr->errorstr); free(fr->errorstr); fr->errorstr = NULL; } else { arg[atop].type = PROG_STRING; arg[atop++].data.string = NULL; } if (fr->errorinst) { free(fr->errorinst); fr->errorinst = NULL; } } else { /* IN_CATCH_DETAILED */ stk_array *nu = new_array_dictionary(); if (fr->errorstr) { array_set_strkey_strval(&nu, "error", fr->errorstr); free(fr->errorstr); fr->errorstr = NULL; } if (fr->errorinst) { array_set_strkey_strval(&nu, "instr", fr->errorinst); free(fr->errorinst); fr->errorinst = NULL; } array_set_strkey_intval(&nu, "line", fr->errorline); array_set_strkey_refval(&nu, "program", fr->errorprog); arg[atop].type = PROG_ARRAY; arg[atop++].data.array = nu; } reload(fr, atop, stop); } pc++; break; case IN_EVENT_WAITFOR: if (atop < 1) abort_loop("Stack Underflow. Missing eventID list array argument.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_ARRAY) abort_loop("EventID string list array expected.", temp1, NULL); if (temp1->data.array && temp1->data.array->type != ARRAY_PACKED) abort_loop("Argument must be a list array of eventid strings.", temp1, NULL); if (!array_is_homogenous(temp1->data.array, PROG_STRING)) abort_loop("Argument must be a list array of eventid strings.", temp1, NULL); fr->pc = pc + 1; reload(fr, atop, stop); { int i, outcount; int count = array_count(temp1->data.array); char** events = (char**)malloc(count * sizeof(char**)); for (outcount = i = 0; i < count; i++) { char *val = array_get_intkey_strval(temp1->data.array, i); if (val != NULL) { int found = 0; int j; for (j = 0; j < outcount; j++) { if (!strcmp(events[j], val)) { found = 1; break; } } if (!found) { events[outcount++] = val; } } } muf_event_register_specific(player, program, fr, outcount, events); free(events); } PLAYER_SET_BLOCK(player, (!fr->been_background)); CLEAR(temp1); interp_depth--; calc_profile_timing(program,fr); return NULL; /* NOTREACHED */ break; case IN_READ: if (writeonly) abort_loop("Program is write-only.", NULL, NULL); if (fr->multitask == BACKGROUND) abort_loop("BACKGROUND programs are write only.", NULL, NULL); reload(fr, atop, stop); fr->brkpt.isread = 1; fr->pc = pc + 1; PLAYER_SET_CURR_PROG(player, program); PLAYER_SET_BLOCK(player, 0); add_muf_read_event(fr->descr, player, program, fr); interp_depth--; calc_profile_timing(program,fr); return NULL; /* NOTREACHED */ break; case IN_SLEEP: if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_INTEGER) abort_loop("Invalid argument type.", temp1, NULL); fr->pc = pc + 1; reload(fr, atop, stop); if (temp1->data.number < 0) abort_loop("Timetravel beyond scope of muf.", temp1, NULL); add_muf_delay_event(temp1->data.number, fr->descr, player, NOTHING, NOTHING, program, fr, "SLEEPING"); PLAYER_SET_BLOCK(player, (!fr->been_background)); interp_depth--; calc_profile_timing(program,fr); return NULL; /* NOTREACHED */ break; default: nargs = 0; reload(fr, atop, stop); tmp = atop; prim_func[pc->data.number - 1] (player, program, mlev, pc, arg, &tmp, fr); atop = tmp; pc++; break; } /* switch */ break; case PROG_CLEARED: log_status("WARNING: attempt to execute instruction cleared by %s:%hd in program %d", (char*)pc->data.addr, pc->line, program); pc = NULL; abort_loop_hard("Program internal error. Program erroneously freed from memory.", NULL, NULL); default: pc = NULL; abort_loop_hard("Program internal error. Unknown instruction type.", NULL, NULL); } /* switch */ if (err) { if (err != ERROR_DIE_NOW && fr->trys.top) { while (fr->trys.st->call_level < stop) { if (stop > 1 && program != sys[stop - 1].progref) { if (sys[stop - 1].progref >= db_top || sys[stop - 1].progref < 0 || (Typeof(sys[stop - 1].progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", NULL, NULL); calc_profile_timing(program,fr); gettimeofday(&fr->proftime, NULL); PROGRAM_DEC_INSTANCES(program); program = sys[stop - 1].progref; mlev = ProgMLevel(program); fr->caller.top--; } scopedvar_poplevel(fr); stop--; } pc = fr->trys.st->addr; err = 0; } else { reload(fr, atop, stop); prog_clean(fr); PLAYER_SET_BLOCK(player, 0); interp_depth--; calc_profile_timing(program,fr); return NULL; } } } /* while */ PLAYER_SET_BLOCK(player, 0); if (atop) { struct inst *rv; if (rettyp) { copyinst(arg + atop - 1, &retval); rv = &retval; } else { if (!false_inst(arg + atop - 1)) { rv = (struct inst *) 1; } else { rv = NULL; } } reload(fr, atop, stop); prog_clean(fr); interp_depth--; calc_profile_timing(program,fr); return rv; } reload(fr, atop, stop); prog_clean(fr); interp_depth--; calc_profile_timing(program,fr); return NULL; }
int array_delrange(stk_array **harr, array_iter *start, array_iter *end) { stk_array *arr; array_data *itm; int sidx, eidx, totsize; array_iter idx; array_iter didx; if (!harr || !*harr) { return -1; } arr = *harr; switch (arr->type) { case ARRAY_PACKED:{ if (start->type != PROG_INTEGER) { return -1; } if (end->type != PROG_INTEGER) { return -1; } if (arr->items == 0) { /* nothing to do here */ return 0; } sidx = start->data.number; eidx = end->data.number; if (sidx < 0) { sidx = 0; } else if (sidx >= arr->items) { return -1; } if (eidx >= arr->items) { eidx = arr->items - 1; } else if (eidx < 0) { return -1; } if (sidx > eidx) { return -1; } if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } start->data.number = sidx; end->data.number = eidx; copyinst(end, &idx); copyinst(start, &didx); idx.data.number += 1; while (idx.data.number < arr->items) { itm = array_getitem(arr, &idx); // plug memory leak -davin if (arr->data.packed[didx.data.number].type != PROG_CLEARED ) { CLEAR(&arr->data.packed[didx.data.number]); } copyinst(itm, &arr->data.packed[didx.data.number]); CLEAR(itm); idx.data.number++; didx.data.number++; } arr->items -= (eidx - sidx + 1); totsize = (arr->items) ? arr->items : 1; arr->data.packed = (array_data *) realloc(arr->data.packed, sizeof(array_data) * totsize); return arr->items; break; } case ARRAY_DICTIONARY:{ array_tree *s; array_tree *e; s = array_tree_find(arr->data.dict, start); if (!s) { s = array_tree_next_node(arr->data.dict, start); if (!s) { return arr->items; } } e = array_tree_find(arr->data.dict, end); if (!e) { e = array_tree_prev_node(arr->data.dict, end); if (!e) { return arr->items; } } if (array_tree_compare(&s->key, &e->key, 0, 0, 0) > 0) { return arr->items; } if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } copyinst(&s->key, &idx); while (s && array_tree_compare(&s->key, &e->key, 0, 0, 0) <= 0) { arr->data.dict = array_tree_delete(&s->key, arr->data.dict); arr->items--; s = array_tree_next_node(arr->data.dict, &idx); } CLEAR(&idx); return arr->items; break; } default: break; } return -1; }
int array_insertrange(stk_array **harr, array_iter *start, stk_array *inarr) { stk_array *arr; array_data *itm; array_iter idx; array_iter didx; if (!harr || !*harr) { return -1; } arr = *harr; if (!inarr || !inarr->items) { return arr->items; } switch (arr->type) { case ARRAY_PACKED:{ if (!start) { return -1; } if (start->type != PROG_INTEGER) { return -1; } if (start->data.number < 0 || start->data.number > arr->items) { return -1; } if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } arr->data.packed = (array_data *) realloc(arr->data.packed, sizeof(array_data) * (arr->items + inarr->items)); copyinst(start, &idx); copyinst(start, &didx); idx.data.number = arr->items - 1; didx.data.number = arr->items + inarr->items - 1; while (idx.data.number >= start->data.number) { itm = array_getitem(arr, &idx); copyinst(itm, &arr->data.packed[didx.data.number]); CLEAR(itm); idx.data.number--; didx.data.number--; } if (array_first(inarr, &idx)) { do { itm = array_getitem(inarr, &idx); copyinst(itm, &arr->data.packed[start->data.number]); start->data.number++; } while (array_next(inarr, &idx)); } arr->items += inarr->items; return arr->items; break; } case ARRAY_DICTIONARY:{ if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } if (array_first(inarr, &idx)) { do { array_setitem(&arr, &idx, array_getitem(inarr, &idx)); } while (array_next(inarr, &idx)); } return arr->items; break; } default: break; } return -1; }
int array_setitem(stk_array **harr, array_iter *idx, array_data *item) { stk_array *arr; if (!harr) return -1; if (!*harr) return -2; if (!idx) return -3; arr = *harr; switch (arr->type) { case ARRAY_PACKED:{ if (idx->type != PROG_INTEGER) { return -4; } if (idx->data.number >= 0 && idx->data.number < arr->items) { if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } CLEAR(&arr->data.packed[idx->data.number]); copyinst(item, &arr->data.packed[idx->data.number]); return arr->items; } else if (idx->data.number == arr->items) { if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } arr->data.packed = (array_data *) realloc(arr->data.packed, sizeof(array_data) * (arr->items + 1)); copyinst(item, &arr->data.packed[arr->items]); return (++arr->items); } else { return -5; } break; } case ARRAY_DICTIONARY:{ array_tree *p; if (arr->links > 1) { arr->links--; arr = *harr = array_decouple(arr); } p = array_tree_find(arr->data.dict, idx); if (p) { CLEAR(&p->data); } else { arr->items++; p = array_tree_insert(&arr->data.dict, idx); } copyinst(item, &p->data); return arr->items; break; } default: break; } return -6; }
void prim_fork(PRIM_PROTOTYPE) { int i, j; struct frame *tmpfr; CHECKOP(0); CHECKOFLOW(1); if (mlev < LMAGE) abort_interp("Mage prim"); fr->pc = pc; tmpfr = (struct frame *) calloc(1, sizeof(struct frame)); tmpfr->system.top = fr->system.top; for (i = 0; i < fr->system.top; i++) tmpfr->system.st[i] = fr->system.st[i]; tmpfr->argument.top = fr->argument.top; for (i = 0; i < fr->argument.top; i++) copyinst(&fr->argument.st[i], &tmpfr->argument.st[i]); tmpfr->caller.top = fr->caller.top; for (i = 0; i <= fr->caller.top; i++) { tmpfr->caller.st[i] = fr->caller.st[i]; if (i > 0) DBFETCH(fr->caller.st[i])->sp.program.instances++; } for (i = 0; i < MAX_VAR; i++) copyinst(&fr->variables[i], &tmpfr->variables[i]); tmpfr->varset.top = fr->varset.top; for (i = fr->varset.top; i >= 0; i--) { tmpfr->varset.st[i] = (vars *) calloc(1, sizeof(vars)); for (j = 0; j < MAX_VAR; j++) copyinst(&((*fr->varset.st[i])[j]), &((*tmpfr->varset.st[i])[j])); } tmpfr->pc = pc; tmpfr->pc++; tmpfr->level = fr->level; tmpfr->already_created = fr->already_created; tmpfr->trig = fr->trig; tmpfr->brkpt.debugging = 0; tmpfr->brkpt.count = 0; tmpfr->brkpt.showstack = 0; tmpfr->brkpt.isread = 0; tmpfr->brkpt.bypass = 0; tmpfr->brkpt.lastcmd = NULL; tmpfr->pid = top_pid++; tmpfr->multitask = BACKGROUND; tmpfr->writeonly = 1; tmpfr->started = time(NULL); tmpfr->instcnt = 0; /* child process gets a 0 returned on the stack */ result = 0; push(tmpfr->argument.st, &(tmpfr->argument.top), PROG_INTEGER, MIPSCAST & result); result = add_muf_delay_event(0, fr->descr, player, NOTHING, NOTHING, program, tmpfr, "BACKGROUND"); /* parent process gets the child's pid returned on the stack */ if (!result) result = -1; PushInt(result); }
void prim_fork(PRIM_PROTOTYPE) { int i; struct frame *tmpfr; CHECKOP(0); CHECKOFLOW(1); if (mlev < 3) abort_interp("Permission Denied."); fr->pc = pc; tmpfr = (struct frame *) calloc(1, sizeof(struct frame)); tmpfr->next = NULL; tmpfr->system.top = fr->system.top; for (i = 0; i < fr->system.top; i++) tmpfr->system.st[i] = fr->system.st[i]; tmpfr->argument.top = fr->argument.top; for (i = 0; i < fr->argument.top; i++) copyinst(&fr->argument.st[i], &tmpfr->argument.st[i]); tmpfr->caller.top = fr->caller.top; for (i = 0; i <= fr->caller.top; i++) { tmpfr->caller.st[i] = fr->caller.st[i]; if (i > 0) PROGRAM_INC_INSTANCES(fr->caller.st[i]); } tmpfr->trys.top = fr->trys.top; tmpfr->trys.st = copy_trys(fr->trys.st); tmpfr->fors.top = fr->fors.top; tmpfr->fors.st = copy_fors(fr->fors.st); for (i = 0; i < MAX_VAR; i++) copyinst(&fr->variables[i], &tmpfr->variables[i]); localvar_dupall(tmpfr, fr); scopedvar_dupall(tmpfr, fr); tmpfr->error.is_flags = fr->error.is_flags; if (fr->rndbuf) { tmpfr->rndbuf = (void *) malloc(sizeof(unsigned long) * 4); if (tmpfr->rndbuf) { memcpy(tmpfr->rndbuf, fr->rndbuf, 16); } } else { tmpfr->rndbuf = NULL; } tmpfr->pc = pc; tmpfr->pc++; tmpfr->level = fr->level; tmpfr->already_created = fr->already_created; tmpfr->trig = fr->trig; tmpfr->brkpt.debugging = 0; tmpfr->brkpt.bypass = 0; tmpfr->brkpt.isread = 0; tmpfr->brkpt.showstack = 0; tmpfr->brkpt.lastline = 0; tmpfr->brkpt.lastpc = 0; tmpfr->brkpt.lastlisted = 0; tmpfr->brkpt.lastcmd = NULL; tmpfr->brkpt.breaknum = -1; tmpfr->brkpt.lastproglisted = NOTHING; tmpfr->brkpt.proglines = NULL; tmpfr->brkpt.count = 1; tmpfr->brkpt.temp[0] = 1; tmpfr->brkpt.level[0] = -1; tmpfr->brkpt.line[0] = -1; tmpfr->brkpt.linecount[0] = -2; tmpfr->brkpt.pc[0] = NULL; tmpfr->brkpt.pccount[0] = -2; tmpfr->brkpt.prog[0] = program; tmpfr->proftime.tv_sec = 0; tmpfr->proftime.tv_usec = 0; tmpfr->totaltime.tv_sec = 0; tmpfr->totaltime.tv_usec = 0; tmpfr->pid = top_pid++; tmpfr->multitask = BACKGROUND; tmpfr->been_background = 1; tmpfr->writeonly = 1; tmpfr->started = time(NULL); tmpfr->instcnt = 0; tmpfr->skip_declare = fr->skip_declare; tmpfr->wantsblanks = fr->wantsblanks; tmpfr->perms = fr->perms; tmpfr->descr = fr->descr; tmpfr->events = NULL; tmpfr->waiters = NULL; tmpfr->waitees = NULL; tmpfr->dlogids = NULL; tmpfr->timercount = 0; /* child process gets a 0 returned on the stack */ result = 0; push(tmpfr->argument.st, &(tmpfr->argument.top), PROG_INTEGER, MIPSCAST & result); result = add_muf_delay_event(0, fr->descr, player, NOTHING, NOTHING, program, tmpfr, "BACKGROUND"); /* parent process gets the child's pid returned on the stack */ if (!result) result = -1; PushInt(result); }