/* C K U S I G  --  Kermit signal handling for Unix and OS/2 systems */

/*
  Author: Jeffrey Altman (jaltman@columbia.edu),
  Columbia University Academic Information Systems, New York City.

  Copyright (C) 1985, 2000,
    Trustees of Columbia University in the City of New York.
    All rights reserved.  See the C-Kermit COPYING.TXT file or the
    copyright text in the ckcmai.c module for disclaimer and permissions.
*/
#include "ckcsym.h"
#include "ckcasc.h"			/* ASCII character symbols */
#include "ckcdeb.h"			/* Debug & other symbols */
#include "ckcker.h"			/* Kermit symbols */
#include "ckcnet.h"			/* Network symbols */
#ifndef NOSPL
#include "ckuusr.h"
#endif /* NOSPL */

#include <signal.h>
#ifdef NT
#include <setjmpex.h>
#include <excpt.h>
#else /* NT */
#include <setjmp.h>
#endif /* NT */
#include "ckcsig.h"

#ifdef NOCCTRAP
extern ckjmpbuf cmjbuf;
#endif /* NOCCTRAP */

#ifdef MAC
#define signal msignal
#define SIGTYP long
#define alarm malarm
#define SIG_IGN 0
#define SIGALRM 1
#define SIGINT  2
SIGTYP (*msignal(int type, SIGTYP (*func)(int)))(int);
#endif /* MAC */

#ifdef STRATUS
/* We know these are set here.  MUST unset them before the definitions. */
#define signal vsignal
#define alarm valarm
SIGTYP (*vsignal(int type, SIGTYP (*func)(int)))(int);
int valarm(int interval);
#endif /* STRATUS */

#ifdef AMIGA
#define signal asignal
#define alarm aalarm
#define SIGALRM (_NUMSIG+1)
#define SIGTYP void
SIGTYP (*asignal(int type, SIGTYP (*func)(int)))(int);
unsigned aalarm(unsigned);
#endif /* AMIGA */

#ifdef NTASM
DWORD
ckgetIP(void)
{
   __asm
   {
      mov eax, dword ptr [esp+0x10]
      jmp ckgetIP + 0x18
   }
   return 1;

}
#endif /* NTASM */

#ifdef NT
DWORD
exception_filter( void )
{
   GetExceptionInformation ;
   return( EXCEPTION_EXECUTE_HANDLER ) ;
}
void
crash( void )
{
   int x = 0, y = 0 ;
    x / y ;
}
#endif /* NT */

#ifndef NOCCTRAP
int
#ifdef CK_ANSIC
cc_execute( ckjptr(sj_buf), ck_sigfunc dofunc, ck_sigfunc failfunc )
#else
cc_execute( sj_buf, dofunc, failfunc)
    ckjptr(sj_buf);
    ck_sigfunc dofunc;
    ck_sigfunc failfunc;
#endif /* CK_ANSIC */
/* cc_execute */ {
    int rc = 0 ;
#ifdef NTASM
   DWORD Eip, Esp ;
    isinterrupted = 0;
    sj_buf->retcode = 0 ;
    sj_buf->Id = GetCurrentThreadId() ;
    memset( &sj_buf->context, 0, sizeof(CONTEXT) );
    sj_buf->context.ContextFlags = CONTEXT_FULL ;
#ifndef COMMENT
    GetThreadContext(GetCurrentThread(), &(sj_buf->context) ) ;
    __asm
    {
          mov       ecx,dword ptr [sj_buf]
          mov       dword ptr [ecx+0xc4],esp
    }
   sj_buf->context.EFlags = 530 ;
   sj_buf->context.Eip = ckgetIP()+0x0C ;
#else /* COMMENT */
   __asm
   {
      mov eax, dword ptr [sj_buf]
      push eax
      mov eax, 0xfffffffe
      push eax
      mov eax, 0x00000039
      mov edx,esp
      int 0x2e
      pop eax
      pop eax
   }
#endif /* COMMENT */
#endif /* NTASM */
    if (
#ifdef NTASM
         isinterrupted
#else
		 cksetjmp(ckjdref(sj_buf))
#endif /* NTASM */
		 ) {
#ifdef NTASM
          __asm
            {
                mov esp, ESPToRestore
            }
            isinterrupted = 0 ;
#endif /* NTASM */
            (*failfunc)(NULL) ;
#ifdef NTASM
             rc = sj_buf->retcode ;
#else /* NTASM */
             rc = -1 ;
#endif  /* NTASM */
         } else {
#ifdef NT
            __try {
               (*dofunc)(NULL);
            }
            __except(exception_filter())
            {
               debug(F100,"cc_execute __except","",0);
               debug(F111,
		     "exception_filter",
		     "_exception_code",
		     etExceptionCode()
		     );
               longjmp(ckjdref(sj_buf),SIGINT);
            }
#else /* NT */
            (*dofunc)(NULL);
#endif /* NT */
         }
   return rc ;
}
#endif /* NOCCTRAP */

