/* xldebug - xlisp debugging support */
/* Copyright (c) 1989, by David Michael Betz.                            */
/* You may give out copies of this software; for conditions see the file */
/* COPYING included with this distribution.                              */

#include "xlisp.h"

/* forward declarations */
LOCAL VOID breakloop P5H(char *, char *, char *, LVAL, int);
#ifdef CONDITIONS
LOCAL VOID conditionhook P3H(char *, char *, LVAL);
#endif /* CONDITIONS */

/* xlabort - xlisp serious error handler */
VOID xlabort P1C(char *, emsg)
{
    xlsignal(emsg,s_unbound);
    xlerrprint("error",NULL,emsg,s_unbound);
    xlbrklevel();
}

/* xlbreak - enter a break loop */
VOID xlbreak P2C(char *, emsg, LVAL, arg)
{
    breakloop("break","return from BREAK",emsg,arg,TRUE);
}

/* xlfail - xlisp error handler */
VOID xlfail P1C(char *, emsg)
{
    xlerror(emsg,s_unbound);
}

/* xlerror - handle a fatal error */
LVAL xlerror P2C(char *, emsg, LVAL, arg)
{
  /** This is an incredible hack.  If an error occurs in
      initialization we are in big trouble.  The most common reason is
      that on this hardware division by zero causes a SIGFPE.  This
      really needs to be dealt with in configure. **/
  if (s_breakenable == NULL) {
    if (strcmp(emsg, "floating point error")==0)
      xoserror("floating point error, probably in computing IEEE infinity"
	       "--check how to prevent floating point division by zero"
	       " from raising a SIGFPE on your system");
    else xoserror(emsg);
    exit(1);
  }
#ifdef CONDITIONS
    if (s_condition_hook != NULL && getvalue(s_condition_hook) != NIL)
      conditionhook(NULL, emsg, arg);
    else
#endif /* CONDITIONS */
    if (!null(getvalue(s_breakenable)))
	breakloop("error",NULL,emsg,arg,FALSE);
    else {
	xlsignal(emsg,arg);
	xlerrprint("error",NULL,emsg,arg);
	xlbrklevel();
    }
    return NIL;     /* actually doesn't return */
}

/* xlcerror - handle a recoverable error */
VOID xlcerror P3C(char *, cmsg, char *, emsg, LVAL, arg)
{
#ifdef CONDITIONS
    if (s_condition_hook != NULL && getvalue(s_condition_hook) != NIL)
      conditionhook(cmsg, emsg, arg);
    else
#endif /* CONDITIONS */
    if (!null(getvalue(s_breakenable)))
	breakloop("error",cmsg,emsg,arg,TRUE);
    else {
	xlsignal(emsg,arg);
	xlerrprint("error",NULL,emsg,arg);
	xlbrklevel();
    }
}

/* xlerrprint - print an error message */
VOID xlerrprint P4C(char *, hdr, char *, cmsg, char *, emsg, LVAL, arg)
{
    /* TAA MOD -- start error message on a fresh line */
    xlfreshline(getvalue(s_stderr));

    /* print the error message */
    sprintf(buf,"%s: %s",hdr,emsg);
    errputstr(buf);

    /* print the argument */
    if (arg != s_unbound) {
	errputstr(" - ");
	errprint(arg);
    }

    /* no argument, just end the line */
    else
	errputstr("\n");

    /* print the continuation message */
    if (cmsg != NULL) {
	sprintf(buf,"if continued: %s\n",cmsg);
	errputstr(buf);
    }
}

#ifdef NEED_TO_REPLACE_BREAKLOOP
/* $putpatch.c$: "MODULE_XLDBUG_C_BREAKLOOP_REPLACEMENT" */
#else

