int muf_debugger(dbref player, dbref program, const char *text, struct frame *fr) { char cmd[BUFFER_LEN]; char buf[BUFFER_LEN]; char *ptr, *ptr2, *arg; struct inst *pinst; 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(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(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(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(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(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(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(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(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(player, program, fr); return 0; } if (!(i = primitive(arg))) { anotify_nolisten(player, CINFO "I don't recognize that primitive.", 1); add_muf_read_event(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(player, program, fr); return 0; } shstr.data[0] = '\0'; shstr.links = 1; shstr.length= strlen(shstr.data); primset[0].type = PROG_FUNCTION; primset[0].line = 0; primset[0].data.string = &shstr; primset[1].type = PROG_PRIMITIVE; primset[1].line = 0; primset[1].data.number = i; primset[2].type = PROG_PRIMITIVE; primset[2].line = 0; primset[2].data.number = primitive("EXIT"); fr->system.st[fr->system.top].progref = program; fr->system.st[fr->system.top++].offset = fr->pc; fr->pc = primset; 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, "break")) { add_muf_read_event(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(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(player, program, fr); return 0; } else if (!string_compare(cmd, "where")) { i = atoi(arg); muf_backtrace(player, program, i, fr); add_muf_read_event(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 = ""; for (j = fr->argument.top; j>0 && i-->0;) { cnt = 0; do { strcpy(buf, ptr); ptr = insttotext(&fr->argument.st[--j], 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(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(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(program, fr->pc, STACK_SIZE, 1) : show_line_prims(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(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(player, program, fr); return 0; } else if (!string_compare(cmd, "print")) { debug_printvar(player, fr, arg); add_muf_read_event(player, program, fr); return 0; } else if (!string_compare(cmd, "push")) { push_arg(player, fr, arg); add_muf_read_event(player, program, fr); return 0; } else if (!string_compare(cmd, "pop")) { add_muf_read_event(player, program, fr); if (fr->argument.top < 1) { anotify_nolisten(player, CFAIL "Nothing to pop.", 1); return 0; } fr->argument.top--; CLEAR(fr->argument.st + fr->argument.top); anotify_nolisten(player, CSUCC "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(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(player, program, fr); return 0; } return 0; }
/** * Implementation of the MUF debugger * * This implements the command parsing for the MUF debugger. It also clears * temporary bookmarks if this was triggered from a temporary one. * * This relies on some static globals, so it is not threadsafe. If the * 'prim' debugger command is ever used to trigger the MUF debugger somehow * in a recursive fashion, and then you call 'prim' again, it will probably * cause havock. * * @param descr the descriptor of the debugging player * @param player the debugging player * @param program the program we are debugging * @param text the input text from the user * @param fr the current frame pointer * @return boolean true if the program should exit, false if not */ 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; int i, j, cnt; static struct inst primset[5]; static struct muf_proc_data temp_muf_proc_data = { "__Temp_Debugger_Proc", 0, 0, NULL }; /* * Basic massaging of the input - clearing spaces, finding the * argument. */ skip_whitespace(&text); strcpyn(cmd, sizeof(cmd), text); ptr = cmd; remove_ending_whitespace(&ptr); for (arg = cmd; *arg && !isspace(*arg); arg++) ; if (*arg) *arg++ = '\0'; /* Empty command means repeat last command, if available */ if (!*cmd && fr->brkpt.lastcmd) { strcpyn(cmd, sizeof(cmd), fr->brkpt.lastcmd); } else { free(fr->brkpt.lastcmd); if (*cmd) fr->brkpt.lastcmd = strdup(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; /** * @TODO This giant if statement is pretty gnarly; we'd be better * of looping over an array of callbacks to break this up * nicer and make it more extensible. */ if (!strcasecmp(cmd, "cont")) { /* Nothing to do -- this will continue to next breakpoint */ } else if (!strcasecmp(cmd, "finish")) { if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "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 (!strcasecmp(cmd, "stepi")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "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 (!strcasecmp(cmd, "step")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "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 (!strcasecmp(cmd, "nexti")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "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 (!strcasecmp(cmd, "next")) { i = atoi(arg); if (!i) i = 1; if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "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 (!strcasecmp(cmd, "exec")) { if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "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))) { notify_nolisten(player, "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) { notify_nolisten(player, "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 (!strcasecmp(cmd, "prim")) { /* * @TODO The way this works is a little funky. It looks like * it would be possible to cause some weird havoc if we * manage to run a primitive that in turn triggers muf_debugger * * I am uncertain if this is possible; looks like the only * way it could happen is by typing 'prim debugger_break' * but I don't know much about about how muf_debugger is * triggered. Some digging should be done to make this * safe. * * Even better would be to not use statics for this somehow * without introducing a memory leak. (tanabi) */ if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Cannot finish because there are too many breakpoints set.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (!primitive(arg)) { notify_nolisten(player, "I don't recognize that primitive.", 1); add_muf_read_event(descr, player, program, fr); return 0; } if (fr->system.top >= STACK_SIZE) { notify_nolisten(player, "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 (!strcasecmp(cmd, "break")) { add_muf_read_event(descr, player, program, fr); if (fr->brkpt.count >= MAX_BREAKS) { notify_nolisten(player, "Too many breakpoints set.", 1); return 0; } if (number(arg)) { i = atoi(arg); } else { if (!(pinst = funcname_to_pc(program, arg))) { notify_nolisten(player, "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; notify_nolisten(player, "Breakpoint set.", 1); return 0; } else if (!strcasecmp(cmd, "delete")) { add_muf_read_event(descr, player, program, fr); i = atoi(arg); if (!i) { notify_nolisten(player, "Which breakpoint did you want to delete?", 1); return 0; } if (i < 1 || i > fr->brkpt.count) { notify_nolisten(player, "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--; notify_nolisten(player, "Breakpoint deleted.", 1); return 0; } else if (!strcasecmp(cmd, "breaks")) { notify_nolisten(player, "Breakpoints:", 1); for (i = 0; i < fr->brkpt.count; i++) { ptr = unparse_breakpoint(fr, i); notify_nolisten(player, ptr, 1); } notify_nolisten(player, "*done*", 1); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "where")) { i = atoi(arg); muf_backtrace(player, program, i, fr); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "stack")) { notify_nolisten(player, "*Argument stack top*", 1); i = atoi(arg); if (!i) i = STACK_SIZE; ptr = ""; for (j = fr->argument.top; j > 0 && i-- > 0;) { cnt = 0; do { strcpyn(buf, sizeof(buf), ptr); ptr = insttotext(NULL, 0, &fr->argument.st[--j], buf2, sizeof(buf2), 4000, program, 1); cnt++; } while (!strcasecmp(ptr, buf) && j > 0); if (cnt > 1) notifyf(player, " [repeats %d times]", cnt); if (strcasecmp(ptr, buf)) notifyf(player, "%3d) %s", j + 1, ptr); } notify_nolisten(player, "*done*", 1); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "list") || !strcasecmp(cmd, "listi")) { int startline, endline; add_muf_read_event(descr, player, program, fr); if ((ptr2 = (char *) strchr(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))) { notify_nolisten(player, "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))) { notify_nolisten(player, "I don't know a function by that name. (ending arg, 1)", 1); return 0; } else { endline = pinst->line; } } else { endline = atoi(ptr2); } } i = (PROGRAM_CODE(program) + PROGRAM_SIZ(program) - 1)->line; if (startline > i) { notify_nolisten(player, "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; notify_nolisten(player, "Listing:", 1); if (!strcasecmp(cmd, "listi")) { for (i = startline; i <= endline; i++) { pinst = linenum_to_pc(program, i); if (pinst) { notifyf_nolisten(player, "line %d: %s", i, (i == fr->pc->line) ? show_line_prims(program, fr->pc, STACK_SIZE, 1) : show_line_prims(program, pinst, STACK_SIZE, 0)); } } } else { list_proglines(player, program, fr, startline, endline); } fr->brkpt.lastlisted = endline; notify_nolisten(player, "*done*", 1); return 0; } else if (!strcasecmp(cmd, "quit")) { notify_nolisten(player, "Halting execution.", 1); return 1; } else if (!strcasecmp(cmd, "trace")) { add_muf_read_event(descr, player, program, fr); if (!strcasecmp(arg, "on")) { fr->brkpt.showstack = 1; notify_nolisten(player, "Trace turned on.", 1); } else if (!strcasecmp(arg, "off")) { fr->brkpt.showstack = 0; notify_nolisten(player, "Trace turned off.", 1); } else { notifyf_nolisten(player, "Trace is currently %s.", fr->brkpt.showstack ? "on" : "off"); } return 0; } else if (!strcasecmp(cmd, "words")) { list_program_functions(player, program, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "print")) { debug_printvar(player, program, fr, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(cmd, "push")) { push_arg(player, fr, arg); add_muf_read_event(descr, player, program, fr); return 0; } else if (!strcasecmp(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 (!strcasecmp(cmd, "help")) { do_helpfile(player, tp_file_man_dir, tp_file_man, "debugger_commands", ""); return 0; } else { notify_nolisten(player, "I don't understand that debugger command. Type 'help' for help.", 1); add_muf_read_event(descr, player, program, fr); return 0; } return 0; }