/** 
   --  Exception-oriented Subroutines.
   
    Copyright (C) Tektronix, Inc. 1998 - 2001. All rights reserved.
  
    @see     GNU LGPL
    @author  Tektronix CTE            @(#) %derived_by: guidod %
    @version %version: bln_mpt1!1.22 %
      (%date_modified: Tue Jun 04 16:34:59 2002 %)
 */
/*@{*/
#if defined(__version_control__) && defined(__GNUC__)
static char* id __attribute__((unused)) = 
"@(#) $Id: %full_filespec:  exception-sub.c~bln_mpt1!1.22:csrc:bln_12xx!1 % $";
#endif

#define _P4_SOURCE 1

#include <pfe/pfe-base.h>
#include <pfe/def-xtra.h>

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <setjmp.h>

#include <pfe/exception-sub.h>
#include <pfe/block-sub.h>
#include <pfe/file-sub.h>
#include <pfe/_missing.h>

#include <pfe/logging.h>

#ifndef _export
#define p4_longjmp_abort()	(p4_longjmp_loop('A'))
#define p4_longjmp_exit()	(p4_longjmp_loop('X'))
#define p4_longjmp_quit()	(p4_longjmp_loop('Q'))
#define p4_longjmp_yield()	(p4_longjmp_loop('S'))
#endif

/**
   just call longjmp on PFE.loop
 */
_export void
p4_longjmp_loop(int arg)
{
    longjmp (PFE.loop, arg);
}
/*
   show the error, along with info like the block, filename, line numer.
 */
