/* insert this line into program */ void insert(dbref player, const char *line) { dbref program; int i; struct line *curr; struct line *new_line; program = PLAYER_CURR_PROG(player); if (!string_compare(line, EXIT_INSERT)) { PLAYER_SET_INSERT_MODE(player, 0); /* turn off insert mode */ notify_nolisten(player, "Exiting insert mode.", 1); return; } i = PROGRAM_CURR_LINE(program) - 1; for (curr = PROGRAM_FIRST(program); curr && i && i + 1; i--) curr = curr->next; new_line = get_new_line(); /* initialize line */ if (!*line) { new_line->this_line = alloc_string(" "); } else { new_line->this_line = alloc_string(line); } if (!PROGRAM_FIRST(program)) { /* nothing --- insert in front */ PROGRAM_SET_FIRST(program, new_line); PROGRAM_SET_CURR_LINE(program, 2); /* insert at the end */ /* DBDIRTY(program); */ return; } if (!curr) { /* insert at the end */ i = 1; for (curr = PROGRAM_FIRST(program); curr->next; curr = curr->next) i++; /* count lines */ PROGRAM_SET_CURR_LINE(program, i + 2); new_line->prev = curr; curr->next = new_line; /* DBDIRTY(program); */ return; } if (!PROGRAM_CURR_LINE(program)) { /* insert at the * beginning */ PROGRAM_SET_CURR_LINE(program, 1); /* insert after this new * line */ new_line->next = PROGRAM_FIRST(program); PROGRAM_SET_FIRST(program, new_line); /* DBDIRTY(program); */ return; } /* inserting in the middle */ PROGRAM_SET_CURR_LINE(program, PROGRAM_CURR_LINE(program) + 1); new_line->prev = curr; new_line->next = curr->next; if (new_line->next) new_line->next->prev = new_line; curr->next = new_line; /* DBDIRTY(program); */ }
/** * List program lines to a player * * This is used by the debugger for listing lines and for backtraces. * Uses the editor's list_program under the hood. * * @see list_program * * @param player the player to send the listing to * @param program the program to list * @param fr the running program frame * @param start the start line * @param end the end line */ void list_proglines(dbref player, dbref program, struct frame *fr, int start, int end) { int range[2]; int argc; if (start == end || end == 0) { range[0] = start; range[1] = start; argc = 1; } else { range[0] = start; range[1] = end; argc = 2; } /* Make sure we have the lines of code loaded for display */ if (!fr->brkpt.proglines || program != fr->brkpt.lastproglisted) { free_prog_text(fr->brkpt.proglines); fr->brkpt.proglines = (struct line *) read_program(program); fr->brkpt.lastproglisted = program; } { /* * We have to change the program position in order to do the * listing, so we use this tmpline so we can reset it when * we are done. */ struct line *tmpline = PROGRAM_FIRST(program); PROGRAM_SET_FIRST(program, fr->brkpt.proglines); { int tmpflg = (FLAGS(player) & INTERNAL); FLAGS(player) |= INTERNAL; list_program(player, program, range, argc, 0); if (!tmpflg) { FLAGS(player) &= ~INTERNAL; } } PROGRAM_SET_FIRST(program, tmpline); } return; }
void prim_cancallp(PRIM_PROTOTYPE) { CHECKOP(2); oper2 = POP(); /* string: public function name */ oper1 = POP(); /* dbref: Program dbref to check */ if (oper1->type != PROG_OBJECT) abort_interp("Expected dbref argument. (1)"); if (!valid_object(oper1)) abort_interp("Invalid dbref (1)"); if (Typeof(oper1->data.objref) != TYPE_PROGRAM) abort_interp("Object is not a MUF Program. (1)"); if (oper2->type != PROG_STRING) abort_interp("Expected string argument. (2)"); if (!oper2->data.string) abort_interp("Invalid Null string argument. (2)"); if (!(PROGRAM_CODE(oper1->data.objref))) { struct line *tmpline; tmpline = PROGRAM_FIRST(oper1->data.objref); PROGRAM_SET_FIRST(oper1->data.objref, (struct line *) read_program(oper1->data.objref)); do_compile(-1, OWNER(oper1->data.objref), oper1->data.objref, 0); free_prog_text(PROGRAM_FIRST(oper1->data.objref)); PROGRAM_SET_FIRST(oper1->data.objref, tmpline); } result = 0; if (ProgMLevel(oper1->data.objref) > 0 && (mlev >= 4 || OWNER(oper1->data.objref) == ProgUID || Linkable(oper1->data.objref)) ) { struct publics *pbs; pbs = PROGRAM_PUBS(oper1->data.objref); while (pbs) { if (!strcasecmp(oper2->data.string->data, pbs->subname)) break; pbs = pbs->next; } if (pbs && mlev >= pbs->mlev) result = 1; } CHECKOFLOW(1); CLEAR(oper1); CLEAR(oper2); PushInt(result); }
void list_publics(int descr, dbref player, int arg[], int argc) { dbref program; if (argc > 1) { notify(player, "I don't understand which program you want to list PUBLIC functions for."); return; } program = (argc == 0) ? PLAYER_CURR_PROG(player) : arg[0]; if (Typeof(program) != TYPE_PROGRAM) { notify(player, "That isn't a program."); return; } if (!(controls(player, program) || Linkable(program))) { notify(player, "That's not a public program."); return; } if (!(PROGRAM_CODE(program))) { if (program == PLAYER_CURR_PROG(player)) { do_compile(descr, OWNER(program), program, 0); } else { struct line *tmpline; tmpline = PROGRAM_FIRST(program); PROGRAM_SET_FIRST(program, (struct line *) read_program(program)); do_compile(descr, OWNER(program), program, 0); free_prog_text(PROGRAM_FIRST(program)); PROGRAM_SET_FIRST(program, tmpline); } if (!PROGRAM_CODE(program)) { notify(player, "Program not compilable."); return; } } do_list_publics(player, program); }
/* deletes line n if one argument, lines arg1 -- arg2 if two arguments current line if no argument */ void do_delete(dbref player, dbref program, int arg[], int argc) { struct line *curr, *temp; char buf[BUFFER_LEN]; int i; switch (argc) { case 0: arg[0] = PROGRAM_CURR_LINE(program); case 1: arg[1] = arg[0]; case 2: /* delete from line 1 to line 2 */ /* first, check for conflict */ if (arg[0] > arg[1]) { notify(player, "Nonsensical arguments."); return; } i = arg[0] - 1; for (curr = PROGRAM_FIRST(program); curr && i; i--) curr = curr->next; if (curr) { PROGRAM_SET_CURR_LINE(program, arg[0]); i = arg[1] - arg[0] + 1; /* delete n lines */ while (i && curr) { temp = curr; if (curr->prev) curr->prev->next = curr->next; else PROGRAM_SET_FIRST(program, curr->next); if (curr->next) curr->next->prev = curr->prev; curr = curr->next; free_line(temp); i--; } snprintf(buf, sizeof(buf), "%d lines deleted", arg[1] - arg[0] - i + 1); notify(player, buf); } else notify(player, "No line to delete!"); break; default: notify(player, "Too many arguments!"); break; } }
/* quit from edit mode. Put player back into the regular game mode */ void do_quit(dbref player, dbref program) { log_status("PROGRAM SAVED: %s by %s(%d)", unparse_object(player, program), NAME(player), player); write_program(PROGRAM_FIRST(program), program); if (tp_log_programs) log_program_text(PROGRAM_FIRST(program), player, program); free_prog_text(PROGRAM_FIRST(program)); PROGRAM_SET_FIRST(program, NULL); FLAGS(program) &= ~INTERNAL; FLAGS(player) &= ~INTERACTIVE; PLAYER_SET_CURR_PROG(player, NOTHING); DBDIRTY(player); DBDIRTY(program); }
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; }
void match_and_list(int descr, dbref player, const char *name, char *linespec) { dbref thing; char *p; char *q; int range[2]; int argc; struct match_data md; struct line *tmpline; init_match(descr, player, name, TYPE_PROGRAM, &md); match_neighbor(&md); match_possession(&md); match_registered(&md); match_absolute(&md); if ((thing = noisy_match_result(&md)) == NOTHING) return; if (Typeof(thing) != TYPE_PROGRAM) { notify(player, "You can't list anything but a program."); return; } /* if (!(controls(player, thing) || Linkable(thing))) { */ if (!(controls(player, thing) || (FLAGS(thing) & VEHICLE))) { notify(player, "Permission denied. (You don't control the program, and it's not set Viewable)"); return; } if (!*linespec) { range[0] = 1; range[1] = -1; argc = 2; } else { q = p = linespec; while (*p) { while (*p && !isspace(*p)) *q++ = *p++; while (*p && isspace(*++p)) ; } *q = '\0'; argc = 1; if (isdigit(*linespec)) { range[0] = atoi(linespec); while (*linespec && isdigit(*linespec)) linespec++; } else { range[0] = 1; } if (*linespec) { argc = 2; while (*linespec && !isdigit(*linespec)) linespec++; if (*linespec) range[1] = atoi(linespec); else range[1] = -1; } } tmpline = PROGRAM_FIRST(thing); PROGRAM_SET_FIRST(thing, read_program(thing)); do_list(player, thing, range, argc); free_prog_text(PROGRAM_FIRST(thing)); PROGRAM_SET_FIRST(thing, tmpline); return; }