/* breakloop - the debug read-eval-print loop */
LOCAL VOID breakloop P5C(char *, hdr, char *, cmsg, char *, emsg, LVAL, arg, int, cflag)
{
    LVAL expr,val;
    CONTEXT cntxt;
    int type;

    /* print the error message */
    xlerrprint(hdr,cmsg,emsg,arg);

    /* handle running in batch mode */
    if (batchmode) xlfatal("uncaught error");

    /* flush the input buffer */
    xlflush();

    /* do the back trace */
    if (!null(getvalue(s_tracenable))) {
	val = getvalue(s_tlimit);
	xlbaktrace(fixp(val) ? (int)getfixnum(val) : -1);
    }

    /* protect some pointers */
    xlsave1(expr);

    /* increment the debug level */
    ++xldebug;

    /* debug command processing loop */
    xlbegin(&cntxt, CF_BRKLEVEL|CF_CLEANUP|CF_CONTINUE, s_true);
    for (type = 0; type == 0; ) {

	/* setup the continue trap */
#ifdef CRAYCC
        type = XL_SETJMP(cntxt.c_jmpbuf);
	if (type != 0)
#else
	if ((type = XL_SETJMP(cntxt.c_jmpbuf)) != 0)
#endif /* CRAYCC */
	    switch (type) {
	    case CF_CLEANUP:
		continue;
	    case CF_BRKLEVEL:
		type = 0;
		break;
	    case CF_CONTINUE:
		if (cflag) {
		    dbgputstr("[ continue from break loop ]\n");
		    continue;
		}
		else xlabort("this error can't be continued");
	    }

	/* print a prompt */
#ifdef PACKAGES
	{
	  LVAL pack = getvalue(s_package);
	  if (pack != xluserpack && goodpackagep(pack)) {
	    dbgputstr(getstring(xlpackagename(pack)));
	    dbgputstr(" ");
	  }
	}
#endif /* PACKAGES */
	sprintf(buf,"%d> ",xldebug);
	dbgputstr(buf);

	/* read an expression and check for eof */
	if (!xlread(getvalue(s_debugio),&expr, FALSE, FALSE)) {
	    type = CF_CLEANUP;
	    break;
	}

	/* save the input expression */
	xlrdsave(expr);

	/* evaluate the expression */
	expr = xleval(expr);

	/* save the result */
	xlevsave(expr);

	/* Show result on a new line -- TAA MOD to improve display */
	xlfreshline(getvalue(s_debugio));

	/* print it */
#ifdef MULVALS
	{
	  int i;
	  for (i = 0; i < xlnumresults; i++)
	    dbgprint(xlresults[i]);
	}
#else
	dbgprint(expr);
#endif /* MULVALS */
    }
    xlend(&cntxt);

    /* decrement the debug level */
    --xldebug;

    /* restore the stack */
    xlpop();

    /* check for aborting to the previous level */
    if (type == CF_CLEANUP)
	xlbrklevel();
}
#endif

/* baktrace - do a back trace */
VOID xlbaktrace P1C(int, n)
{
  FRAMEP fp, p;
  int argc;
  for (fp = xlfp; (n < 0 || n--) && !null(*fp); fp = fp - (int)getfixnum(*fp)) {
    p = fp + 1;
    errputstr("Function: ");
    errprint(*p++);
    if (getvalue(s_baktraceprargs) != NIL) {
      if ((argc = (int)getfixnum(*p++)) != 0)
	errputstr("Arguments:\n");
      while (--argc >= 0) {
	errputstr("  ");
	errprint(*p++);
      }
    }
  }
}

/* xldinit - debug initialization routine */
VOID xldinit(V)
{
    xlsample = 0;
    xldebug = 0;
}

VOID xlsigint(V)
{
  FRAMEP newfp;

  if (boundp(s_intaction) && !null(getvalue(s_intaction))) {
    newfp = xlsp;
    pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
    pusharg(getvalue(s_intaction));
    pusharg(cvfixnum((FIXTYPE)0));
    xlfp = newfp;
    xlapply(0);
  }
}

#ifdef CONDITIONS
LOCAL VOID conditionhook P3C(char *, cmsg, char *, emsg, LVAL, arg)
{
  FRAMEP newfp;
  LVAL olddenv,val,hook;
  int argc;

  /* rebind the hook functions to nil */
  hook = getvalue(s_condition_hook);
  olddenv = xldenv;
  xldbind(s_condition_hook,NIL);

  /* compute argument count */
  argc = cmsg == NULL ? 4 : 5;
  if (arg != s_unbound) argc++;

  /* create the new call frame */
  newfp = xlsp;
  pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  pusharg(hook);
  pusharg(cvfixnum((FIXTYPE) argc));
  pusharg(cmsg == NULL ? s_error : s_cerror);
  pusharg(null(xlfp[0]) ? NIL : cvfixnum((FIXTYPE) (xlfp - xlargstkbase)));
  pusharg(cons(xlenv,xlfenv));
  if (cmsg != NULL) pusharg(cvstring(cmsg));
  if (arg != s_unbound) {
    strcpy(buf, emsg);
    strcat(buf, " - ~S");
    pusharg(cvstring(buf));
  }
  else
    pusharg(cvstring(emsg));
  if (arg != s_unbound) pusharg(arg);
  xlfp = newfp;

  /* call the hook function */
  val = xlapply(argc);

  /* unbind the symbols */
  xlunbind(olddenv);

  if (cmsg == NULL)
    xlabort("condition hook function should not have returned");
}
#endif /* CONDITIONS */


syntax highlighted by Code2HTML, v. 0.9.1