static void
show_error (const char* str, int len)
{
    int n;

    PFE.input_err = PFE.input;	/* save input specification of error */

    if (! str) str = "";
    if (! len) len = strlen(str);
    p4_outf ("\nError: %.*s", len, str);
    if (! PFE.word.ptr || ! PFE.word.len) 
{ str = ""; len = 1; }
else
{ str = PFE.word.ptr; len = PFE.word.len; }
switch (SOURCE_ID)
{
     case 0:
         if (BLK && BLOCK_FILE && ! ferror (BLOCK_FILE->f))
         
{
             p4_outf ("\nBlock %lu line %d: \"%.*s\"\n",
               (unsigned long) BLK, (int) TO_IN / 64, len, str);
             p4_dot_line (BLOCK_FILE, BLK, TO_IN / 64);
             n = TO_IN % 64;
             break;
         }
/* fallthrough*/ case -1: p4_outf (" : \"%.*s\"\n", len, str); /* to Error:-line */ p4_type (TIB, NUMBER_TIB); n = TO_IN; break; default: p4_outf ("\nFile %s line %lu: \"%.*s\"\n", SOURCE_FILE->name, (unsigned long) SOURCE_FILE->n, len, str); p4_type (TIB, NUMBER_TIB); n = TO_IN; }
if (PFE.word.len > TO_IN) p4_outf ("\n%*s", n, "^"); /* just mark ">IN" */ else
{
	p4_outs ("\n");
	if (TO_IN != PFE.word.len)
	    p4_emits (TO_IN - PFE.word.len-1, ' ');
	p4_emits (PFE.word.len+1, '^'); /* mark the word */
    }
# ifdef _K12_SOURCE if (len > 70) len = 70; if (PFE.tib) strncpy (PFE.tib, str, len); # endif p4_outs (" "); p4_longjmp_abort (); }
static void
throw_msg (int id, char *msg)
{
    static const char *throw_explanation[] =
    
{
        /*  -1 */ NULL, /* ABORT */
        /*  -2 */ NULL, /* ABORT" */
        /*  -3 */ "stack overflow",
        /*  -4 */ "stack underflow",
        /*  -5 */ "return-stack overflow",
        /*  -6 */ "return-stack underflow",
        /*  -7 */ "do-loops nested too deeply during execution",
        /*  -8 */ "dictionary overflow",
        /*  -9 */ "invalid memory address",
        /* -10 */ "division by zero",
        /* -11 */ "result out of range",
        /* -12 */ "argument type mismatch",
        /* -13 */ "undefined word",
        /* -14 */ "interpreting a compile-only word",
        /* -15 */ "invalid FORGET (not between FENCE and HERE)",
        /* -16 */ "attempt to use a zero-length string as a name",
        /* -17 */ "pictured numeric output string overflow",
        /* -18 */ "parsed string overflow (input token longer than 255)",
        /* -19 */ "definition name too long",
        /* -20 */ "write to a read-only location",
        /* -21 */ "unsupported operation",
        /* -22 */ "control structure mismatch",
        /* -23 */ "address alignment exception",
        /* -24 */ "invalid numeric argument",
        /* -25 */ "return stack imbalance",
        /* -26 */ "loop parameters unavailable",
        /* -27 */ "invalid recursion",
        /* -28 */ "user interrupt",
        /* -29 */ "compiler nesting (exec/comp state incorrect)",
        /* -30 */ "obsolescent feature",
        /* -31 */ ">BODY used on non-CREATEDd definition",
        /* -32 */ "invalid name argument",
        /* -33 */ "block read exception",
        /* -34 */ "block write exception",
        /* -35 */ "invalid block number",
        /* -36 */ "invalid file position",
        /* -37 */ "file I/O exception",
        /* -38 */ "non-existent file",
        /* -39 */ "unexpected end of file",
        /* -40 */ "invalid BASE for floating-point conversion",
        /* -41 */ "loss of precision",
        /* -42 */ "floating-point divide by zero",
        /* -43 */ "floating-point result out of range",
        /* -44 */ "floating-point stack overflow",
        /* -45 */ "floating-point stack underflow",
        /* -46 */ "floating-point invalid argument",
        /* -47 */ "CURRENT deleted (forget on DEFINITIONS vocabulary)",
        /* -48 */ "invalid POSTPONE",
        /* -49 */ "search-order overflow (ALSO failed)",
        /* -50 */ "search-order underflow (PREVIOUS failed)",
        /* -51 */ "compilation word list changed",
        /* -52 */ "control flow stack overflow",
        /* -53 */ "exception stack overflow",
        /* -54 */ "floating-point underflow",
        /* -55 */ "floating-point unidentified fault",
        /* -56 */ NULL, /* QUIT */
        /* -57 */ "error in sending or receiving a character",
        /* -58 */ "[IF], [ELSE] or [THEN] error",
        /* -59 */ "dictionary space exhausted"
    }
; if (-1 - DIM (throw_explanation) < id && id <= -1)
{
        /* ANS-Forth throw codes, messages are in throw_explanation[] */
        strcpy (msg, throw_explanation[-1 - id]);
    }
else if (-1024 < id && id <= -256)
{
        /* Signals, see signal-ext.c, 
	   those not handled and not fatal lead to THROW */
        sprintf (msg, "Received signal %d", -256 - id);
    }
else if (-2048 < id && id <= -1024)
{
        /* File errors, see FX_IOR / P4_IOR(flag) */
        sprintf (msg, "I/O Error %d : %s", -1024-id, strerror (-1024-id));
    }
else if (-32767 < id && id <= -2048)
{
	/* search the exception_link for our id */
	p4_Exception* expt = PFE.exception_link;
	strcpy (msg, "module-specific error-condition");
	while (expt)
	
{
	    if (expt->id == id)
	    
{
		strcpy (msg, expt->name);
		break;
	    }
expt = expt->next; }
}
else if (0 < id)
{
#     ifdef PFE_HAVE_STRERROR_R
	strerror_r (id, msg, 255);
#     else
	strcpy (msg, strerror (id));
#     endif
    }
else
{
        sprintf (msg, "%d THROW unassigned", id);
    }
}
/**
   the CATCH impl
 */
_export int
p4_catch (p4xt xt)
{
    register int id;
#  ifdef P4_RP_IN_VM
    Except *x = P4_DEC (RP, Except);
#  else
    auto Except except;  register Except *x = & except;
#  endif

    x->magic = P4_EXCEPTION_MAGIC;
#  ifndef PFE_SBR_CALL_ARG_THREADING 
    x->ipp = IP;
#  endif
    x->spp = SP;
    x->lpp = LP;
#  ifndef P4_NO_FP
    x->fpp = FP;
#  endif
    x->iframe = PFE.saved_input;
    x->prev = PFE.cAtch;
    PFE.cAtch = x;
    id = setjmp (x->jmp);
    if (!id)
        p4_call (xt);
    PFE.cAtch = x->prev;
#  ifdef P4_RP_IN_VM
    RP = (p4xcode **) &x[1]; /*fixme: need to enable that in sbr-threading??*/
#  endif
    return id;
}
#ifdef _K12_SOURCE extern void trcStack(int); /* show stack trace */ extern int taskIdSelf(); extern int taskPriorityGet(int, int*); extern int taskDelay(int); extern int taskSpawn(char*, int, int, int, void*, int, ...);
static int spawn_trcStack(int taskprio, int taskid)
{ 
    if (taskprio > 0) taskprio--;
    taskDelay(1); /* 1 x sched_yield */
    taskSpawn(0, taskprio, 0, 8192, (void*)trcStack, taskid); 
    return 0;
}
#endif
/**
   the THROW impl
 */
_export void
p4_throws (int id, const char* addr, int len)
{
    Except *x = PFE.cAtch;
    char msg[256];

    if (PFE.atexit_running) 
    
{
        if (addr && len)
            show_error (addr, len);
        p4_longjmp_exit ();
    }
#ifdef _K12_SOURCE
{
        int taskid, taskprio;
        if (p4_LogMask & P4_LOG_DEBUG) 
        
{ /* if any debug-channel used */
            taskPriorityGet((taskid= taskIdSelf()), &taskprio);
            taskSpawn(0, taskprio, 0, 8192, 
              (void*)spawn_trcStack, taskprio, taskid);
            taskDelay(2); /* 2 x sched_yield */
        }
}
#endif if (PFE.throw_cleanup)
{ 
        PFE.throw_cleanup ();
        PFE.throw_cleanup = NULL;
    }
if (x && x->magic == P4_EXCEPTION_MAGIC)
{
#    ifndef PFE_SBR_CALL_ARG_THREADING
        IP = x->ipp;
#    endif
        SP = x->spp;
        LP = x->lpp;
#    ifndef P4_NO_FP
        FP = x->fpp;
#     endif /*P4_NO_FP*/
        p4_unnest_input (x->iframe);
        longjmp (x->jmp, id);
    }
# ifdef P4_RP_IN_VM *--RP = IP; CSP = (p4cell*) RP; /* come_back marker */ # endif switch (id)
{
     case P4_ON_ABORT_QUOTE:
     
{
	 show_error (addr, len);
     }
case P4_ON_ABORT: p4_longjmp_abort (); case P4_ON_QUIT: p4_longjmp_quit (); default: throw_msg (id, msg); if (addr)
{
             strcat (msg, " : ");
             if (! len)
                 strcat (msg, addr);
             else
             
{
                 msg[len+strlen(msg)] = '\0';
                 strncat (msg, addr, len);
             }
}
show_error (msg, 0); }
}
_export void
p4_throw (int id)
{
    p4_throws (id, 0, 0);
}
/*@}*/