muforth/error.c

/*
 * This file is part of muFORTH: http://pages.nimblemachines.com/muforth
 *
 * Copyright (c) 2002-2008 David Frech. All rights reserved, and all wrongs
 * reversed. (See the file COPYRIGHT for details.)
 */

/* error-handling code for muForth */

#include "muforth.h"

#include <setjmp.h>
#include <stdlib.h>
#include <errno.h>

#ifndef XXX
#include <sys/uio.h>
#include <unistd.h>
#endif

#define write_string(f,s)  write(f,s,strlen(s))

/* A bit of a crock, but only called if we haven't set up a catch frame. */
void die(const char *msg)
{
    write_string(2, "muforth: ");
    if (parsed.length != 0)
    {
        write(2, parsed.data, parsed.length);
        write(2, " ", 1);
    }
    write_string(2, msg);
    write(2, "\n", 1);
    exit(1);
}

/* This works like C and not like Forth: catch returns 0 when it sets up
 * the frame and non-zero when it has been longjumped to. Catch does _not_
 * call a function. But then, how/when do you undo the frame? Hmmm.
 * Okay, doing it the Forth way. */

#define SETJMP setjmp
#define LONGJMP longjmp

struct trapframe
{
    jmp_buf jb;
    struct trapframe *prev;
    xtk *ip;
    cell *sp;
    xtk **rp;
};

static struct trapframe *last_tf;    /* top of "stack" of trap frames */

void mu_catch()
{
    struct trapframe tf;
    cell thrown;

    /* link onto front of trapframe list */
    tf.prev = last_tf;
    last_tf = &tf;

    tf.sp = SP;
    tf.rp = RP;
    tf.ip = IP;

    thrown = SETJMP(tf.jb);
    if (thrown == 0)
    {
        EXECUTE;
        DUP;     /* make room for thrown value */
    }
    else
    {
        SP = tf.sp;  /* we longjmp'ed; restore sp, rp, & ip */
        RP = tf.rp;
        IP = tf.ip;
    }
    /* unlink frame */
    last_tf = tf.prev;

    /* return thrown value */
    TOP = thrown;
}

void mu_throw()
{
    if (TOP != 0)
    {
        if (last_tf)
            LONGJMP(last_tf->jb, TOP);
        else
            die((char *)TOP);
    }
    DROP(1);
}

char *counted_strerror()
{
    return to_counted_string(strerror(errno));
}