/** * Displays a MUF Backtrace message. * * This is used when a MUF program is aborted, if someone who has 'controls' * permissions was running it, or if you type 'where' in the debugger. * Shows a fairly straight forward backtrace, going 'count' deep. If * 'count' is 0, it will display up to STACK_SIZE depth. * * @param player the player getting the backtrace * @param program the program being backtraced * @param count the depth of the trace, or 0 for STACK_SIZE * @param fr the frame pointer */ void muf_backtrace(dbref player, dbref program, int count, struct frame *fr) { char buf2[BUFFER_LEN]; char buf3[BUFFER_LEN]; char *ptr; dbref ref; int i, j, cnt, flag; struct inst *pinst, *lastinst; int lev; notify_nolisten(player, "\033[1;33;40mSystem stack backtrace:\033[0m", 1); i = count; if (!i) i = STACK_SIZE; ref = program; pinst = NULL; j = fr->system.top + 1; /* * i is our depth; iterate until we've run out of depth or we have * broken out of the loop */ while (j > 1 && i-- > 0) { cnt = 0; do { lastinst = pinst; if (--j == fr->system.top) { pinst = fr->pc; } else { ref = fr->system.st[j].progref; pinst = fr->system.st[j].offset; } ptr = unparse_sysreturn(&ref, pinst); cnt++; } while (pinst == lastinst && j > 1); if (cnt > 1) { notifyf_nolisten(player, " [repeats %d times]", cnt); } lev = fr->system.top - j; if (ptr) { int snplen; char *bufend = buf2; struct inst *fntop = fr->pc; struct inst *varinst; while (fntop->type != PROG_FUNCTION) fntop--; snplen = snprintf(buf2, sizeof(buf2), "%.512s\033[1m(\033[0m", ptr); if (snplen == -1) { buf2[sizeof(buf2) - 1] = '\0'; snplen = sizeof(buf2) - 1; } bufend += snplen; for (int k = 0; k < fntop->data.mufproc->args; k++) { const char *nam = scopedvar_getname(fr, lev, k); char *val; if (!nam) { break; } varinst = scopedvar_get(fr, lev, k); val = insttotext(fr, lev, varinst, buf3, sizeof(buf3), 30, program, 1); if (k) { bufend += snprintf(bufend, buf2 - bufend - 18, "\033[1m, %s=\033[0m%s", nam, val); } else { bufend += snprintf(bufend, buf2 - bufend - 18, "\033[1m%s=\033[0m%s", nam, val); } } ptr = buf2; } if (pinst != lastinst) { notifyf_nolisten(player, "\033[1;33;40m%3d)\033[0m \033[1m%s(#%d)\033[0m %s:", lev, NAME(ref), ref, ptr); flag = ((FLAGS(player) & INTERNAL) ? 1 : 0); FLAGS(player) &= ~INTERNAL; list_proglines(player, ref, fr, pinst->line, 0); if (flag) { FLAGS(player) |= INTERNAL; } } } notify_nolisten(player, "\033[1;33;40m*done*\033[0m", 1); }
static void push_arg(dbref player, struct frame *fr, const char *arg) { int num = 0, lflag = 0, sflag = 0; double inum = 0.0; if (fr->argument.top >= STACK_SIZE) { anotify_nolisten(player, CFAIL "That would overflow the stack.", 1); return; } if (number(arg)) { /* push a number */ num = atoi(arg); push(fr->argument.st, &fr->argument.top, PROG_INTEGER, MIPSCAST & num); anotify_nolisten(player, CSUCC "Integer pushed.", 1); } else if (ifloat(arg)) { /* push a float */ inum = atof(arg); push(fr->argument.st, &fr->argument.top, PROG_FLOAT, MIPSCAST & inum); notify_nolisten(player, "Float pushed.", 1); } else if (*arg == NUMBER_TOKEN) { /* push a dbref */ if (!number(arg + 1)) { anotify_nolisten(player, CINFO "I don't understand that dbref.", 1); return; } num = atoi(arg + 1); push(fr->argument.st, &fr->argument.top, PROG_OBJECT, MIPSCAST & num); anotify_nolisten(player, CSUCC "Dbref pushed.", 1); } else if (*arg == '"') { /* push a string */ char buf[BUFFER_LEN]; char *ptr; const char *ptr2; for (ptr = buf, ptr2 = arg + 1; *ptr2; ptr2++) { if (*ptr2 == '\\') { if (!*(++ptr2)) break; *ptr++ = *ptr2; } else if (*ptr2 == '"') { break; } else { *ptr++ = *ptr2; } } *ptr = '\0'; push(fr->argument.st, &fr->argument.top, PROG_STRING, MIPSCAST alloc_prog_string(buf)); anotify_nolisten(player, CSUCC "String pushed.", 1); } else { int varnum = scopedvar_getnum(fr, 0, arg); if (varnum != -1) { sflag = 1; } else { if (*arg == 'S' || *arg == 's') { ++arg; if (*arg == 'V' || *arg == 'v') { arg++; } sflag = 1; varnum = scopedvar_getnum(fr, 0, arg); } else if (*arg == 'L' || *arg == 'l') { ++arg; if (*arg == 'V' || *arg == 'v') { ++arg; } lflag = 1; } else if (*arg == 'V' || *arg == 'v') { ++arg; } } if (varnum > -1) { num = varnum; } else if (number(arg)) { num = atoi(arg); } else { anotify_nolisten(player, CINFO "I don't understand what you want to push.", 1); return; } if (lflag) { push(fr->argument.st, &fr->argument.top, PROG_LVAR, MIPSCAST & num); anotify_nolisten(player, CSUCC "Local variable pushed.", 1); } else if (sflag) { push(fr->argument.st, &fr->argument.top, PROG_SVAR, MIPSCAST & num); anotify_nolisten(player, CSUCC "Scoped variable pushed.", 1); } else { push(fr->argument.st, &fr->argument.top, PROG_VAR, MIPSCAST & num); anotify_nolisten(player, CSUCC "Global variable pushed.", 1); } } }
int muf_debugger(int descr, dbref player, dbref program, const char *text, struct frame *fr) { char cmd[BUFFER_LEN]; char buf[BUFFER_LEN]; char buf2[BUFFER_LEN]; char *ptr, *ptr2, *arg; struct inst *pinst; dbref ref; int i, j, cnt; while (isspace(*text)) text++; strcpy(cmd, text); ptr = cmd + strlen(cmd); if (ptr > cmd) ptr--; while (ptr >= cmd && isspace(*ptr)) *ptr-- = '\0'; for (arg = cmd; *arg && !isspace(*arg); arg++) ; if (*arg) *arg++ = '\0'; if (!*cmd && fr->brkpt.lastcmd) { strcpy(cmd, fr->brkpt.lastcmd); } else { if (fr->brkpt.lastcmd) free(fr->brkpt.lastcmd); if (*cmd) fr->brkpt.lastcmd = string_dup(cmd); } /* delete triggering breakpoint, if it's only temp. */ j = fr->brkpt.breaknum; if (j >= 0 && fr->brkpt.temp[j]) { for (j++; j < fr->brkpt.count; j++) { fr->brkpt.temp[j - 1] = fr->brkpt.temp[j]; fr->brkpt.level[j - 1] = fr->brkpt.level[j]; fr->brkpt.line[j - 1] = fr->brkpt.line[j]; fr->brkpt.linecount[j - 1] = fr->brkpt.linecount[j]; fr->brkpt.pc[j - 1] = fr->brkpt.pc[j]; fr->brkpt.pccount[j - 1] = fr->brkpt.pccount[j]; fr->brkpt.prog[j - 1] = fr->brkpt.prog[j]; } fr->brkpt.count--; } fr->brkpt.breaknum = -1; if (!string_compare(cmd, "cont")) { } else if (!string_compare(cmd, "finish")) { if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Cannot finish because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top - 1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!string_compare(cmd, "stepi")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Cannot stepi because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = i; fr->brkpt.prog[j] = NOTHING; fr->brkpt.bypass = 1; return 0; } else if (!string_compare(cmd, "step")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Cannot step because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = i; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = NOTHING; fr->brkpt.bypass = 1; return 0; } else if (!string_compare(cmd, "nexti")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Cannot nexti because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = i; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!string_compare(cmd, "next")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Cannot next because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = i; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!string_compare(cmd, "exec")) { if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Cannot finish because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (!(pinst = funcname_to_pc(program, arg))) { anotify_nolisten(player, CINFO "I don't know a function by that name.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (fr->system.top >= STACK_SIZE) { anotify_nolisten(player, CFAIL "That would exceed the system stack size for this program.", 1); add_muf_read_event(descr, player, program, fr); return 0; } fr->system.st[fr->system.top].progref = program; fr->system.st[fr->system.top++].offset = fr->pc; fr->pc = pinst; j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = fr->system.top - 1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; return 0; } else if (!string_compare(cmd, "prim")) { if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Cannot finish because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (!(i = primitive(arg))) { anotify_nolisten(player, CINFO "I don't recognize that primitive.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (fr->system.top >= STACK_SIZE) { anotify_nolisten(player, CFAIL "That would exceed the system stack size for this program.", 1); add_muf_read_event(descr, player, program, fr); return 0; } primset[0].type = PROG_FUNCTION; primset[0].line = 0; primset[0].data.mufproc = &temp_muf_proc_data; primset[0].data.mufproc->vars = 0; primset[0].data.mufproc->args = 0; primset[0].data.mufproc->varnames = NULL; primset[1].type = PROG_PRIMITIVE; primset[1].line = 0; primset[1].data.number = get_primitive(arg); primset[2].type = PROG_PRIMITIVE; primset[2].line = 0; primset[2].data.number = IN_RET; /* primset[3].data.number = primitive("EXIT"); */ fr->system.st[fr->system.top].progref = program; fr->system.st[fr->system.top++].offset = fr->pc; fr->pc = &primset[1]; j = fr->brkpt.count++; fr->brkpt.temp[j] = 1; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = -1; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = &primset[2]; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; fr->brkpt.bypass = 1; fr->brkpt.dosyspop = 1; return 0; } else if (!string_compare(cmd, "break")) { add_muf_read_event(descr, player, program, fr); if (fr->brkpt.count >= MAX_BREAKS) { anotify_nolisten(player, CFAIL "Too many breakpoints set.", 1); return 0; } if (number(arg)) { i = atoi(arg); } else { if (!(pinst = funcname_to_pc(program, arg))) { anotify_nolisten(player, CINFO "I don't know a function by that name.", 1); return 0; } else { i = pinst->line; } } if (!i) i = fr->pc->line; j = fr->brkpt.count++; fr->brkpt.temp[j] = 0; fr->brkpt.level[j] = -1; fr->brkpt.line[j] = i; fr->brkpt.linecount[j] = -2; fr->brkpt.pc[j] = NULL; fr->brkpt.pccount[j] = -2; fr->brkpt.prog[j] = program; anotify_nolisten(player, CSUCC "Breakpoint set.", 1); return 0; } else if (!string_compare(cmd, "delete")) { add_muf_read_event(descr, player, program, fr); i = atoi(arg); if (!i) { anotify_nolisten(player, CINFO "Which breakpoint did you want to delete?", 1); return 0; } if (i < 1 || i > fr->brkpt.count) { anotify_nolisten(player, CFAIL "No such breakpoint.", 1); return 0; } j = i - 1; for (j++; j < fr->brkpt.count; j++) { fr->brkpt.temp[j - 1] = fr->brkpt.temp[j]; fr->brkpt.level[j - 1] = fr->brkpt.level[j]; fr->brkpt.line[j - 1] = fr->brkpt.line[j]; fr->brkpt.linecount[j - 1] = fr->brkpt.linecount[j]; fr->brkpt.pc[j - 1] = fr->brkpt.pc[j]; fr->brkpt.pccount[j - 1] = fr->brkpt.pccount[j]; fr->brkpt.prog[j - 1] = fr->brkpt.prog[j]; } fr->brkpt.count--; anotify_nolisten(player, CSUCC "Breakpoint deleted.", 1); return 0; } else if (!string_compare(cmd, "breaks")) { anotify_nolisten(player, CINFO "Breakpoints:", 1); for (i = 0; i < fr->brkpt.count; i++) { ptr = unparse_breakpoint(fr, i); notify_nolisten(player, ptr, 1); } anotify_nolisten(player, CINFO "Done.", 1); add_muf_read_event(descr, player, program, fr); return 0; } else if (!string_compare(cmd, "where")) { i = atoi(arg); muf_backtrace(player, program, i, fr); add_muf_read_event(descr, player, program, fr); return 0; } else if (!string_compare(cmd, "stack")) { anotify_nolisten(player, CINFO "*Argument stack top*", 1); i = atoi(arg); if (!i) i = STACK_SIZE; ptr = ""; ref = program; for (j = fr->argument.top; j > 0 && i-- > 0;) { cnt = 0; do { strcpy(buf, ptr); ptr = insttotext(NULL, 0, &fr->argument.st[--j], buf2, sizeof(buf2), 4000, program); cnt++; } while (!string_compare(ptr, buf) && j > 0); if (cnt > 1) notify_fmt(player, " [repeats %d times]", cnt); if (string_compare(ptr, buf)) notify_fmt(player, "%3d) %s", j + 1, ptr); } anotify_nolisten(player, CINFO "Done.", 1); add_muf_read_event(descr, player, program, fr); return 0; } else if (!string_compare(cmd, "list") || !string_compare(cmd, "listi")) { int startline, endline; startline = endline = 0; add_muf_read_event(descr, player, program, fr); if ((ptr2 = (char *) index(arg, ','))) { *ptr2++ = '\0'; } else { ptr2 = ""; } if (!*arg) { if (fr->brkpt.lastlisted) { startline = fr->brkpt.lastlisted + 1; } else { startline = fr->pc->line; } endline = startline + 15; } else { if (!number(arg)) { if (!(pinst = funcname_to_pc(program, arg))) { anotify_nolisten(player, CINFO "I don't know a function by that name. (starting arg, 1)", 1); return 0; } else { startline = pinst->line; endline = startline + 15; } } else { if (*ptr2) { endline = startline = atoi(arg); } else { startline = atoi(arg) - 7; endline = startline + 15; } } } if (*ptr2) { if (!number(ptr2)) { if (!(pinst = funcname_to_pc(program, ptr2))) { anotify_nolisten(player, CINFO "I don't know a function by that name. (ending arg, 1)", 1); return 0; } else { endline = pinst->line; } } else { endline = atoi(ptr2); } } i = (DBFETCH(program)->sp.program.code + DBFETCH(program)->sp.program.siz - 1)->line; if (startline > i) { anotify_nolisten(player, CFAIL "Starting line is beyond end of program.", 1); return 0; } if (startline < 1) startline = 1; if (endline > i) endline = i; if (endline < startline) endline = startline; anotify_nolisten(player, CINFO "Listing:", 1); if (!string_compare(cmd, "listi")) { for (i = startline; i <= endline; i++) { pinst = linenum_to_pc(program, i); if (pinst) { sprintf(buf, "line %d: %s", i, (i == fr->pc->line) ? show_line_prims(fr, program, fr->pc, STACK_SIZE, 1) : show_line_prims(fr, program, pinst, STACK_SIZE, 0)); notify_nolisten(player, buf, 1); } } } else { list_proglines(player, program, fr, startline, endline); } fr->brkpt.lastlisted = endline; anotify_nolisten(player, CINFO "Done.", 1); return 0; } else if (!string_compare(cmd, "quit")) { anotify_nolisten(player, CINFO "Halting execution.", 1); return 1; } else if (!string_compare(cmd, "trace")) { add_muf_read_event(descr, player, program, fr); if (!string_compare(arg, "on")) { fr->brkpt.showstack = 1; anotify_nolisten(player, CSUCC "Trace turned on.", 1); } else if (!string_compare(arg, "off")) { fr->brkpt.showstack = 0; anotify_nolisten(player, CSUCC "Trace turned off.", 1); } else { sprintf(buf, CINFO "Trace is currently %s.", fr->brkpt.showstack ? "on" : "off"); anotify_nolisten(player, buf, 1); } return 0; } else if (!string_compare(cmd, "words")) { list_program_functions(player, program, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!string_compare(cmd, "print")) { debug_printvar(player, program, fr, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!string_compare(cmd, "push")) { push_arg(player, fr, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!string_compare(cmd, "pop")) { add_muf_read_event(descr, player, program, fr); if (fr->argument.top < 1) { notify_nolisten(player, "Nothing to pop.", 1); return 0; } fr->argument.top--; CLEAR(fr->argument.st + fr->argument.top); notify_nolisten(player, "Stack item popped.", 1); return 0; } else if (!string_compare(cmd, "help")) { notify_nolisten(player, "cont continues execution until a breakpoint is hit.", 1); notify_nolisten(player, "finish completes execution of current function.", 1); notify_nolisten(player, "step [NUM] executes one (or NUM, 1) lines of muf.", 1); notify_nolisten(player, "stepi [NUM] executes one (or NUM, 1) muf instructions.", 1); notify_nolisten(player, "next [NUM] like step, except skips CALL and EXECUTE.", 1); notify_nolisten(player, "nexti [NUM] like stepi, except skips CALL and EXECUTE.", 1); notify_nolisten(player, "break LINE# sets breakpoint at given LINE number.", 1); notify_nolisten(player, "break FUNCNAME sets breakpoint at start of given function.", 1); notify_nolisten(player, "breaks lists all currently set breakpoints.", 1); notify_nolisten(player, "delete NUM deletes breakpoint by NUM, as listed by 'breaks'", 1); notify_nolisten(player, "where [LEVS] displays function call backtrace of up to num levels deep.", 1); notify_nolisten(player, "stack [NUM] shows the top num items on the stack.", 1); notify_nolisten(player, "print v# displays the value of given global variable #.", 1); notify_nolisten(player, "print lv# displays the value of given local variable #.", 1); notify_nolisten(player, "trace [on|off] turns on/off debug stack tracing.", 1); notify_nolisten(player, "list [L1,[L2]] lists source code of given line range.", 1); notify_nolisten(player, "list FUNCNAME lists source code of given function.", 1); notify_nolisten(player, "listi [L1,[L2]] lists instructions in given line range.", 1); notify_nolisten(player, "listi FUNCNAME lists instructions in given function.", 1); notify_nolisten(player, "words lists all function word names in program.", 1); notify_nolisten(player, "words PATTERN lists all function word names that match PATTERN.", 1); notify_nolisten(player, "exec FUNCNAME calls given function with the current stack data.", 1); notify_nolisten(player, "prim PRIMITIVE executes given primitive with current stack data.", 1); notify_nolisten(player, "push DATA pushes an int, dbref, var, or string onto the stack.", 1); notify_nolisten(player, "pop pops top data item off the stack.", 1); notify_nolisten(player, "help displays this help screen.", 1); notify_nolisten(player, "quit stop execution here.", 1); add_muf_read_event(descr, player, program, fr); return 0; } else { anotify_nolisten(player, CINFO "I don't understand that debugger command. Type 'help' for help.", 1); add_muf_read_event(descr, player, program, fr); return 0; } return 0; }
void muf_backtrace(dbref player, dbref program, int count, struct frame *fr) { char buf[BUFFER_LEN]; char buf2[BUFFER_LEN]; char buf3[BUFFER_LEN]; char *ptr; dbref ref; int i, j, cnt, flag; struct inst *pinst, *lastinst; int lev; anotify_nolisten(player, CINFO "System stack backtrace:", 1); i = count; if (!i) i = STACK_SIZE; ref = program; pinst = NULL; j = fr->system.top + 1; while (j > 1 && i-- > 0) { cnt = 0; do { lastinst = pinst; if (--j == fr->system.top) { pinst = fr->pc + 1; } else { ref = fr->system.st[j].progref; pinst = fr->system.st[j].offset; } ptr = unparse_sysreturn(&ref, pinst); cnt++; } while (pinst == lastinst && j > 1); if (cnt > 1) { sprintf(buf, " [repeats %d times]", cnt); notify_nolisten(player, buf, 1); } lev = fr->system.top - j; if (ptr) { int k; char *bufend = buf2; struct inst *fntop = fr->pc; struct inst *varinst; while (fntop->type != PROG_FUNCTION) --fntop; bufend += sprintf(buf2, "%.512s" SYSWHITE "(" SYSNORMAL, ptr); for (k = 0; k < fntop->data.mufproc->args; ++k) { const char *nam = scopedvar_getname(fr, lev, k); char *val; const char *fmt; if (!nam) { break; } varinst = scopedvar_get(fr, lev, k); val = insttotext(fr, lev, varinst, buf3, sizeof(buf3), 30, program); if (k) { fmt = SYSWHITE ", %s=" SYSNORMAL "%s"; } else { fmt = SYSWHITE "%s=" SYSNORMAL "%s"; } bufend += snprintf(bufend, buf2 - bufend - 18, fmt, nam, val); } bufend += snprintf(bufend, buf2 - bufend - 1, SYSWHITE ")" SYSNORMAL, ptr); ptr = buf2; } if (pinst != lastinst) { sprintf(buf, "%3d) %s(#%d) %s:", j, NAME(ref), ref, ptr); notify_nolisten(player, buf, 1); flag = ((FLAGS(player) & INTERNAL) ? 1 : 0); FLAGS(player) &= ~INTERNAL; list_proglines(player, ref, fr, (pinst - 1)->line, 0); if (flag) { FLAGS(player) |= INTERNAL; } } } anotify_nolisten(player, CINFO "Done.", 1); }
static void debug_printvar(dbref player, dbref program, struct frame *fr, const char *arg) { int i; int lflag = 0; int sflag = 0; int varnum = -1; char buf[BUFFER_LEN]; if (!arg || !*arg) { anotify_nolisten(player, CINFO "I don't know which variable you mean.", 1); return; } varnum = scopedvar_getnum(fr, 0, arg); if (varnum != -1) { sflag = 1; } else if (*arg == 'L' || *arg == 'l') { arg++; if (*arg == 'V' || *arg == 'v') { arg++; } lflag = 1; varnum = scopedvar_getnum(fr, 0, arg); } else if (*arg == 'S' || *arg == 's') { arg++; if (*arg == 'V' || *arg == 'v') { arg++; } sflag = 1; } else if (*arg == 'V' || *arg == 'v') { arg++; } if (varnum > -1) { i = varnum; } else if (number(arg)) { i = atoi(arg); } else { notify_nolisten(player, "I don't know which variable you mean.", 1); return; } if (i >= MAX_VAR || i < 0) { anotify_nolisten(player, CINFO "Variable number out of range.", 1); return; } if (sflag) { struct inst *tmp = scopedvar_get(fr, 0, i); if (!tmp) { notify_nolisten(player, "Scoped variable number out of range.", 1); return; } notify_nolisten(player, insttotext(fr, 0, tmp, buf, sizeof(buf), 4000, -1), 1); } else if (lflag) { struct localvars *lvars = localvars_get(fr, program); notify_nolisten(player, insttotext(fr, 0, &(lvars->lvars[i]), buf, sizeof(buf), 4000, -1), 1); } else { notify_nolisten(player, insttotext(fr, 0, &(fr->variables[i]), buf, sizeof(buf), 4000, -1), 1); } }
void list_events(dbref player) { char buf[BUFFER_LEN]; char pidstr[128]; char duestr[128]; char runstr[128]; char inststr[128]; char cpustr[128]; char progstr[128]; char prognamestr[128]; int count = 0; timequeue ptr = tqhead; time_t rtime = time((time_t *) NULL); time_t etime; double pcnt; const char* strfmt = "%10s %4s %4s %6s %4s %7s %-10.10s %-12s %.512s"; (void)snprintf(buf, sizeof(buf), strfmt, "PID", "Next", "Run", "KInst", "%CPU", "Prog#", "ProgName", "Player", ""); notify_nolisten(player, buf, 1); while (ptr) { /* pid */ snprintf(pidstr, sizeof(pidstr), "%d", ptr->eventnum); /* next due */ strcpyn(duestr, sizeof(duestr), ((ptr->when - rtime) > 0) ? time_format_2((long) (ptr->when - rtime)) : "Due"); /* Run length */ strcpyn(runstr, sizeof(runstr), ptr->fr ? time_format_2((long) (rtime - ptr->fr->started)): "0s"); /* Thousand Instructions executed */ snprintf(inststr, sizeof(inststr), "%d", ptr->fr? (ptr->fr->instcnt / 1000) : 0); /* If it's actually a program, instead of MPI... */ /* we need to figure out how much CPU it's used */ if (ptr->fr) { etime = rtime - ptr->fr->started; if (etime > 0) { pcnt = ptr->fr->totaltime.tv_sec; pcnt += ptr->fr->totaltime.tv_usec / 1000000; pcnt = pcnt * 100 / etime; if (pcnt > 99.9) { pcnt = 99.9; } } else { pcnt = 0.0; } } else { pcnt = 0.0; } snprintf(cpustr, sizeof(cpustr), "%4.1f", pcnt); /* Get the dbref! */ if (ptr->fr) { /* if it's a program... */ snprintf(progstr, sizeof(progstr), "#%d", ptr->fr->caller.st[1]); snprintf(prognamestr, sizeof(prognamestr), "%s", NAME(ptr->fr->caller.st[1])); } else if (ptr->typ == TQ_MPI_TYP) { /* if it's MPI... */ snprintf(progstr, sizeof(progstr), "#%d", ptr->trig); snprintf(prognamestr, sizeof(prognamestr), "%s", ""); } else { /* if it's anything else... */ snprintf(progstr, sizeof(progstr), "#%d", ptr->called_prog); snprintf(prognamestr, sizeof(prognamestr), "%s", NAME(ptr->called_prog)); } /* Now, the next due is based on if it's waiting on a READ */ if (ptr->typ == TQ_MUF_TYP && ptr->subtyp == TQ_MUF_READ) { strcpyn(duestr, sizeof(duestr), "--"); } else if (ptr->typ == TQ_MUF_TYP && ptr->subtyp == TQ_MUF_TIMER) { /* if it's a timer event, it gives the eventnum */ snprintf(pidstr, sizeof(pidstr), "(%d)", ptr->eventnum); } else if (ptr->typ == TQ_MPI_TYP) { /* and if it's MPI, undo most of the stuff we did * before, and set it up for mostly MPI stuff */ strcpyn(runstr, sizeof(runstr), "--"); strcpyn(inststr, sizeof(inststr), "MPI"); strcpyn(cpustr, sizeof(cpustr), "--"); } (void) snprintf(buf, sizeof(buf), strfmt, pidstr, duestr, runstr, inststr, cpustr, progstr, prognamestr, NAME(ptr->uid), (ptr->called_data? ptr->called_data : "")); if (Wizard(OWNER(player)) || ptr->uid == player) { notify_nolisten(player, buf, 1); } else if (ptr->called_prog != NOTHING && OWNER(ptr->called_prog) == OWNER(player)) { notify_nolisten(player, buf, 1); } ptr = ptr->next; count++; } count += muf_event_list(player, strfmt); snprintf(buf, sizeof(buf), "%d events.", count); notify_nolisten(player, buf, 1); }
void handle_read_event(int descr, dbref player, const char *command) { struct frame *fr; timequeue ptr, lastevent; int flag, typ, nothing_flag; int oldflags; dbref prog; nothing_flag = 0; if (command == NULL) { nothing_flag = 1; } oldflags = FLAGS(player); FLAGS(player) &= ~(INTERACTIVE | READMODE); ptr = tqhead; lastevent = NULL; while (ptr) { if (ptr->typ == TQ_MUF_TYP && (ptr->subtyp == TQ_MUF_READ || ptr->subtyp == TQ_MUF_TREAD) && ptr->uid == player) { break; } lastevent = ptr; ptr = ptr->next; } /* * When execution gets to here, either ptr will point to the * READ event for the player, or else ptr will be NULL. */ if (ptr) { /* remember our program, and our execution frame. */ fr = ptr->fr; if (fr == NULL) { log_status("WARNING: handle_read_event(): NULL frame ! Ignored."); return; } if (!fr->brkpt.debugging || fr->brkpt.isread) { if (!fr->wantsblanks && command && !*command) { FLAGS(player) = oldflags; return; } } typ = ptr->subtyp; prog = ptr->called_prog; if (command) { /* remove the READ timequeue node from the timequeue */ process_count--; if (lastevent) { lastevent->next = ptr->next; } else { tqhead = ptr->next; } } /* remember next timequeue node, to check for more READs later */ lastevent = ptr; ptr = ptr->next; /* Make SURE not to let the program frame get freed. We need it. */ lastevent->fr = NULL; if (command) { /* * Free up the READ timequeue node * we just removed from the queue. */ free_timenode(lastevent); } if (fr->brkpt.debugging && !fr->brkpt.isread) { /* We're in the MUF debugger! Call it with the input line. */ if (command) { if (muf_debugger(descr, player, prog, command, fr)) { /* MUF Debugger exited. Free up the program frame & exit */ prog_clean(fr); return; } } else { if (muf_debugger(descr, player, prog, "", fr)) { /* MUF Debugger exited. Free up the program frame & exit */ prog_clean(fr); return; } } } else { /* This is a MUF READ event. */ if (command && !string_compare(command, BREAK_COMMAND)) { /* Whoops! The user typed @Q. Free the frame and exit. */ prog_clean(fr); return; } if ((fr->argument.top >= STACK_SIZE) || (nothing_flag && fr->argument.top >= STACK_SIZE - 1)) { /* * Uh oh! That MUF program's stack is full! * Print an error, free the frame, and exit. */ notify_nolisten(player, "Program stack overflow.", 1); prog_clean(fr); return; } /* * Everything looks okay. Lets stuff the input line * on the program's argument stack as a string item. */ fr->argument.st[fr->argument.top].type = PROG_STRING; fr->argument.st[fr->argument.top++].data.string = alloc_prog_string(command ? command : ""); if (typ == TQ_MUF_TREAD) { if (nothing_flag) { fr->argument.st[fr->argument.top].type = PROG_INTEGER; fr->argument.st[fr->argument.top++].data.number = 0; } else { fr->argument.st[fr->argument.top].type = PROG_INTEGER; fr->argument.st[fr->argument.top++].data.number = 1; } } } /* * When using the MUF Debugger, the debugger will set the * INTERACTIVE bit on the user, if it does NOT want the MUF * program to resume executing. */ flag = (FLAGS(player) & INTERACTIVE); if (!flag && fr) { interp_loop(player, prog, fr, 0); /* WORK: if more input is pending, send the READ mufevent again. */ /* WORK: if no input is pending, clear READ mufevent from all of this player's programs. */ } /* * Check for any other READ events for this player. * If there are any, set the READ related flags. */ while (ptr) { if (ptr->typ == TQ_MUF_TYP && (ptr->subtyp == TQ_MUF_READ || ptr->subtyp == TQ_MUF_TREAD)) { if (ptr->uid == player) { FLAGS(player) |= (INTERACTIVE | READMODE); } } ptr = ptr->next; } } }
int add_event(int event_typ, int subtyp, int dtime, int descr, dbref player, dbref loc, dbref trig, dbref program, struct frame *fr, const char *strdata, const char *strcmd, const char *str3) { timequeue ptr = tqhead; timequeue lastevent = NULL; time_t rtime = time((time_t *) NULL) + (time_t) dtime; int mypids = 0; if (tqhead) { for (ptr = tqhead, mypids = 0; ptr; ptr = ptr->next) { if (ptr->uid == player) mypids++; lastevent = ptr; } } if (event_typ == TQ_MUF_TYP && subtyp == TQ_MUF_READ) { process_count++; if (lastevent) { lastevent->next = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig, program, fr, strdata, strcmd, str3, NULL); return (lastevent->next->eventnum); } else { tqhead = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig, program, fr, strdata, strcmd, str3, NULL); return (tqhead->eventnum); } } if (!(event_typ == TQ_MUF_TYP && subtyp == TQ_MUF_TREAD)) { if (process_count > tp_max_process_limit || (mypids > tp_max_plyr_processes && !Wizard(OWNER(player)))) { if (fr) { if (fr->multitask != BACKGROUND) PLAYER_SET_BLOCK(player, 0); prog_clean(fr); } notify_nolisten(player, "Event killed. Timequeue table full.", 1); return 0; } } process_count++; if (!tqhead) { tqhead = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig, program, fr, strdata, strcmd, str3, NULL); return (tqhead->eventnum); } if (rtime < tqhead->when || (tqhead->typ == TQ_MUF_TYP && tqhead->subtyp == TQ_MUF_READ) ) { tqhead = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig, program, fr, strdata, strcmd, str3, tqhead); return (tqhead->eventnum); } ptr = tqhead; while (ptr && ptr->next && rtime >= ptr->next->when && !(ptr->next->typ == TQ_MUF_TYP && ptr->next->subtyp == TQ_MUF_READ)) { ptr = ptr->next; } ptr->next = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig, program, fr, strdata, strcmd, str3, ptr->next); return (ptr->next->eventnum); }
void propqueue(int descr, dbref player, dbref where, dbref trigger, dbref what, dbref xclude, const char *propname, const char *toparg, int mlev, int mt) { const char *tmpchar; const char *pname; dbref the_prog; char buf[BUFFER_LEN]; char exbuf[BUFFER_LEN]; the_prog = NOTHING; tmpchar = NULL; /* queue up program referred to by the given property */ if (((the_prog = get_property_dbref(what, propname)) != NOTHING) || (tmpchar = get_property_class(what, propname))) { if ((tmpchar && *tmpchar) || the_prog != NOTHING) { if (tmpchar) { if (*tmpchar == '&') { the_prog = AMBIGUOUS; } else if (*tmpchar == NUMBER_TOKEN && number(tmpchar + 1)) { the_prog = (dbref) atoi(++tmpchar); } else if (*tmpchar == REGISTERED_TOKEN) { the_prog = find_registered_obj(what, tmpchar); } else if (number(tmpchar)) { the_prog = (dbref) atoi(tmpchar); } else { the_prog = NOTHING; } } else { if (the_prog == AMBIGUOUS) the_prog = NOTHING; } if (the_prog != AMBIGUOUS) { if (the_prog < 0 || the_prog >= db_top) { the_prog = NOTHING; } else if (Typeof(the_prog) != TYPE_PROGRAM) { the_prog = NOTHING; } else if ((OWNER(the_prog) != OWNER(player)) && !(FLAGS(the_prog) & LINK_OK)) { the_prog = NOTHING; } else if (MLevel(the_prog) < mlev) { the_prog = NOTHING; } else if (MLevel(OWNER(the_prog)) < mlev) { the_prog = NOTHING; } else if (the_prog == xclude) { the_prog = NOTHING; } } if (propq_level < 8) { propq_level++; if (the_prog == AMBIGUOUS) { char cbuf[BUFFER_LEN]; int ival; strcpyn(match_args, sizeof(match_args), ""); strcpyn(match_cmdname, sizeof(match_cmdname), toparg); ival = (mt == 0) ? MPI_ISPUBLIC : MPI_ISPRIVATE; if (Prop_Blessed(what, propname)) ival |= MPI_ISBLESSED; do_parse_mesg(descr, player, what, tmpchar + 1, "(MPIqueue)", cbuf, sizeof(cbuf), ival); if (*cbuf) { if (mt) { notify_filtered(player, player, cbuf, 1); } else { char bbuf[BUFFER_LEN]; dbref plyr; snprintf(bbuf, sizeof(bbuf), ">> %.4000s", pronoun_substitute(descr, player, cbuf)); plyr = DBFETCH(where)->contents; while (plyr != NOTHING) { if (Typeof(plyr) == TYPE_PLAYER && plyr != player) notify_filtered(player, plyr, bbuf, 0); plyr = DBFETCH(plyr)->next; } } } } else if (the_prog != NOTHING) { struct frame *tmpfr; strcpyn(match_args, sizeof(match_args), toparg ? toparg : ""); strcpyn(match_cmdname, sizeof(match_cmdname), "Queued event."); tmpfr = interp(descr, player, where, the_prog, trigger, BACKGROUND, STD_HARDUID, 0); if (tmpfr) { interp_loop(player, the_prog, tmpfr, 0); } } propq_level--; } else { notify_nolisten(player, "Propqueue stopped to prevent infinite loop.", 1); } } } strcpyn(buf, sizeof(buf), propname); if (is_propdir(what, buf)) { strcatn(buf, sizeof(buf), "/"); while ((pname = next_prop_name(what, exbuf, sizeof(exbuf), buf))) { strcpyn(buf, sizeof(buf), pname); propqueue(descr, player, where, trigger, what, xclude, buf, toparg, mlev, mt); } } }
void do_dequeue(int descr, dbref player, const char *arg1) { char buf[BUFFER_LEN]; int count; dbref match; struct match_data md; timequeue tmp, ptr = tqhead; if (*arg1 == '\0') { notify_nolisten(player, "What event do you want to dequeue?", 1); } else { if (!string_compare(arg1, "all")) { if (!Wizard(OWNER(player))) { notify_nolisten(player, "Permission denied", 1); return; } while (ptr) { tmp = ptr; tqhead = ptr = ptr->next; free_timenode(tmp); process_count--; } tqhead = NULL; muf_event_dequeue(NOTHING, 0); notify_nolisten(player, "Time queue cleared.", 1); } else { if (!number(arg1)) { init_match(descr, player, arg1, NOTYPE, &md); match_absolute(&md); match_everything(&md); match = noisy_match_result(&md); if (match == NOTHING) { notify_nolisten(player, "I don't know what you want to dequeue!", 1); return; } if (!valid_objref(match)) { notify_nolisten(player, "I don't recognize that object.", 1); return; } if ((!Wizard(OWNER(player))) && (OWNER(match) != OWNER(player))) { notify_nolisten(player, "Permission denied.", 1); return; } count = dequeue_prog(match, 0); if (!count) { notify_nolisten(player, "That program wasn't in the time queue.", 1); return; } if (count > 1) { snprintf(buf, sizeof(buf), "%d processes dequeued.", count); } else { snprintf(buf, sizeof(buf), "Process dequeued."); } notify_nolisten(player, buf, 1); } else { if ((count = atoi(arg1))) { if (!(control_process(player, count))) { notify_nolisten(player, "Permission denied.", 1); return; } if (!(dequeue_process(count))) { notify_nolisten(player, "No such process!", 1); return; } process_count--; notify_nolisten(player, "Process dequeued.", 1); } else { notify_nolisten(player, "What process do you want to dequeue?", 1); } } } } return; }