int
#ifdef CK_ANSIC				/* ANSIC C declaration... */
alrm_execute(ckjptr(sj_buf),
	     int timo,
	     ck_sighand handler,
	     ck_sigfunc dofunc,
	     ck_sigfunc failfunc
	     )

#else /* Not ANSIC C ... */

alrm_execute(sj_buf,
	     timo,
	     handler,
	     dofunc,
	     failfunc
	     )
    ckjptr(sj_buf);
    int timo;
    ck_sighand handler;
    ck_sigfunc dofunc;
    ck_sigfunc failfunc;
#endif /* CK_ANSIC */

/* alrm_execute */ {

    int rc = 0;
    int savalrm = 0;
_PROTOTYP(SIGTYP (*savhandler), (int));

    savalrm = alarm(timo);
    savhandler = signal(SIGALRM, handler);

#ifdef NTASM
    sj_buf->retcode = 0 ;
    sj_buf->Id = GetCurrentThreadId();
    memset(&sj_buf->context, 0, sizeof(CONTEXT));
    sj_buf->context.ContextFlags = CONTEXT_FULL;
#ifndef COMMENT
    GetThreadContext(GetCurrentThread(), &(sj_buf->context));
#else
   __asm
   {
      mov eax, dword ptr [sj_buf]
      push eax
      mov eax, 0xfffffffe
      push eax
      mov eax, 0x00000039
      mov edx,esp
      int 0x2e
      pop eax
      pop eax
   }
#endif
    isinterrupted = 0;
#endif /* NTASM */
    if (
#ifdef NTASM
		 sj_buf->retcode
#else
		 cksetjmp(ckjdref(sj_buf))
#endif /* NTASM */
		) {
	(*failfunc)(NULL) ;
	rc = -1 ;
    } else {
#ifdef NT
       __try {
          (*dofunc)(NULL) ;
       }
       __except( exception_filter() )
       {
          debug(F100,"alrm_execute __except","",0);
          debug(F111,"exception_filter",
		"_exception_code",
		GetExceptionCode()
		);
          longjmp(ckjdref(sj_buf),SIGINT);
       }
#else /* NT */
       (*dofunc)(NULL) ;
#endif /* NT */
    }
    alarm(savalrm) ;
    if ( savhandler )
        signal( SIGALRM, savhandler ) ;
    return rc ;
}

int
#ifdef CK_ANSIC				/* ANSIC C declaration... */
cc_alrm_execute(ckjptr(sj_buf),
		int timo,
		ck_sighand handler,
		ck_sigfunc dofunc,
		ck_sigfunc failfunc
		)

#else /* Not ANSIC C ... */

cc_alrm_execute(sj_buf,
	     timo,
	     handler,
	     dofunc,
	     failfunc
	     )
    ckjptr(sj_buf);
    int timo;
    ck_sighand handler;
    ck_sigfunc dofunc;
    ck_sigfunc failfunc;
#endif /* CK_ANSIC */

/* cc_alrm_execute */ {

    int rc = 0;
    int savalrm = 0;
_PROTOTYP(SIGTYP (*savhandler), (int));
    savalrm = alarm(timo);
    savhandler = signal( SIGALRM, handler );

#ifdef NTASM
    sj_buf->retcode = 0 ;
    sj_buf->Id = GetCurrentThreadId() ;
    memset( &sj_buf->context, 0, sizeof(CONTEXT) );
    sj_buf->context.ContextFlags = CONTEXT_FULL ;
#ifndef COMMENT
    GetThreadContext( GetCurrentThread(), &(sj_buf->context) ) ;
#else
   __asm
   {
      mov eax, dword ptr [sj_buf]
      push eax
      mov eax, 0xfffffffe
      push eax
      mov eax, 0x00000039
      mov edx,esp
      int 0x2e
      pop eax
      pop eax
   }
#endif
    isinterrupted = 0;
#endif /* NTASM */
    if (
#ifdef NTASM
		 sj_buf->retcode
#else
		 cksetjmp(ckjdref(sj_buf))
#endif /* NTASM */
		) {
	(*failfunc)(NULL) ;
	rc = -1 ;
    } else {
#ifdef NT
       __try {
          (*dofunc)(NULL) ;
       }
       __except( exception_filter() )
       {
	   debug(F100,"cc_alrm_execute __except","",0);
	   debug(F111,
		 "exception_filter",
		 "_exception_code",
		 GetExceptionCode()
		 );
	   longjmp(ckjdref(sj_buf),SIGINT) ;
       }
#else /* NT */
       (*dofunc)(NULL) ;
#endif /* NT */
    }
    alarm(savalrm);
    if (savhandler)
      signal(SIGALRM,savhandler);
    return(rc);
}
