# define INCLUDE_FILE_IO
# include "dgd.h"
# include "str.h"
# include "array.h"
# include "object.h"
# include "data.h"
# include "interpret.h"
# include "comm.h"
typedef struct _context_ {
jmp_buf env; /* error context */
frame *f; /* frame context */
unsigned short offset; /* sp offset */
rlinfo *rlim; /* rlimits info */
ec_ftn handler; /* error handler */
struct _context_ *next; /* next in linked list */
} context;
static context firstcontext; /* bottom context */
static context *econtext; /* current error context */
static context *atomicec; /* first context beyond atomic */
static string *errstr; /* current error string */
/*
* NAME: errcontext->clear()
* DESCRIPTION: clear the error context string
*/
void ec_clear()
{
if (errstr != (string *) NULL) {
str_del(errstr);
errstr = (string *) NULL;
}
}
/*
* NAME: errcontext->_push_()
* DESCRIPTION: push and return the current errorcontext
*/
jmp_buf *_ec_push_(handler)
ec_ftn handler;
{
register context *e;
if (econtext == (context *) NULL) {
e = &firstcontext;
} else {
e = ALLOC(context, 1);
}
e->f = cframe;
e->offset = cframe->fp - cframe->sp;
e->rlim = cframe->rlim;
e->handler = handler;
e->next = econtext;
econtext = e;
return &e->env;
}
/*
* NAME: errcontext->pop()
* DESCRIPTION: pop the current errorcontext
*/
void ec_pop()
{
register context *e;
e = econtext;
# ifdef DEBUG
if (e == (context *) NULL) {
fatal("pop empty error stack");
}
# endif
econtext = e->next;
if (e != &firstcontext) {
FREE(e);
} else {
ec_clear();
}
}
/*
* NAME: errorcontext->handler()
* DESCRIPTION: dummy handler for previously handled error
*/
static void ec_handler(f, depth)
frame *f;
Int depth;
{
}
/*
* NAME: errorstr()
* DESCRIPTION: return the current error string
*/
string *errorstr()
{
return errstr;
}
/*
* NAME: serror()
* DESCRIPTION: cause an error, with a string argument
*/
void serror(str)
string *str;
{
jmp_buf env;
register context *e;
int offset;
ec_ftn handler;
if (str != (string *) NULL) {
if (errstr != (string *) NULL) {
str_del(errstr);
}
str_ref(errstr = str);
# ifdef DEBUG
} else if (errstr == (string *) NULL) {
fatal("no error string");
# endif
}
e = econtext;
offset = e->offset;
memcpy(&env, &e->env, sizeof(jmp_buf));
if (atomicec == (context *) NULL || atomicec == e) {
do {
if (cframe->level != e->f->level) {
if (atomicec == (context *) NULL) {
i_atomic_error(cframe, e->f->level);
if (e != econtext) {
atomicec = e;
break; /* handle rollback later */
}
}
cframe = i_restore(cframe, e->f->level);
atomicec = (context *) NULL;
}
if (e->handler != (ec_ftn) NULL) {
handler = e->handler;
e->handler = (ec_ftn) ec_handler;
(*handler)(cframe, e->f->depth);
break;
}
e = e->next;
} while (e != (context *) NULL);
}
if (cframe->rlim != econtext->rlim) {
i_set_rlimits(cframe, econtext->rlim);
}
cframe = i_set_sp(cframe, econtext->f->fp - offset);
cframe->rlim = econtext->rlim;
ec_pop();
longjmp(env, 1);
}
/*
* NAME: error()
* DESCRIPTION: cause an error
*/
void error(format, arg1, arg2, arg3, arg4, arg5, arg6)
char *format, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
{
char ebuf[4 * STRINGSZ];
if (format != (char *) NULL) {
sprintf(ebuf, format, arg1, arg2, arg3, arg4, arg5, arg6);
serror(str_new(ebuf, (long) strlen(ebuf)));
} else {
serror((string *) NULL);
}
}
/*
* NAME: fatal()
* DESCRIPTION: a fatal error has been encountered; terminate the program and
* dump a core if possible
*/
void fatal(format, arg1, arg2, arg3, arg4, arg5, arg6)
char *format, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
{
static short count;
char ebuf1[STRINGSZ], ebuf2[STRINGSZ];
if (count++ == 0) {
sprintf(ebuf1, format, arg1, arg2, arg3, arg4, arg5, arg6);
sprintf(ebuf2, "Fatal error: %s\012", ebuf1); /* LF */
P_message(ebuf2); /* show message */
comm_finish();
}
abort();
}
/*
* NAME: message()
* DESCRIPTION: issue a message on stderr
*/
void message(format, arg1, arg2, arg3, arg4, arg5, arg6)
char *format, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
{
char ebuf[4 * STRINGSZ];
if (format == (char *) NULL) {
# ifdef DEBUG
if (errstr == (string *) NULL) {
fatal("no error string");
}
# endif
if (errstr->len <= sizeof(ebuf) - 2) {
sprintf(ebuf, "%s\012", errstr->text);
} else {
strcpy(ebuf, "[too long error string]\012");
}
} else {
sprintf(ebuf, format, arg1, arg2, arg3, arg4, arg5, arg6);
}
P_message(ebuf); /* show message */
}