#ifndef lint
static char *RCSid = "$Header: /auto/home/flipper/anders/flipper/prosj/rexx/src/RCS/signals.c,v 1.4 1993/05/10 06:04:52 anders Exp anders $";
#endif

/*
 *  The Regina Rexx Interpreter
 *  Copyright (C) 1992-1994  Anders Christensen <anders@pvv.unit.no>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "rexx.h"
#include <signal.h>
#include <string.h>
#include <stdio.h>

#ifdef VMS
# ifndef SIG_ERR
#  define SIG_ERR BADSIG
# endif
#endif

/* at least dolphin does not have a properly ANSI C set of include files */
#ifndef SIG_ERR
# define SIG_ERR ((void(*)())(-1))
#endif



extern proclevel currlevel ;

char *signalnames[] = {
   "ERROR",
   "FAILURE",
   "HALT",
   "NOVALUE",
   "NOTREADY",
   "SYNTAX" 
} ;

sigtype *nextsig = NULL ; 


#ifdef TRACEMEM
void mark_signals()
{
    if (nextsig)
    {
       markmemory( nextsig, TRC_MATH ) ;
       if (nextsig->descr)
          markmemory( nextsig->descr, TRC_MATH ) ;
    }
}
#endif


static trap *dupltraps( trap *traps ) 
{
   trap *ptr=NULL ;
   int i=0 ;
  
   ptr = Malloc(sizeof(trap) * SIGNALS) ;
   /* Stupid SunOS acc gives incorrect warning for the next line */
   memcpy( ptr, traps, sizeof(trap) * SIGNALS) ;
   for ( i=0; i<SIGNALS; i++ )
      if (traps[i].name)
         ptr[i].name = Str_dup( traps[i].name ) ;
      

   return ptr ;
}


sigtype *getsigs( proclevel level ) 
{
   for (; level && (!level->sig); level=level->prev ) ;
   return ((level) ? (level->sig) : (NULL)) ;
}

jmp_buf *getjmpbuf( proclevel level )
{
   for (; level && level->buf; level=level->prev ) ;
   return ((level) ? (level->buf) : (NULL)) ;
}
   

trap *gettraps( proclevel level ) 
{
   proclevel ptr=level ;

   if (!ptr->traps)
   {
      for (ptr=level; ptr && ptr->traps==NULL; ptr=ptr->prev ) ;
      if (ptr==NULL || ptr->traps==NULL)
          exiterror( ERR_INTERPRETER_FAILURE, 0 )  ;

      level->traps = dupltraps( ptr->traps ) ;
      ptr = level ;
   }

   return ptr->traps ;
}


int condition_hook( int type, int errorno, int lineno, streng *description )
{
   extern proclevel currlevel ;
   extern nodeptr currentnode ;
   trap *traps = gettraps( currlevel ) ;
/*   volatile sigtype **sigptr=((volatile sigtype **)(&nextsig)) ; */
   sigtype *sigptr=NULL ;

   /* if we dont know what to do, ... or */
   /* if we don't *really* want to try to recover from these ... */
   if (traps==NULL || type == SIGNAL_FATAL) 
   {
      if (description)
         Free_string( description ) ;       
      return 0 ;
   }

   if (lineno==(-1))
      if (currentnode)
         lineno = currentnode->lineno ;
      else
#ifdef NDEBUG
         lineno = 0 ;
#else
          exiterror( ERR_INTERPRETER_FAILURE, 0 )  ;
#endif

   if ( traps[type].on_off) /* condition is being trapped */
   {
      static streng sigl = { 4, 4, { 'S', 'I', 'G', 'L' }};
      static streng rc = { 4, 2, "RC" } ;
      
      if ((traps[type].delayed) && (traps[type].ignored))
      {
         if (description)
            Free_string( description ) ;
         return 0 ;
      }

      sigptr = Malloc( sizeof( sigtype )) ;

      sigptr->type = type ;
      sigptr->info = NULL ;   /* BUG: I don't really think this is used */
      sigptr->descr = description ;
      sigptr->invoke = traps[type].invoked ;
      sigptr->rc = errorno ;
      sigptr->lineno = lineno ; 

      if ( traps[type].invoked )   /* if SIGNAL ON */
      {
      /* traps[type].on_off = 0 ;  */ /* turn trap off */
      /* traps[type].trapped = 0 ; */ /* unecessary, just to be sure */
         traps[type].delayed = 0 ;    /* ... ditto ... */
         setvalue( &sigl, int_to_streng( lineno )) ;
         if (type == SIGNAL_SYNTAX)
            setvalue( &rc, int_to_streng( errorno )) ;  /* special condition */

         nextsig = sigptr ;

         longjmp( *(currlevel->buf), 1 ) ;
         abort() ;
      }
      else
      {
        nextsig = sigptr ;
        return 1 ;
      }
   }

   if (description)
      Free_string(description) ;

   /* signal is not to be trapped */
   return (traps[type].def_act) ;
}


int identify_trap( int type ) 
{
   switch (type)
   {
      case X_S_HALT:     return SIGNAL_HALT ;
      case X_S_SYNTAX:   return SIGNAL_SYNTAX ;
      case X_S_NOVALUE:  return SIGNAL_NOVALUE ;
      case X_S_NOTREADY: return SIGNAL_NOTREADY ;
      case X_S_ERROR:    return SIGNAL_ERROR ;
      case X_S_FAILURE:  return SIGNAL_FAILURE ; 
   }
    exiterror( ERR_INTERPRETER_FAILURE, 0 )  ;
   return SIGNAL_FATAL ;
}


/* the rest should probably also be defined */
char *signals_names[] = {
     "", "SIGHUP", "SIGINT", "", "", "", "", "", "", "",
     "", "", "", "", "", "SIGTERM", "", "", "", "", "",
     "", "", "", "", "", "", "", "", "", "",
     "", "" 
} ;


/* Yuk! Some of these should *really* have been volatilized */
static void halt_handler( int num )
{
   extern nodeptr currentnode ;

#ifdef VMS
   vms_killproc() ;
#endif

   if (signal( num, halt_handler ) == SIG_ERR)
       exiterror( ERR_SYSTEM_FAILURE, 0 )  ;

   if (!condition_hook(SIGNAL_HALT, ERR_PROG_INTERRUPT, 
               lineno_of(currentnode), Str_cre(signals_names[num])))
       exiterror( ERR_PROG_INTERRUPT, 0 )  ;
 
   return ;
}

static void hup_handler( int num ) 
{
   exit( 0 ) ;
}



void signal_setup( void )
{
   extern int isclient ;

   if (signal( SIGTERM, halt_handler ) == SIG_ERR)
       exiterror( ERR_SYSTEM_FAILURE, 0 )  ;

   if (signal( SIGINT, halt_handler) == SIG_ERR)
       exiterror( ERR_SYSTEM_FAILURE, 0 )  ;
#if defined(SIGHUP)                                     /* MH 10-06-96 */
   if (signal( SIGHUP, (isclient)?(hup_handler):(halt_handler)) == SIG_ERR)
       exiterror( ERR_SYSTEM_FAILURE, 0 )  ;
#endif                                                  /* MH 10-06-96 */

}

void set_rexx_halt( void )
{
   halt_handler( SIGINT );
}


