/*
    Clif - A C-like Interpreter Framework
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997 T. Hruz, L. Koren
    1998 L. Koren

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

/*
 * sig-bsd.c
 *
 * Functions for framework interrupt handling.
 */

#include "global.h"
#include "config.h"
#include <stdio.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <termio.h>
#include <fcntl.h>
#include <setjmp.h>

#define OFF(x, y) (x) & (~(y))
#define ON(x, y) (x) | (y)
#define SPACE 0x20
#define NL '\n'

int handler = 0;
int handle_fd;
struct termio term, term_initial;
struct sigvec vec, ovec;

RETSIGTYPE (*interrupt_handler) PROTO((void));
RETSIGTYPE interrupt_service PROTO((void));
void interrupt_register PROTO((void));
void term_restore PROTO((void));

RETSIGTYPE fatal_handler PROTO((void));
void fatal_handler_register PROTO((void));
extern jmp_buf jmpbuf;
extern int error_count;

/* \verbatim{sig_bsd_c_interrupt_service.tex} */

/*
 * Asynchronous interrupt service.
 */
RETSIGTYPE
interrupt_service ()
{
#ifdef DEBUG_INTER 
  printfx ("interrupt\n");
#endif
  if ((clif_interrupt_level > 0) || (!virtual_machine_suspended))

/* 
 * Test of the virtual machine running and the level of interrupt.
 * An interrupt is only accepted if the virtual machine is running.
 */

    {
#ifdef DEBUG_INTER 
      printfx ("virtual machine is running, interrupt accepted\n");
#endif
      handler = 1;
#ifdef HAVE_TIOCSTI
      ioctl (handle_fd, TIOCSTI, "\n");
#endif
    }
  return;
}
/* \verbatim */


/* \verbatim{sig_bsd_c_interrupt_handler.tex} */

/*
 * Registers interrupt handler.
 */
void
interrupt_register ()
{
  interrupt_handler = interrupt_service;
  handle_fd = fileno (stdin);
  ioctl (handle_fd, TCGETA, &term);
  term_initial = term;
  term.c_cc[0] = 0x14;		/* DC4 */
  term.c_cc[5] = 0x12;		/* DC2 */
  ioctl (handle_fd, TCSETA, &term);
  vec.sv_handler = interrupt_handler;
  sigvec (SIGINT, &vec, &ovec);
}

/* \verbatim */


/*
 * Synchronous interrupt service.
 */
void 
interrupt_service_sync ()
{
  handler = 1;
}


/*
 * Restores setting of the terminal at the termination of Clif session.
 */
void
term_restore ()
{
  ioctl (handle_fd, TCSETA, &term_initial);
}

RETSIGTYPE
fatal_handler ()
{
  if (error_count)
    longjmp (jmpbuf, 1);
  {
    struct sigvec vec, ovec;
    vec.sv_handler = SIG_DFL;
    sigvec (SIGFPE, &vec, &ovec);
    sigvec (SIGSEGV, &vec, &ovec);
  }
}

void
fatal_handler_register ()
{
  struct sigvec vec, ovec;
  
  vec.sv_handler = fatal_handler;

  if (sigvec (SIGFPE, &vec, &ovec) < 0)
    error_message (4004);
  if (sigvec (SIGSEGV, &vec, &ovec) < 0)
    error_message (4004);
}
