version 1.4, 1997/08/22 19:23:20
|
version 1.36, 2009/06/29 20:21:28
|
Line 1
|
Line 1
|
/* direct key io driver; signal handler |
/* direct key io driver |
|
|
Copyright (C) 1995 Free Software Foundation, Inc. |
Copyright (C) 1995,1996,1997,1998,1999,2002,2003,2006,2007,2008 Free Software Foundation, Inc. |
|
|
This file is part of Gforth. |
This file is part of Gforth. |
|
|
Gforth is free software; you can redistribute it and/or |
Gforth is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public License |
modify it under the terms of the GNU General Public License |
as published by the Free Software Foundation; either version 2 |
as published by the Free Software Foundation, either version 3 |
of the License, or (at your option) any later version. |
of the License, or (at your option) any later version. |
|
|
This program is distributed in the hope that it will be useful, |
This program is distributed in the hope that it will be useful, |
Line 15
|
Line 15
|
GNU General Public License for more details. |
GNU General Public License for more details. |
|
|
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
along with this program; if not, see http://www.gnu.org/licenses/. |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
|
The following is stolen from the readline library for bash |
The following is stolen from the readline library for bash |
*/ |
*/ |
Line 26
|
Line 25
|
*/ |
*/ |
|
|
#include "config.h" |
#include "config.h" |
|
#include "forth.h" |
|
#include <sys/time.h> |
|
#include <sys/types.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
#if defined(apollo) || defined(_WIN32) |
#if defined(apollo) || defined(_WIN32) |
#define _POSIX_VERSION |
#define _POSIX_VERSION |
#endif |
#endif |
|
|
|
#if !defined(Solaris) && defined(sun) && defined(__svr4__) |
|
#define Solaris |
|
typedef unsigned int uint32_t; |
|
#endif |
|
|
|
#include <stdlib.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <signal.h> |
#include <signal.h> |
#include <string.h> |
#include <string.h> |
#include <sys/types.h> |
|
#if !defined(apollo) && !defined(MSDOS) |
#if !defined(apollo) && !defined(MSDOS) |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#endif |
#endif |
Line 45
|
Line 52
|
#include <sys/filio.h> |
#include <sys/filio.h> |
#endif |
#endif |
#include <setjmp.h> |
#include <setjmp.h> |
#include "forth.h" |
|
#include "io.h" |
#include "io.h" |
|
|
#ifndef MSDOS |
#ifndef MSDOS |
Line 85
|
Line 91
|
#endif /* !_POSIX_VERSION */ |
#endif /* !_POSIX_VERSION */ |
|
|
/* Posix systems use termios and the Posix signal functions. */ |
/* Posix systems use termios and the Posix signal functions. */ |
#if defined (_POSIX_VERSION) |
#if defined (_POSIX_VERSION) || defined (NeXT) |
# if !defined (TERMIOS_MISSING) |
# if !defined (TERMIOS_MISSING) |
# undef NEW_TTY_DRIVER |
# undef NEW_TTY_DRIVER |
# define TERMIOS_TTY_DRIVER |
# define TERMIOS_TTY_DRIVER |
# include <termios.h> |
# include <termios.h> |
# endif /* !TERMIOS_MISSING */ |
# endif /* !TERMIOS_MISSING */ |
|
#endif /* _POSIX_VERSION || NeXT */ |
|
|
|
#if defined (_POSIX_VERSION) |
# define HAVE_POSIX_SIGNALS |
# define HAVE_POSIX_SIGNALS |
# if !defined (O_NDELAY) |
# if !defined (O_NDELAY) |
# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */ |
# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */ |
Line 107
|
Line 116
|
special character is disabled and to disable certain special |
special character is disabled and to disable certain special |
characters. Posix systems should set to 0, USG systems to -1. */ |
characters. Posix systems should set to 0, USG systems to -1. */ |
#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE) |
#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE) |
# if defined (_POSIX_VERSION) |
# if defined (_POSIX_VERSION) || defined (NeXT) |
# define _POSIX_VDISABLE 0 |
# define _POSIX_VDISABLE 0 |
# else /* !_POSIX_VERSION */ |
# else /* !_POSIX_VERSION */ |
# define _POSIX_VDISABLE -1 |
# define _POSIX_VDISABLE -1 |
Line 438 void deprep_terminal ()
|
Line 447 void deprep_terminal ()
|
#define VTIME VEOL |
#define VTIME VEOL |
#endif |
#endif |
|
|
|
#include <locale.h> |
|
|
void prep_terminal () |
void prep_terminal () |
{ |
{ |
int tty = fileno (stdin); |
int tty = fileno (stdin); |
Line 463 void prep_terminal ()
|
Line 474 void prep_terminal ()
|
return; /* added by MdG */ |
return; /* added by MdG */ |
} /* added by MdG */ |
} /* added by MdG */ |
|
|
|
setlocale(LC_ALL, ""); |
|
setlocale(LC_NUMERIC, "C"); |
|
|
/* Try to keep this function from being INTerrupted. We can do it |
/* Try to keep this function from being INTerrupted. We can do it |
on POSIX and systems with BSD-like signal handling. */ |
on POSIX and systems with BSD-like signal handling. */ |
#if defined (HAVE_POSIX_SIGNALS) |
#if defined (HAVE_POSIX_SIGNALS) |
Line 604 void deprep_terminal ()
|
Line 618 void deprep_terminal ()
|
} |
} |
#endif /* NEW_TTY_DRIVER */ |
#endif /* NEW_TTY_DRIVER */ |
|
|
/* If a character is available to be read, then read it |
/* an ungetc() variant where we can know that there is a character waiting: |
and stuff it into IBUFFER. Otherwise, just return. */ |
gf_ungetc: like ungetc |
|
gf_regetc: call when reading a char, but does not get the character |
long pending = -1L; |
gf_ungottenc: true if there is a char waiting |
|
|
long key_avail (stream) |
|
FILE *stream; |
|
{ |
|
int tty = fileno (stream); |
|
int chars_avail = pending; |
|
int result; |
|
|
|
if(!terminal_prepped) prep_terminal(); |
Implementation: just an array containing all the FILEs with ungotten chars. |
|
Sequential search for membership checking (there should not be many elements) |
|
*/ |
|
|
#ifndef _WIN32 |
static FILE **ungotten_files = NULL; |
result = ioctl (tty, FIONREAD, &chars_avail); |
static size_t n_ungotten = 0; /* actual number */ |
#else |
static size_t max_ungotten = 0; /* buffer size */ |
{ |
|
fd_set selin; |
int gf_ungetc(int c, FILE *stream) |
static int now[2] = { 0 , 0 }; |
/* like ungetc, but works with the others */ |
int res; |
{ |
|
if (n_ungotten>=max_ungotten) { |
FD_ZERO(&selin); |
max_ungotten = max_ungotten*2+1; |
FD_SET(tty, &selin); |
ungotten_files = realloc(ungotten_files, max_ungotten*sizeof(FILE *)); |
chars_avail=select(1, &selin, NULL, NULL, now); |
|
} |
} |
#endif |
ungotten_files[n_ungotten++] = stream; |
|
return ungetc(c, stream); |
|
} |
|
|
if(chars_avail == -1L) |
static long search_ungotten(FILE *stream) |
{ unsigned char inchar; |
{ |
|
long i; |
|
for (i=0; i<n_ungotten; i++) |
|
if (ungotten_files[i] == stream) |
|
return i; |
|
return -1; |
|
} |
|
|
fcntl(tty, F_SETFL, O_NDELAY); |
void gf_regetc(FILE *stream) |
result = read(tty, &inchar, sizeof(char)); |
/* remove STREAM from ungotten_files */ |
if(result == sizeof(char)) |
{ |
{ |
long i = search_ungotten(stream); |
chars_avail = 1; |
if (i>=0) |
pending = (long)inchar; |
ungotten_files[i] = ungotten_files[--n_ungotten]; |
} |
} |
else |
|
chars_avail = 0; |
|
fcntl(tty, F_SETFL, 0); |
|
} |
|
|
|
return chars_avail; |
int gf_ungottenc(FILE *stream) |
|
/* true if stream has been ungotten */ |
|
{ |
|
return search_ungotten(stream)>=0; |
|
} |
|
|
|
long key_avail (FILE *stream) |
|
{ |
|
int tty = fileno (stream); |
|
fd_set selin; |
|
static struct timeval now = { 0 , 0 }; |
|
int chars_avail; |
|
|
|
setvbuf(stream, NULL, _IONBF, 0); |
|
if(!terminal_prepped && stream == stdin) |
|
prep_terminal(); |
|
if (gf_ungottenc(stream)) |
|
return 1; |
|
|
|
FD_ZERO(&selin); |
|
FD_SET(tty, &selin); |
|
chars_avail = select(1, &selin, NULL, NULL, &now); |
|
if (chars_avail > 0) { |
|
/* getc won't block */ |
|
int c = getc(stream); |
|
if (c==EOF) |
|
return 0; |
|
gf_ungetc(c, stream); |
|
} |
|
return (chars_avail == -1) ? 0 : chars_avail; |
} |
} |
|
|
/* Get a key from the buffer of characters to be read. |
/* Get a key from the buffer of characters to be read. |
Line 657 long key_avail (stream)
|
Line 698 long key_avail (stream)
|
/* When compiling and running in the `Posix' environment, Ultrix does |
/* When compiling and running in the `Posix' environment, Ultrix does |
not restart system calls, so this needs to do it. */ |
not restart system calls, so this needs to do it. */ |
|
|
unsigned char getkey(stream) |
Cell getkey(FILE * stream) |
FILE *stream; |
|
{ |
{ |
int result; |
Cell result; |
unsigned char c; |
unsigned char c; |
|
|
if(!terminal_prepped) prep_terminal(); |
setvbuf(stream, NULL, _IONBF, 0); |
|
if(!terminal_prepped && stream == stdin) |
while (pending < 0) |
prep_terminal(); |
{ |
|
result = read (fileno (stream), &c, sizeof (char)); |
|
|
|
if (result == sizeof (char)) |
|
return /* (c == 0x7F ? 0x08 :*/ c /*)*/; |
|
|
|
/* If zero characters are returned, then the file that we are |
result = fread(&c, sizeof(c), 1, stream); |
reading from is empty! Return EOF in that case. */ |
return result==0 ? (errno == EINTR ? 12 : 4) : c; |
if (result == 0) |
} |
return CTRL('D'); |
|
|
|
/* If the error that we received was SIGINT, then try again, |
|
this is simply an interrupted system call to read (). |
|
Otherwise, some error ocurred, also signifying EOF. */ |
|
if (errno != EINTR) |
|
return (EOF); |
|
} |
|
|
|
result = (int) pending; |
#ifdef STANDALONE |
pending = -1L; |
void emit_char(char x) |
|
{ |
|
putc(x, stdout); |
|
} |
|
|
return result; |
void type_chars(char *addr, unsigned int l) |
|
{ |
|
fwrite(addr, l, 1, stdout); |
} |
} |
|
#endif |
|
|
#ifdef TEST |
#ifdef TEST |
|
|
Line 731 int main()
|
Line 764 int main()
|
#endif |
#endif |
#endif /* MSDOS */ |
#endif /* MSDOS */ |
|
|
/* signal handling adapted from pfe by Dirk Zoller (Copylefted) - anton */ |
|
|
|
static void |
|
graceful_exit (int sig) |
|
{ |
|
deprep_terminal(); |
|
fprintf (stderr, "\n\n%s.\n", strsignal (sig)); |
|
exit (0x80|sig); |
|
} |
|
|
|
jmp_buf throw_jmp_buf; |
|
|
|
static void |
|
signal_throw(int sig) |
|
{ |
|
int code; |
|
struct { |
|
int signal; |
|
int throwcode; |
|
} *p, throwtable[] = { |
|
{ SIGINT, -28 }, |
|
{ SIGFPE, -55 }, |
|
#ifdef SIGBUS |
|
{ SIGBUS, -23 }, |
|
#endif |
|
{ SIGSEGV, -9 }, |
|
}; |
|
signal(sig,signal_throw); |
|
for (code=-256-sig, p=throwtable; p<throwtable+(sizeof(throwtable)/sizeof(*p)); p++) |
|
if (sig == p->signal) { |
|
code = p->throwcode; |
|
break; |
|
} |
|
longjmp(throw_jmp_buf,code); /* or use siglongjmp ? */ |
|
} |
|
|
|
UCell cols=80; |
|
#if defined(MSDOS) || defined (_WIN32) |
|
UCell rows=25; |
|
#else |
|
UCell rows=24; |
|
#endif |
|
|
|
#ifdef SIGCONT |
|
static void termprep (int sig) |
|
{ |
|
signal(sig,termprep); |
|
terminal_prepped=0; |
|
} |
|
#endif |
|
|
|
#ifdef SIGWINCH |
|
void get_winsize() |
|
{ |
|
#ifdef TIOCGWINSZ |
|
struct winsize size; |
|
|
|
if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) { |
|
rows = size.ws_row; |
|
cols = size.ws_col; |
|
} |
|
#else |
|
char *s, *ends; |
|
unsigned long ul; |
|
if (s=getenv("LINES")) { |
|
rows=atoi(s); |
|
if (rows==0) |
|
rows=24; |
|
} |
|
if (s=getenv("COLUMNS")) { |
|
rows=atoi(s); |
|
if (rows==0) |
|
cols=80; |
|
} |
|
#endif |
|
} |
|
|
|
static void change_winsize(int sig) |
|
{ |
|
signal(sig,change_winsize); |
|
#ifdef TIOCGWINSZ |
|
get_winsize(); |
|
#endif |
|
} |
|
#endif |
|
|
|
void install_signal_handlers (void) |
|
{ |
|
|
|
#if 0 |
|
/* these signals are handled right by default, no need to handle them; |
|
they are listed here just for fun */ |
|
static short sigs_to_default [] = { |
|
#ifdef SIGCHLD |
|
SIGCHLD, |
|
#endif |
|
#ifdef SIGINFO |
|
SIGINFO, |
|
#endif |
|
#ifdef SIGIO |
|
SIGIO, |
|
#endif |
|
#ifdef SIGLOST |
|
SIGLOST, |
|
#endif |
|
#ifdef SIGKILL |
|
SIGKILL, |
|
#endif |
|
#ifdef SIGSTOP |
|
SIGSTOP, |
|
#endif |
|
#ifdef SIGPWR |
|
SIGPWR, |
|
#endif |
|
#ifdef SIGMSG |
|
SIGMSG, |
|
#endif |
|
#ifdef SIGDANGER |
|
SIGDANGER, |
|
#endif |
|
#ifdef SIGMIGRATE |
|
SIGMIGRATE, |
|
#endif |
|
#ifdef SIGPRE |
|
SIGPRE, |
|
#endif |
|
#ifdef SIGVIRT |
|
SIGVIRT, |
|
#endif |
|
#ifdef SIGGRANT |
|
SIGGRANT, |
|
#endif |
|
#ifdef SIGRETRACT |
|
SIGRETRACT, |
|
#endif |
|
#ifdef SIGSOUND |
|
SIGSOUND, |
|
#endif |
|
#ifdef SIGSAK |
|
SIGSAK, |
|
#endif |
|
#ifdef SIGTSTP |
|
SIGTSTP, |
|
#endif |
|
#ifdef SIGTTIN |
|
SIGTTIN, |
|
#endif |
|
#ifdef SIGTTOU |
|
SIGTTOU, |
|
#endif |
|
#ifdef SIGSTKFLT |
|
SIGSTKFLT, |
|
#endif |
|
#ifdef SIGUNUSED |
|
SIGUNUSED, |
|
#endif |
|
}; |
|
#endif |
|
|
|
static short sigs_to_throw [] = { |
|
#ifdef SIGBREAK |
|
SIGBREAK, |
|
#endif |
|
#ifdef SIGINT |
|
SIGINT, |
|
#endif |
|
#ifdef SIGILL |
|
SIGILL, |
|
#endif |
|
#ifdef SIGEMT |
|
SIGEMT, |
|
#endif |
|
#ifdef SIGFPE |
|
SIGFPE, |
|
#endif |
|
#ifdef SIGIOT |
|
SIGIOT, |
|
#endif |
|
#ifdef SIGSEGV |
|
SIGSEGV, |
|
#endif |
|
#ifdef SIGALRM |
|
SIGALRM, |
|
#endif |
|
#ifdef SIGPIPE |
|
SIGPIPE, |
|
#endif |
|
#ifdef SIGPOLL |
|
SIGPOLL, |
|
#endif |
|
#ifdef SIGPROF |
|
SIGPROF, |
|
#endif |
|
#ifdef SIGBUS |
|
SIGBUS, |
|
#endif |
|
#ifdef SIGSYS |
|
SIGSYS, |
|
#endif |
|
#ifdef SIGTRAP |
|
SIGTRAP, |
|
#endif |
|
#ifdef SIGURG |
|
SIGURG, |
|
#endif |
|
#ifdef SIGUSR1 |
|
SIGUSR1, |
|
#endif |
|
#ifdef SIGUSR2 |
|
SIGUSR2, |
|
#endif |
|
#ifdef SIGVTALRM |
|
SIGVTALRM, |
|
#endif |
|
#ifdef SIGXFSZ |
|
SIGXFSZ, |
|
#endif |
|
}; |
|
static short sigs_to_quit [] = { |
|
#ifdef SIGHUP |
|
SIGHUP, |
|
#endif |
|
#ifdef SIGQUIT |
|
SIGQUIT, |
|
#endif |
|
#ifdef SIGABRT |
|
SIGABRT, |
|
#endif |
|
#ifdef SIGTERM |
|
SIGTERM, |
|
#endif |
|
#ifdef SIGXCPU |
|
SIGXCPU, |
|
#endif |
|
}; |
|
int i; |
|
|
|
#define DIM(X) (sizeof (X) / sizeof *(X)) |
|
/* |
|
for (i = 0; i < DIM (sigs_to_ignore); i++) |
|
signal (sigs_to_ignore [i], SIG_IGN); |
|
*/ |
|
for (i = 0; i < DIM (sigs_to_throw); i++) |
|
signal (sigs_to_throw [i], signal_throw); |
|
for (i = 0; i < DIM (sigs_to_quit); i++) |
|
signal (sigs_to_quit [i], graceful_exit); |
|
#ifdef SIGCONT |
|
signal (SIGCONT, termprep); |
|
#endif |
|
#ifdef SIGWINCH |
|
signal (SIGWINCH, change_winsize); |
|
#endif |
|
} |
|
/* end signal handling */ |
|