15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2001 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/debugger.c,v 1.24tsi Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include <ctype.h>
335dfecf96Smrg#include "lisp/io.h"
345dfecf96Smrg#include "lisp/debugger.h"
355dfecf96Smrg#include "lisp/write.h"
365dfecf96Smrg
375dfecf96Smrg#ifdef DEBUGGER
385dfecf96Smrg#define DebuggerHelp		0
395dfecf96Smrg#define DebuggerAbort		1
405dfecf96Smrg#define DebuggerBacktrace	2
415dfecf96Smrg#define DebuggerContinue	3
425dfecf96Smrg#define DebuggerFinish		4
435dfecf96Smrg#define DebuggerFrame		5
445dfecf96Smrg#define DebuggerNext		6
455dfecf96Smrg#define DebuggerPrint		7
465dfecf96Smrg#define DebuggerStep		8
475dfecf96Smrg#define DebuggerBreak		9
485dfecf96Smrg#define DebuggerDelete		10
495dfecf96Smrg#define DebuggerDown		11
505dfecf96Smrg#define DebuggerUp		12
515dfecf96Smrg#define DebuggerInfo		13
525dfecf96Smrg#define DebuggerWatch		14
535dfecf96Smrg
545dfecf96Smrg#define DebuggerInfoBreakpoints	0
555dfecf96Smrg#define DebuggerInfoBacktrace	1
565dfecf96Smrg
575dfecf96Smrg/*
585dfecf96Smrg * Prototypes
595dfecf96Smrg */
605dfecf96Smrgstatic char *format_integer(int);
615dfecf96Smrgstatic void LispDebuggerCommand(LispObj *obj);
625dfecf96Smrg
635dfecf96Smrg/*
645dfecf96Smrg * Initialization
655dfecf96Smrg */
665dfecf96Smrgstatic struct {
67f765521fSmrg    const char *name;
685dfecf96Smrg    int action;
69f765521fSmrg} const commands[] = {
705dfecf96Smrg    {"help",		DebuggerHelp},
715dfecf96Smrg    {"abort",		DebuggerAbort},
725dfecf96Smrg    {"backtrace",	DebuggerBacktrace},
735dfecf96Smrg    {"b",		DebuggerBreak},
745dfecf96Smrg    {"break",		DebuggerBreak},
755dfecf96Smrg    {"bt",		DebuggerBacktrace},
765dfecf96Smrg    {"continue",	DebuggerContinue},
775dfecf96Smrg    {"d",		DebuggerDelete},
785dfecf96Smrg    {"delete",		DebuggerDelete},
795dfecf96Smrg    {"down",		DebuggerDown},
805dfecf96Smrg    {"finish",		DebuggerFinish},
815dfecf96Smrg    {"frame",		DebuggerFrame},
825dfecf96Smrg    {"info",		DebuggerInfo},
835dfecf96Smrg    {"n",		DebuggerNext},
845dfecf96Smrg    {"next",		DebuggerNext},
855dfecf96Smrg    {"print",		DebuggerPrint},
865dfecf96Smrg    {"run",		DebuggerContinue},
875dfecf96Smrg    {"s",		DebuggerStep},
885dfecf96Smrg    {"step",		DebuggerStep},
895dfecf96Smrg    {"up",		DebuggerUp},
905dfecf96Smrg    {"watch",		DebuggerWatch},
915dfecf96Smrg};
925dfecf96Smrg
935dfecf96Smrgstatic struct {
94f765521fSmrg    const char *name;
955dfecf96Smrg    int subaction;
96f765521fSmrg} const info_commands[] = {
975dfecf96Smrg    {"breakpoints",	DebuggerInfoBreakpoints},
985dfecf96Smrg    {"stack",		DebuggerInfoBacktrace},
995dfecf96Smrg    {"watchpoints",	DebuggerInfoBreakpoints},
1005dfecf96Smrg};
1015dfecf96Smrg
102f765521fSmrgstatic const char *debugger_help =
1035dfecf96Smrg"Available commands are:\n\
1045dfecf96Smrg\n\
1055dfecf96Smrghelp		- This message.\n\
1065dfecf96Smrgabort		- Abort the current execution, and return to toplevel.\n\
1075dfecf96Smrgbacktrace, bt	- Print backtrace.\n\
1085dfecf96Smrgb, break	- Set breakpoint at function name argument.\n\
1095dfecf96Smrgcontinue	- Continue execution.\n\
1105dfecf96Smrgd, delete	- Delete breakpoint(s), all breakpoint if no arguments given.\n\
1115dfecf96Smrgdown		- Set environment to frame called by the current one.\n\
1125dfecf96Smrgfinish		- Executes until current form is finished.\n\
1135dfecf96Smrgframe		- Set environment to selected frame.\n\
1145dfecf96Smrginfo		- Prints information about the debugger state.\n\
1155dfecf96Smrgn, next		- Evaluate next form.\n\
1165dfecf96Smrgprint		- Print value of variable name argument.\n\
1175dfecf96Smrgrun		- Continue execution.\n\
1185dfecf96Smrgs, step		- Evaluate next form, stopping on any subforms.\n\
1195dfecf96Smrgup		- Set environment to frame that called the current one.\n\
1205dfecf96Smrg\n\
1215dfecf96SmrgCommands may be abbreviated.\n";
1225dfecf96Smrg
123f765521fSmrgstatic const char *debugger_info_help =
1245dfecf96Smrg"Available subcommands are:\n\
1255dfecf96Smrg\n\
1265dfecf96Smrgbreakpoints	- List and prints status of breakpoints, and watchpoints.\n\
1275dfecf96Smrgstack		- Backtrace of stack.\n\
1285dfecf96Smrgwatchpoints	- List and prints status of watchpoints, and breakpoints.\n\
1295dfecf96Smrg\n\
1305dfecf96SmrgSubcommands may be abbreviated.\n";
1315dfecf96Smrg
1325dfecf96Smrg/* Debugger variables layout (if you change it, update description):
1335dfecf96Smrg *
1345dfecf96Smrg * DBG
1355dfecf96Smrg *	is a macro for lisp__data.dbglist
1365dfecf96Smrg *	is a NIL terminated list
1375dfecf96Smrg *	every element is a list in the format (NOT NIL terminated):
1385dfecf96Smrg *	(list* NAM ARG ENV HED LEX)
1395dfecf96Smrg *	where
1405dfecf96Smrg *		NAM is an ATOM for the function/macro name
1415dfecf96Smrg *		    or NIL for lambda expressions
1425dfecf96Smrg *		ARG is NAM arguments (a LIST)
1435dfecf96Smrg *		ENV is the value of lisp__data.stack.base (a FIXNUM)
1445dfecf96Smrg *		LEN is the value of lisp__data.env.length (a FIXNUM)
1455dfecf96Smrg *		LEX is the value of lisp__data.env.lex (a FIXNUM)
1465dfecf96Smrg *	new elements are added to the beggining of the DBG list
1475dfecf96Smrg *
1485dfecf96Smrg * BRK
1495dfecf96Smrg *	is macro for lisp__data.brklist
1505dfecf96Smrg *	is a NIL terminated list
1515dfecf96Smrg *	every element is a list in the format (NIL terminated):
1525dfecf96Smrg *	(list NAM IDX TYP HIT VAR VAL FRM)
1535dfecf96Smrg *	where
1545dfecf96Smrg *		NAM is an ATOM for the name of the object at
1555dfecf96Smrg *		    wich the breakpoint was added
1565dfecf96Smrg *		IDX is a FIXNUM, the breakpoint number
1575dfecf96Smrg *		    must be stored, as breakpoints may be deleted
1585dfecf96Smrg *		TYP is a FIXNUM that must be an integer of enum LispBreakType
1595dfecf96Smrg *		HIT is a FIXNUM, with the number of times this breakpoint was
1605dfecf96Smrg *		    hitted.
1615dfecf96Smrg *		VAR variable to watch a SYMBOL	(not needed for breakpoints)
1625dfecf96Smrg *		VAL value of watched variable	(not needed for breakpoints)
1635dfecf96Smrg *		FRM frame where variable started being watched
1645dfecf96Smrg *						(not needed for breakpoints)
1655dfecf96Smrg *	new elements are added to the end of the list
1665dfecf96Smrg */
1675dfecf96Smrg
1685dfecf96Smrg/*
1695dfecf96Smrg * Implementation
1705dfecf96Smrg */
1715dfecf96Smrgvoid
1725dfecf96SmrgLispDebugger(LispDebugCall call, LispObj *name, LispObj *arg)
1735dfecf96Smrg{
1745dfecf96Smrg    int force = 0;
1755dfecf96Smrg    LispObj *obj, *prev;
1765dfecf96Smrg
1775dfecf96Smrg    switch (call) {
1785dfecf96Smrg	case LispDebugCallBegin:
1795dfecf96Smrg	    ++lisp__data.debug_level;
1805dfecf96Smrg	    GCDisable();
1815dfecf96Smrg	    DBG = CONS(CONS(name, CONS(arg, CONS(FIXNUM(lisp__data.stack.base),
1825dfecf96Smrg		       CONS(FIXNUM(lisp__data.env.length),
1835dfecf96Smrg			    FIXNUM(lisp__data.env.lex))))), DBG);
1845dfecf96Smrg	    GCEnable();
1855dfecf96Smrg	    for (obj = BRK; obj != NIL; obj = CDR(obj))
1865dfecf96Smrg		if (ATOMID(CAR(CAR(obj))) == ATOMID(name) &&
1875dfecf96Smrg		    FIXNUM_VALUE(CAR(CDR(CDR(CAR(obj))))) ==
1885dfecf96Smrg		    LispDebugBreakFunction)
1895dfecf96Smrg		    break;
1905dfecf96Smrg	    if (obj != NIL) {
1915dfecf96Smrg		long counter;
1925dfecf96Smrg
1935dfecf96Smrg		/* if not at a fresh line */
1945dfecf96Smrg		if (LispGetColumn(NIL))
1955dfecf96Smrg		    LispFputc(Stdout, '\n');
1965dfecf96Smrg		LispFputs(Stdout, "BREAK #");
1975dfecf96Smrg		LispWriteObject(NIL, CAR(CDR(CAR(obj))));
1985dfecf96Smrg		LispFputs(Stdout, "> (");
1995dfecf96Smrg		LispWriteObject(NIL, CAR(CAR(DBG)));
2005dfecf96Smrg		LispFputc(Stdout, ' ');
2015dfecf96Smrg		LispWriteObject(NIL, CAR(CDR(CAR(DBG))));
2025dfecf96Smrg		LispFputs(Stdout, ")\n");
2035dfecf96Smrg		force = 1;
2045dfecf96Smrg		/* update hits counter */
2055dfecf96Smrg		counter = FIXNUM_VALUE(CAR(CDR(CDR(CDR(CAR(obj))))));
2065dfecf96Smrg		CAR(CDR(CDR(CDR(CAR(obj))))) FIXNUM(counter + 1);
2075dfecf96Smrg	    }
2085dfecf96Smrg	    break;
2095dfecf96Smrg	case LispDebugCallEnd:
2105dfecf96Smrg	    DBG = CDR(DBG);
2115dfecf96Smrg	    if (lisp__data.debug_level < lisp__data.debug_step)
2125dfecf96Smrg		lisp__data.debug_step = lisp__data.debug_level;
2135dfecf96Smrg	    --lisp__data.debug_level;
2145dfecf96Smrg	    break;
2155dfecf96Smrg	case LispDebugCallFatal:
2165dfecf96Smrg	    LispDebuggerCommand(NIL);
2175dfecf96Smrg	    return;
2185dfecf96Smrg	case LispDebugCallWatch:
2195dfecf96Smrg	    break;
2205dfecf96Smrg    }
2215dfecf96Smrg
2225dfecf96Smrg    /* didn't return, check watchpoints */
2235dfecf96Smrg    if (call == LispDebugCallEnd || call == LispDebugCallWatch) {
2245dfecf96Smrgwatch_again:
2255dfecf96Smrg	for (prev = obj = BRK; obj != NIL; prev = obj, obj = CDR(obj)) {
2265dfecf96Smrg	    if (FIXNUM_VALUE(CAR(CDR(CDR(CAR(obj))))) ==
2275dfecf96Smrg		LispDebugBreakVariable) {
2285dfecf96Smrg		/* the variable */
2295dfecf96Smrg		LispObj *wat = CAR(CDR(CDR(CDR(CDR(CAR(obj))))));
2305dfecf96Smrg		void *sym = LispGetVarAddr(CAAR(obj));
2315dfecf96Smrg		LispObj *frm = CAR(CDR(CDR(CDR(CDR(CDR(CDR(CAR(obj))))))));
2325dfecf96Smrg
2335dfecf96Smrg		if ((sym == NULL && lisp__data.debug_level <= 0) ||
2345dfecf96Smrg		    (sym != wat->data.opaque.data &&
2355dfecf96Smrg		     FIXNUM_VALUE(frm) > lisp__data.debug_level)) {
2365dfecf96Smrg		    LispFputs(Stdout, "WATCH #");
2375dfecf96Smrg		    LispFputs(Stdout, format_integer(FIXNUM_VALUE(CAR(CDR(CAR(obj))))));
2385dfecf96Smrg		    LispFputs(Stdout, "> ");
2395dfecf96Smrg		    LispFputs(Stdout, STRPTR(CAR(CAR(obj))));
2405dfecf96Smrg		    LispFputs(Stdout, " deleted. Variable does not exist anymore.\n");
2415dfecf96Smrg		    /* force debugger to stop */
2425dfecf96Smrg		    force = 1;
2435dfecf96Smrg		    if (obj == prev) {
2445dfecf96Smrg			BRK = CDR(BRK);
2455dfecf96Smrg			goto watch_again;
2465dfecf96Smrg		    }
2475dfecf96Smrg		    else
2485dfecf96Smrg			RPLACD(prev, CDR(obj));
2495dfecf96Smrg		    obj = prev;
2505dfecf96Smrg		}
2515dfecf96Smrg		else {
2525dfecf96Smrg		    /* current value */
2535dfecf96Smrg		    LispObj *cur = *(LispObj**)wat->data.opaque.data;
2545dfecf96Smrg		    /* last value */
2555dfecf96Smrg		    LispObj *val = CAR(CDR(CDR(CDR(CDR(CDR(CAR(obj)))))));
2565dfecf96Smrg		    if (XEQUAL(val, cur) == NIL) {
2575dfecf96Smrg			long counter;
2585dfecf96Smrg
2595dfecf96Smrg			LispFputs(Stdout, "WATCH #");
2605dfecf96Smrg			LispFputs(Stdout, format_integer(FIXNUM_VALUE(CAR(CDR(CAR(obj))))));
2615dfecf96Smrg			LispFputs(Stdout, "> ");
2625dfecf96Smrg			LispFputs(Stdout, STRPTR(CAR(CAR(obj))));
2635dfecf96Smrg			LispFputc(Stdout, '\n');
2645dfecf96Smrg
2655dfecf96Smrg			LispFputs(Stdout, "OLD: ");
2665dfecf96Smrg			LispWriteObject(NIL, val);
2675dfecf96Smrg
2685dfecf96Smrg			LispFputs(Stdout, "\nNEW: ");
2695dfecf96Smrg			LispWriteObject(NIL, cur);
2705dfecf96Smrg			LispFputc(Stdout, '\n');
2715dfecf96Smrg
2725dfecf96Smrg			/* update current value */
2735dfecf96Smrg			CAR(CDR(CDR(CDR(CDR(CDR(CAR(obj))))))) = cur;
2745dfecf96Smrg			/* update hits counter */
2755dfecf96Smrg			counter = FIXNUM_VALUE(CAR(CDR(CDR(CDR(CAR(obj))))));
2765dfecf96Smrg			CAR(CDR(CDR(CDR(CAR(obj))))) = FIXNUM(counter + 1);
2775dfecf96Smrg			/* force debugger to stop */
2785dfecf96Smrg			force = 1;
2795dfecf96Smrg		    }
2805dfecf96Smrg		}
2815dfecf96Smrg	    }
2825dfecf96Smrg	}
2835dfecf96Smrg
2845dfecf96Smrg	if (call == LispDebugCallWatch)
2855dfecf96Smrg	    /* special call, just don't keep gc protected variables that may be
2865dfecf96Smrg	     * using a lot of memory... */
2875dfecf96Smrg	    return;
2885dfecf96Smrg    }
2895dfecf96Smrg
2905dfecf96Smrg    switch (lisp__data.debug) {
2915dfecf96Smrg	case LispDebugUnspec:
2925dfecf96Smrg	    LispDebuggerCommand(NIL);
2935dfecf96Smrg	    goto debugger_done;
2945dfecf96Smrg	case LispDebugRun:
2955dfecf96Smrg	    if (force)
2965dfecf96Smrg		LispDebuggerCommand(NIL);
2975dfecf96Smrg	    goto debugger_done;
2985dfecf96Smrg	case LispDebugFinish:
2995dfecf96Smrg	    if (!force &&
3005dfecf96Smrg		(call != LispDebugCallEnd ||
3015dfecf96Smrg		 lisp__data.debug_level != lisp__data.debug_step))
3025dfecf96Smrg		goto debugger_done;
3035dfecf96Smrg	    break;
3045dfecf96Smrg	case LispDebugNext:
3055dfecf96Smrg	    if (call == LispDebugCallBegin) {
3065dfecf96Smrg		if (!force && lisp__data.debug_level != lisp__data.debug_step)
3075dfecf96Smrg		    goto debugger_done;
3085dfecf96Smrg	    }
3095dfecf96Smrg	    else if (call == LispDebugCallEnd) {
3105dfecf96Smrg		if (!force && lisp__data.debug_level >= lisp__data.debug_step)
3115dfecf96Smrg		    goto debugger_done;
3125dfecf96Smrg	    }
3135dfecf96Smrg	    break;
3145dfecf96Smrg	case LispDebugStep:
3155dfecf96Smrg	    break;
3165dfecf96Smrg    }
3175dfecf96Smrg
3185dfecf96Smrg    if (call == LispDebugCallBegin) {
3195dfecf96Smrg	LispFputc(Stdout, '#');
3205dfecf96Smrg	LispFputs(Stdout, format_integer(lisp__data.debug_level));
3215dfecf96Smrg	LispFputs(Stdout, "> (");
3225dfecf96Smrg	LispWriteObject(NIL, CAR(CAR(DBG)));
3235dfecf96Smrg	LispFputc(Stdout, ' ');
3245dfecf96Smrg	LispWriteObject(NIL, CAR(CDR(CAR(DBG))));
3255dfecf96Smrg	LispFputs(Stdout, ")\n");
3265dfecf96Smrg	LispDebuggerCommand(NIL);
3275dfecf96Smrg    }
3285dfecf96Smrg    else if (call == LispDebugCallEnd) {
3295dfecf96Smrg	LispFputc(Stdout, '#');
3305dfecf96Smrg	LispFputs(Stdout, format_integer(lisp__data.debug_level + 1));
3315dfecf96Smrg	LispFputs(Stdout, "= ");
3325dfecf96Smrg	LispWriteObject(NIL, arg);
3335dfecf96Smrg	LispFputc(Stdout, '\n');
3345dfecf96Smrg	LispDebuggerCommand(NIL);
3355dfecf96Smrg    }
3365dfecf96Smrg    else if (force)
3375dfecf96Smrg	LispDebuggerCommand(arg);
3385dfecf96Smrg
3395dfecf96Smrgdebugger_done:
3405dfecf96Smrg    return;
3415dfecf96Smrg}
3425dfecf96Smrg
3435dfecf96Smrgstatic void
3445dfecf96SmrgLispDebuggerCommand(LispObj *args)
3455dfecf96Smrg{
3465dfecf96Smrg    LispObj *obj, *frm, *curframe;
3475dfecf96Smrg    int i = 0, frame, matches, action = -1, subaction = 0;
3485dfecf96Smrg    char *cmd, *arg, *ptr, line[256];
3495dfecf96Smrg
3505dfecf96Smrg    int envbase = lisp__data.stack.base,
3515dfecf96Smrg	envlen = lisp__data.env.length,
3525dfecf96Smrg	envlex = lisp__data.env.lex;
3535dfecf96Smrg
3545dfecf96Smrg    frame = lisp__data.debug_level;
3555dfecf96Smrg    curframe = CAR(DBG);
3565dfecf96Smrg
3575dfecf96Smrg    line[0] = '\0';
3585dfecf96Smrg    arg = line;
3595dfecf96Smrg    for (;;) {
3605dfecf96Smrg	LispFputs(Stdout, DBGPROMPT);
3615dfecf96Smrg	LispFflush(Stdout);
3625dfecf96Smrg	if (LispFgets(Stdin, line, sizeof(line)) == NULL) {
3635dfecf96Smrg	    LispFputc(Stdout, '\n');
3645dfecf96Smrg	    return;
3655dfecf96Smrg	}
3665dfecf96Smrg	/* get command */
3675dfecf96Smrg	ptr = line;
3685dfecf96Smrg	while (*ptr && isspace(*ptr))
3695dfecf96Smrg	    ++ptr;
3705dfecf96Smrg	cmd = ptr;
3715dfecf96Smrg	while (*ptr && !isspace(*ptr))
3725dfecf96Smrg	    ++ptr;
3735dfecf96Smrg	if (*ptr)
3745dfecf96Smrg	    *ptr++ = '\0';
3755dfecf96Smrg
3765dfecf96Smrg	if (*cmd) {	/* if *cmd is nul, then arg may be still set */
3775dfecf96Smrg	    /* get argument(s) */
3785dfecf96Smrg	    while (*ptr && isspace(*ptr))
3795dfecf96Smrg		++ptr;
3805dfecf96Smrg	    arg = ptr;
3815dfecf96Smrg	    /* goto end of line */
3825dfecf96Smrg	    if (*ptr) {
3835dfecf96Smrg		while (*ptr)
3845dfecf96Smrg		    ++ptr;
3855dfecf96Smrg		--ptr;
3865dfecf96Smrg		while (*ptr && isspace(*ptr))
3875dfecf96Smrg		    --ptr;
3885dfecf96Smrg		if (*ptr)
3895dfecf96Smrg		    *++ptr = '\0';
3905dfecf96Smrg	    }
3915dfecf96Smrg	}
3925dfecf96Smrg
3935dfecf96Smrg	if (*cmd == '\0') {
3945dfecf96Smrg	    if (action < 0) {
3955dfecf96Smrg		if (lisp__data.debug == LispDebugFinish)
3965dfecf96Smrg		    action = DebuggerFinish;
3975dfecf96Smrg		else if (lisp__data.debug == LispDebugNext)
3985dfecf96Smrg		    action = DebuggerNext;
3995dfecf96Smrg		else if (lisp__data.debug == LispDebugStep)
4005dfecf96Smrg		    action = DebuggerStep;
4015dfecf96Smrg		else if (lisp__data.debug == LispDebugRun)
4025dfecf96Smrg		    action = DebuggerContinue;
4035dfecf96Smrg		else
4045dfecf96Smrg		    continue;
4055dfecf96Smrg	    }
4065dfecf96Smrg	}
4075dfecf96Smrg	else {
4085dfecf96Smrg	    for (i = matches = 0; i < sizeof(commands) / sizeof(commands[0]);
4095dfecf96Smrg		 i++) {
410f765521fSmrg		const char *str = commands[i].name;
4115dfecf96Smrg
4125dfecf96Smrg		ptr = cmd;
4135dfecf96Smrg		while (*ptr && *ptr == *str) {
4145dfecf96Smrg		    ++ptr;
4155dfecf96Smrg		    ++str;
4165dfecf96Smrg		}
4175dfecf96Smrg		if (*ptr == '\0') {
4185dfecf96Smrg		    action = commands[i].action;
4195dfecf96Smrg		    if (*str == '\0') {
4205dfecf96Smrg			matches = 1;
4215dfecf96Smrg			break;
4225dfecf96Smrg		    }
4235dfecf96Smrg		    ++matches;
4245dfecf96Smrg		}
4255dfecf96Smrg	    }
4265dfecf96Smrg	    if (matches == 0) {
4275dfecf96Smrg		LispFputs(Stdout, "* Command unknown: ");
4285dfecf96Smrg		LispFputs(Stdout, cmd);
4295dfecf96Smrg		LispFputs(Stdout, ". Type help for help.\n");
4305dfecf96Smrg		continue;
4315dfecf96Smrg	    }
4325dfecf96Smrg	    else if (matches > 1) {
4335dfecf96Smrg		LispFputs(Stdout, "* Command is ambiguous: ");
4345dfecf96Smrg		LispFputs(Stdout, cmd);
4355dfecf96Smrg		LispFputs(Stdout, ". Type help for help.\n");
4365dfecf96Smrg		continue;
4375dfecf96Smrg	    }
4385dfecf96Smrg	}
4395dfecf96Smrg
4405dfecf96Smrg	switch (action) {
4415dfecf96Smrg	    case DebuggerHelp:
4425dfecf96Smrg		LispFputs(Stdout, debugger_help);
4435dfecf96Smrg		break;
4445dfecf96Smrg	    case DebuggerInfo:
4455dfecf96Smrg		if (*arg == '\0') {
4465dfecf96Smrg		    LispFputs(Stdout, debugger_info_help);
4475dfecf96Smrg		    break;
4485dfecf96Smrg		}
4495dfecf96Smrg
4505dfecf96Smrg		for (i = matches = 0;
4515dfecf96Smrg		     i < sizeof(info_commands) / sizeof(info_commands[0]);
4525dfecf96Smrg		     i++) {
453f765521fSmrg		    const char *str = info_commands[i].name;
4545dfecf96Smrg
4555dfecf96Smrg		    ptr = arg;
4565dfecf96Smrg		    while (*ptr && *ptr == *str) {
4575dfecf96Smrg			++ptr;
4585dfecf96Smrg			++str;
4595dfecf96Smrg		    }
4605dfecf96Smrg		    if (*ptr == '\0') {
4615dfecf96Smrg			subaction = info_commands[i].subaction;
4625dfecf96Smrg			if (*str == '\0') {
4635dfecf96Smrg			    matches = 1;
4645dfecf96Smrg			    break;
4655dfecf96Smrg			}
4665dfecf96Smrg			++matches;
4675dfecf96Smrg		    }
4685dfecf96Smrg		}
4695dfecf96Smrg		if (matches == 0) {
4705dfecf96Smrg		    LispFputs(Stdout, "* Command unknown: ");
4715dfecf96Smrg		    LispFputs(Stdout, arg);
4725dfecf96Smrg		    LispFputs(Stdout, ". Type info for help.\n");
4735dfecf96Smrg		    continue;
4745dfecf96Smrg		}
4755dfecf96Smrg		else if (matches > 1) {
4765dfecf96Smrg		    LispFputs(Stdout, "* Command is ambiguous: ");
4775dfecf96Smrg		    LispFputs(Stdout, arg);
4785dfecf96Smrg		    LispFputs(Stdout, ". Type info for help.\n");
4795dfecf96Smrg		    continue;
4805dfecf96Smrg		}
4815dfecf96Smrg
4825dfecf96Smrg		switch (subaction) {
4835dfecf96Smrg		    case DebuggerInfoBreakpoints:
4845dfecf96Smrg			LispFputs(Stdout, "Num\tHits\tType\t\tWhat\n");
4855dfecf96Smrg			for (obj = BRK; obj != NIL; obj = CDR(obj)) {
4865dfecf96Smrg			    /* breakpoint number */
4875dfecf96Smrg			    LispFputc(Stdout, '#');
4885dfecf96Smrg			    LispWriteObject(NIL, CAR(CDR(CAR(obj))));
4895dfecf96Smrg
4905dfecf96Smrg			    /* number of hits */
4915dfecf96Smrg			    LispFputc(Stdout, '\t');
4925dfecf96Smrg			    LispWriteObject(NIL, CAR(CDR(CDR(CDR(CAR(obj))))));
4935dfecf96Smrg
4945dfecf96Smrg			    /* breakpoint type */
4955dfecf96Smrg			    LispFputc(Stdout, '\t');
4965dfecf96Smrg			    switch ((int)FIXNUM_VALUE(CAR(CDR(CDR(CAR(obj)))))) {
4975dfecf96Smrg				case LispDebugBreakFunction:
4985dfecf96Smrg				    LispFputs(Stdout, "Function");
4995dfecf96Smrg				    break;
5005dfecf96Smrg				case LispDebugBreakVariable:
5015dfecf96Smrg				    LispFputs(Stdout, "Variable");
5025dfecf96Smrg				    break;
5035dfecf96Smrg			    }
5045dfecf96Smrg
5055dfecf96Smrg			    /* breakpoint object */
5065dfecf96Smrg			    LispFputc(Stdout, '\t');
5075dfecf96Smrg			    LispWriteObject(NIL, CAR(CAR(obj)));
5085dfecf96Smrg			    LispFputc(Stdout, '\n');
5095dfecf96Smrg			}
5105dfecf96Smrg			break;
5115dfecf96Smrg		    case DebuggerInfoBacktrace:
5125dfecf96Smrg			goto debugger_print_backtrace;
5135dfecf96Smrg		}
5145dfecf96Smrg		break;
5155dfecf96Smrg	    case DebuggerAbort:
5165dfecf96Smrg		while (lisp__data.mem.level) {
5175dfecf96Smrg		    --lisp__data.mem.level;
5185dfecf96Smrg		    if (lisp__data.mem.mem[lisp__data.mem.level])
5195dfecf96Smrg			free(lisp__data.mem.mem[lisp__data.mem.level]);
5205dfecf96Smrg		}
5215dfecf96Smrg		lisp__data.mem.index = 0;
5225dfecf96Smrg		LispTopLevel();
5235dfecf96Smrg		if (!lisp__data.running) {
5245dfecf96Smrg		    LispMessage("*** Fatal: nowhere to longjmp.");
5255dfecf96Smrg		    abort();
5265dfecf96Smrg		}
5275dfecf96Smrg		/* don't need to restore environment */
5285dfecf96Smrg		siglongjmp(lisp__data.jmp, 1);
5295dfecf96Smrg		/*NOTREACHED*/
5305dfecf96Smrg		break;
5315dfecf96Smrg	    case DebuggerBreak:
5325dfecf96Smrg		for (ptr = arg; *ptr; ptr++) {
5335dfecf96Smrg		    if (isspace(*ptr))
5345dfecf96Smrg			break;
5355dfecf96Smrg		    else
5365dfecf96Smrg			*ptr = toupper(*ptr);
5375dfecf96Smrg		}
5385dfecf96Smrg
5395dfecf96Smrg		if (!*arg || *ptr || strchr(arg, '(') || strchr(arg, '(') ||
5405dfecf96Smrg		    strchr(arg, ';')) {
5415dfecf96Smrg		    LispFputs(Stdout, "* Bad function name '");
5425dfecf96Smrg		    LispFputs(Stdout, arg);
5435dfecf96Smrg		    LispFputs(Stdout, "' specified.\n");
5445dfecf96Smrg		}
5455dfecf96Smrg		else {
5465dfecf96Smrg		    for (obj = frm = BRK; obj != NIL; frm = obj, obj = CDR(obj))
5475dfecf96Smrg			;
5485dfecf96Smrg		    i = lisp__data.debug_break;
5495dfecf96Smrg		    ++lisp__data.debug_break;
5505dfecf96Smrg		    GCDisable();
5515dfecf96Smrg		    obj = CONS(ATOM(arg),
5525dfecf96Smrg			       CONS(FIXNUM(i),
5535dfecf96Smrg				    CONS(FIXNUM(LispDebugBreakFunction),
5545dfecf96Smrg					 CONS(FIXNUM(0), NIL))));
5555dfecf96Smrg		    if (BRK == NIL)
5565dfecf96Smrg			BRK = CONS(obj, NIL);
5575dfecf96Smrg		    else
5585dfecf96Smrg			RPLACD(frm, CONS(obj, NIL));
5595dfecf96Smrg		    GCEnable();
5605dfecf96Smrg		}
5615dfecf96Smrg		break;
5625dfecf96Smrg	    case DebuggerWatch: {
5635dfecf96Smrg		void *sym;
5645dfecf96Smrg		int vframe;
5655dfecf96Smrg		LispObj *val, *atom;
5665dfecf96Smrg
5675dfecf96Smrg		/* make variable name uppercase, an ATOM */
5685dfecf96Smrg		ptr = arg;
5695dfecf96Smrg		while (*ptr) {
5705dfecf96Smrg		    *ptr = toupper(*ptr);
5715dfecf96Smrg		    ++ptr;
5725dfecf96Smrg		}
5735dfecf96Smrg		atom = ATOM(arg);
5745dfecf96Smrg		val = LispGetVar(atom);
5755dfecf96Smrg		if (val == NULL) {
5765dfecf96Smrg		    LispFputs(Stdout, "* No variable named '");
5775dfecf96Smrg		    LispFputs(Stdout, arg);
5785dfecf96Smrg		    LispFputs(Stdout, "' in the selected frame.\n");
5795dfecf96Smrg		    break;
5805dfecf96Smrg		}
5815dfecf96Smrg
5825dfecf96Smrg		/* variable is available at the current frame */
5835dfecf96Smrg		sym = LispGetVarAddr(atom);
5845dfecf96Smrg
5855dfecf96Smrg		/* find the lowest frame where the variable is visible */
5865dfecf96Smrg		vframe = 0;
5875dfecf96Smrg		if (frame > 0) {
5885dfecf96Smrg		    for (; vframe < frame; vframe++) {
5895dfecf96Smrg			for (frm = DBG, i = lisp__data.debug_level; i > vframe;
5905dfecf96Smrg			     frm = CDR(frm), i--)
5915dfecf96Smrg			    ;
5925dfecf96Smrg			obj = CAR(frm);
5935dfecf96Smrg			lisp__data.stack.base = FIXNUM_VALUE(CAR(CDR(CDR(obj))));
5945dfecf96Smrg			lisp__data.env.length = FIXNUM_VALUE(CAR(CDR(CDR(CDR(obj)))));
5955dfecf96Smrg			lisp__data.env.lex = FIXNUM_VALUE(CDR(CDR(CDR(CDR(obj)))));
5965dfecf96Smrg
5975dfecf96Smrg			if (LispGetVarAddr(atom) == sym)
5985dfecf96Smrg			    /* got variable initial frame */
5995dfecf96Smrg			    break;
6005dfecf96Smrg		    }
6015dfecf96Smrg		    vframe = i;
6025dfecf96Smrg		    if (vframe != frame) {
6035dfecf96Smrg			/* restore environment */
6045dfecf96Smrg			for (frm = DBG, i = lisp__data.debug_level; i > frame;
6055dfecf96Smrg			     frm = CDR(frm), i--)
6065dfecf96Smrg			    ;
6075dfecf96Smrg			obj = CAR(frm);
6085dfecf96Smrg			lisp__data.stack.base = FIXNUM_VALUE(CAR(CDR(CDR(obj))));
6095dfecf96Smrg			lisp__data.env.length = FIXNUM_VALUE(CAR(CDR(CDR(CDR(obj)))));
6105dfecf96Smrg			lisp__data.env.lex = FIXNUM_VALUE(CDR(CDR(CDR(CDR(obj)))));
6115dfecf96Smrg		    }
6125dfecf96Smrg		}
6135dfecf96Smrg
6145dfecf96Smrg		i = lisp__data.debug_break;
6155dfecf96Smrg		++lisp__data.debug_break;
6165dfecf96Smrg		for (obj = frm = BRK; obj != NIL; frm = obj, obj = CDR(obj))
6175dfecf96Smrg		    ;
6185dfecf96Smrg
6195dfecf96Smrg		GCDisable();
6205dfecf96Smrg		obj = CONS(atom,					/* NAM */
6215dfecf96Smrg			   CONS(FIXNUM(i),				/* IDX */
6225dfecf96Smrg				CONS(FIXNUM(LispDebugBreakVariable),	/* TYP */
6235dfecf96Smrg				     CONS(FIXNUM(0),			/* HIT */
6245dfecf96Smrg					  CONS(OPAQUE(sym, 0),		/* VAR */
6255dfecf96Smrg					       CONS(val,		/* VAL */
6265dfecf96Smrg						    CONS(FIXNUM(vframe),/* FRM */
6275dfecf96Smrg							      NIL)))))));
6285dfecf96Smrg
6295dfecf96Smrg		/* add watchpoint */
6305dfecf96Smrg		if (BRK == NIL)
6315dfecf96Smrg		    BRK = CONS(obj, NIL);
6325dfecf96Smrg		else
6335dfecf96Smrg		    RPLACD(frm, CONS(obj, NIL));
6345dfecf96Smrg		GCEnable();
6355dfecf96Smrg	    }	break;
6365dfecf96Smrg	    case DebuggerDelete:
6375dfecf96Smrg		if (*arg == 0) {
6385dfecf96Smrg		    int confirm = 0;
6395dfecf96Smrg
6405dfecf96Smrg		    for (;;) {
6415dfecf96Smrg			int ch;
6425dfecf96Smrg
6435dfecf96Smrg			LispFputs(Stdout, "* Delete all breakpoints? (y or n) ");
6445dfecf96Smrg			LispFflush(Stdout);
6455dfecf96Smrg			if ((ch = LispFgetc(Stdin)) == '\n')
6465dfecf96Smrg			    continue;
6475dfecf96Smrg			while ((i = LispFgetc(Stdin)) != '\n' && i != EOF)
6485dfecf96Smrg			    ;
6495dfecf96Smrg			if (tolower(ch) == 'n')
6505dfecf96Smrg			    break;
6515dfecf96Smrg			else if (tolower(ch) == 'y') {
6525dfecf96Smrg			    confirm = 1;
6535dfecf96Smrg			    break;
6545dfecf96Smrg			}
6555dfecf96Smrg		    }
6565dfecf96Smrg		    if (confirm)
6575dfecf96Smrg			BRK = NIL;
6585dfecf96Smrg		}
6595dfecf96Smrg		else {
6605dfecf96Smrg		    for (ptr = arg; *ptr;) {
6615dfecf96Smrg			while (*ptr && isdigit(*ptr))
6625dfecf96Smrg			    ++ptr;
6635dfecf96Smrg			if (*ptr && !isspace(*ptr)) {
6645dfecf96Smrg			    *ptr = '\0';
6655dfecf96Smrg			    LispFputs(Stdout, "* Bad breakpoint number '");
6665dfecf96Smrg			    LispFputs(Stdout, arg);
6675dfecf96Smrg			    LispFputs(Stdout, "' specified.\n");
6685dfecf96Smrg			    break;
6695dfecf96Smrg			}
6705dfecf96Smrg			i = atoi(arg);
6715dfecf96Smrg			for (obj = frm = BRK; frm != NIL;
6725dfecf96Smrg			     obj = frm, frm = CDR(frm))
6735dfecf96Smrg			    if (FIXNUM_VALUE(CAR(CDR(CAR(frm)))) == i)
6745dfecf96Smrg				break;
6755dfecf96Smrg			if (frm == NIL) {
6765dfecf96Smrg			    LispFputs(Stdout, "* No breakpoint number ");
6775dfecf96Smrg			    LispFputs(Stdout, arg);
6785dfecf96Smrg			    LispFputs(Stdout, " available.\n");
6795dfecf96Smrg			    break;
6805dfecf96Smrg			}
6815dfecf96Smrg			if (obj == frm)
6825dfecf96Smrg			    BRK = CDR(BRK);
6835dfecf96Smrg			else
6845dfecf96Smrg			    RPLACD(obj, CDR(frm));
6855dfecf96Smrg			while (*ptr && isspace(*ptr))
6865dfecf96Smrg			    ++ptr;
6875dfecf96Smrg			arg = ptr;
6885dfecf96Smrg		    }
6895dfecf96Smrg		}
6905dfecf96Smrg		break;
6915dfecf96Smrg	    case DebuggerFrame:
6925dfecf96Smrg		i = -1;
6935dfecf96Smrg		ptr = arg;
6945dfecf96Smrg		if (*ptr) {
6955dfecf96Smrg		    i = 0;
6965dfecf96Smrg		    while (*ptr && isdigit(*ptr)) {
6975dfecf96Smrg			i *= 10;
6985dfecf96Smrg			i += *ptr - '0';
6995dfecf96Smrg			++ptr;
7005dfecf96Smrg		    }
7015dfecf96Smrg		    if (*ptr) {
7025dfecf96Smrg			LispFputs(Stdout, "* Frame identifier must "
7035dfecf96Smrg				"be a positive number.\n");
7045dfecf96Smrg			break;
7055dfecf96Smrg		    }
7065dfecf96Smrg		}
7075dfecf96Smrg		else
7085dfecf96Smrg		    goto debugger_print_frame;
7095dfecf96Smrg		if (i >= 0 && i <= lisp__data.debug_level)
7105dfecf96Smrg		    goto debugger_new_frame;
7115dfecf96Smrg		LispFputs(Stdout, "* No such frame ");
7125dfecf96Smrg		LispFputs(Stdout, format_integer(i));
7135dfecf96Smrg		LispFputs(Stdout, ".\n");
7145dfecf96Smrg		break;
7155dfecf96Smrg	    case DebuggerDown:
7165dfecf96Smrg		if (frame + 1 > lisp__data.debug_level) {
7175dfecf96Smrg		    LispFputs(Stdout, "* Cannot go down.\n");
7185dfecf96Smrg		    break;
7195dfecf96Smrg		}
7205dfecf96Smrg		i = frame + 1;
7215dfecf96Smrg		goto debugger_new_frame;
7225dfecf96Smrg		break;
7235dfecf96Smrg	    case DebuggerUp:
7245dfecf96Smrg		if (frame == 0) {
7255dfecf96Smrg		    LispFputs(Stdout, "* Cannot go up.\n");
7265dfecf96Smrg		    break;
7275dfecf96Smrg		}
7285dfecf96Smrg		i = frame - 1;
7295dfecf96Smrg		goto debugger_new_frame;
7305dfecf96Smrg		break;
7315dfecf96Smrg	    case DebuggerPrint:
7325dfecf96Smrg		ptr = arg;
7335dfecf96Smrg		while (*ptr) {
7345dfecf96Smrg		    *ptr = toupper(*ptr);
7355dfecf96Smrg		    ++ptr;
7365dfecf96Smrg		}
7375dfecf96Smrg		obj = LispGetVar(ATOM(arg));
7385dfecf96Smrg		if (obj != NULL) {
7395dfecf96Smrg		    LispWriteObject(NIL, obj);
7405dfecf96Smrg		    LispFputc(Stdout, '\n');
7415dfecf96Smrg		}
7425dfecf96Smrg		else {
7435dfecf96Smrg		    LispFputs(Stdout, "* No variable named '");
7445dfecf96Smrg		    LispFputs(Stdout, arg);
7455dfecf96Smrg		    LispFputs(Stdout, "' in the selected frame.\n");
7465dfecf96Smrg		}
7475dfecf96Smrg		break;
7485dfecf96Smrg	    case DebuggerBacktrace:
7495dfecf96Smrgdebugger_print_backtrace:
7505dfecf96Smrg		if (DBG == NIL) {
7515dfecf96Smrg		    LispFputs(Stdout, "* No stack.\n");
7525dfecf96Smrg		    break;
7535dfecf96Smrg		}
7545dfecf96Smrg		DBG = LispReverse(DBG);
7555dfecf96Smrg		for (obj = DBG, i = 0; obj != NIL; obj = CDR(obj), i++) {
7565dfecf96Smrg		    frm = CAR(obj);
7575dfecf96Smrg		    LispFputc(Stdout, '#');
7585dfecf96Smrg		    LispFputs(Stdout, format_integer(i));
7595dfecf96Smrg		    LispFputs(Stdout, "> (");
7605dfecf96Smrg		    LispWriteObject(NIL, CAR(frm));
7615dfecf96Smrg		    LispFputc(Stdout, ' ');
7625dfecf96Smrg		    LispWriteObject(NIL, CAR(CDR(frm)));
7635dfecf96Smrg		    LispFputs(Stdout, ")\n");
7645dfecf96Smrg		}
7655dfecf96Smrg		DBG = LispReverse(DBG);
7665dfecf96Smrg		break;
7675dfecf96Smrg	    case DebuggerContinue:
7685dfecf96Smrg		lisp__data.debug = LispDebugRun;
7695dfecf96Smrg		goto debugger_command_done;
7705dfecf96Smrg	    case DebuggerFinish:
7715dfecf96Smrg		if (lisp__data.debug != LispDebugFinish) {
7725dfecf96Smrg		    lisp__data.debug_step = lisp__data.debug_level - 2;
7735dfecf96Smrg		    lisp__data.debug = LispDebugFinish;
7745dfecf96Smrg		}
7755dfecf96Smrg		else
7765dfecf96Smrg		    lisp__data.debug_step = lisp__data.debug_level - 1;
7775dfecf96Smrg		goto debugger_command_done;
7785dfecf96Smrg	    case DebuggerNext:
7795dfecf96Smrg		if (lisp__data.debug != LispDebugNext) {
7805dfecf96Smrg		    lisp__data.debug = LispDebugNext;
7815dfecf96Smrg		    lisp__data.debug_step = lisp__data.debug_level + 1;
7825dfecf96Smrg		}
7835dfecf96Smrg		goto debugger_command_done;
7845dfecf96Smrg	    case DebuggerStep:
7855dfecf96Smrg		lisp__data.debug = LispDebugStep;
7865dfecf96Smrg		goto debugger_command_done;
7875dfecf96Smrg	}
7885dfecf96Smrg	continue;
7895dfecf96Smrg
7905dfecf96Smrgdebugger_new_frame:
7915dfecf96Smrg	/* goto here with i as the new frame value, after error checking */
7925dfecf96Smrg	if (i != frame) {
7935dfecf96Smrg	    frame = i;
7945dfecf96Smrg	    for (frm = DBG, i = lisp__data.debug_level;
7955dfecf96Smrg		 i > frame; frm = CDR(frm), i--)
7965dfecf96Smrg		;
7975dfecf96Smrg	    curframe = CAR(frm);
7985dfecf96Smrg	    lisp__data.stack.base = FIXNUM_VALUE(CAR(CDR(CDR(curframe))));
7995dfecf96Smrg	    lisp__data.env.length = FIXNUM_VALUE(CAR(CDR(CDR(CDR(curframe)))));
8005dfecf96Smrg	    lisp__data.env.lex = FIXNUM_VALUE(CDR(CDR(CDR(CDR(curframe)))));
8015dfecf96Smrg	}
8025dfecf96Smrgdebugger_print_frame:
8035dfecf96Smrg	LispFputc(Stdout, '#');
8045dfecf96Smrg	LispFputs(Stdout, format_integer(frame));
8055dfecf96Smrg	LispFputs(Stdout, "> (");
8065dfecf96Smrg	LispWriteObject(NIL, CAR(curframe));
8075dfecf96Smrg	LispFputc(Stdout, ' ');
8085dfecf96Smrg	LispWriteObject(NIL, CAR(CDR(curframe)));
8095dfecf96Smrg	LispFputs(Stdout, ")\n");
8105dfecf96Smrg    }
8115dfecf96Smrg
8125dfecf96Smrgdebugger_command_done:
8135dfecf96Smrg    lisp__data.stack.base = envbase;
8145dfecf96Smrg    lisp__data.env.length = envlen;
8155dfecf96Smrg    lisp__data.env.lex = envlex;
8165dfecf96Smrg}
8175dfecf96Smrg
8185dfecf96Smrgstatic char *
8195dfecf96Smrgformat_integer(int integer)
8205dfecf96Smrg{
8215dfecf96Smrg    static char buffer[16];
8225dfecf96Smrg
8235dfecf96Smrg    sprintf(buffer, "%d", integer);
8245dfecf96Smrg
8255dfecf96Smrg    return (buffer);
8265dfecf96Smrg}
8275dfecf96Smrg
8285dfecf96Smrg#endif /* DEBUGGER */
829