--- gforth/engine/io.c 1998/10/18 23:16:52 1.7 +++ gforth/engine/io.c 2012/12/31 15:25:19 1.45 @@ -1,12 +1,12 @@ -/* 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,2009,2010,2012 Free Software Foundation, Inc. This file is part of Gforth. Gforth 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 + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,8 +15,7 @@ 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. + along with this program; if not, see http://www.gnu.org/licenses/. The following is stolen from the readline library for bash */ @@ -26,6 +25,7 @@ */ #include "config.h" +#include "forth.h" #include #include #include @@ -39,6 +39,7 @@ typedef unsigned int uint32_t; #endif +#include #include #include #include @@ -51,10 +52,10 @@ typedef unsigned int uint32_t; #include #endif #include -#include "forth.h" #include "io.h" #ifndef MSDOS +#include #if defined (__GNUC__) # define alloca __builtin_alloca #else @@ -613,50 +614,83 @@ void deprep_terminal () } #endif /* NEW_TTY_DRIVER */ -/* If a character is available to be read, then read it - and stuff it into IBUFFER. Otherwise, just return. */ +/* an ungetc() variant where we can know that there is a character waiting: + gf_ungetc: like ungetc + gf_regetc: call when reading a char, but does not get the character + gf_ungottenc: true if there is a char waiting + + Implementation: just an array containing all the FILEs with ungotten chars. + Sequential search for membership checking (there should not be many elements) +*/ + +static FILE **ungotten_files = NULL; +static size_t n_ungotten = 0; /* actual number */ +static size_t max_ungotten = 0; /* buffer size */ + +int gf_ungetc(int c, FILE *stream) +/* like ungetc, but works with the others */ +{ + if (n_ungotten>=max_ungotten) { + max_ungotten = max_ungotten*2+1; + ungotten_files = realloc(ungotten_files, max_ungotten*sizeof(FILE *)); + } + ungotten_files[n_ungotten++] = stream; + return ungetc(c, stream); +} + +static long search_ungotten(FILE *stream) +{ + long i; + for (i=0; i=0) + ungotten_files[i] = ungotten_files[--n_ungotten]; +} + +int gf_ungottenc(FILE *stream) +/* true if stream has been ungotten */ +{ + return search_ungotten(stream)>=0; +} -long key_avail (FILE * stream) +long key_avail (FILE *stream) { int tty = fileno (stream); - int chars_avail = pending; - int result; + struct pollfd fds = { tty, POLLIN, 0 }; + int chars_avail; - if(!terminal_prepped) prep_terminal(); + if (gf_ungottenc(stream)) + return 1; + setvbuf(stream, NULL, _IONBF, 0); + if(!terminal_prepped && stream == stdin) + prep_terminal(); -#ifndef _WIN32 +#if defined(FIONREAD) && !defined(_WIN32) if(isatty (tty)) { - result = ioctl (tty, FIONREAD, &chars_avail); - } -#else + int result = ioctl (tty, FIONREAD, &chars_avail); + } else +#endif { - fd_set selin; - static int now[2] = { 0 , 0 }; - int res; - - FD_ZERO(&selin); - FD_SET(tty, &selin); - chars_avail=select(1, &selin, NULL, NULL, now); + chars_avail = poll(&fds, 1, 0); } -#endif - - if(chars_avail == -1L) { - unsigned char inchar; - - fcntl(tty, F_SETFL, O_NDELAY); - result = read(tty, &inchar, sizeof(char)); - if(result == sizeof(char)) { - chars_avail = 1; - pending = (long)inchar; - } else { - chars_avail = 0; - } - fcntl(tty, F_SETFL, 0); +#ifndef __ANDROID__ + if (chars_avail > 0) { + /* getc won't block */ + int c = getc(stream); + if (c==EOF) + return 0; + gf_ungetc(c, stream); } - - return chars_avail; +#endif + return (chars_avail == -1) ? 0 : chars_avail; } /* Get a key from the buffer of characters to be read. @@ -666,37 +700,33 @@ long key_avail (FILE * stream) /* When compiling and running in the `Posix' environment, Ultrix does not restart system calls, so this needs to do it. */ -unsigned char getkey(FILE * stream) +Cell getkey(FILE * stream) { - int result; + Cell result; unsigned char c; - if(!terminal_prepped) prep_terminal(); - - while (pending < 0) - { - result = read (fileno (stream), &c, sizeof (char)); - - if (result == sizeof (char)) - return /* (c == 0x7F ? 0x08 :*/ c /*)*/; + if (!gf_ungottenc(stream)) + setvbuf(stream, NULL, _IONBF, 0); + if(!terminal_prepped && stream == stdin) + prep_terminal(); - /* If zero characters are returned, then the file that we are - reading from is empty! Return EOF in that case. */ - 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 = fread(&c, sizeof(c), 1, stream); + if (result>0) + gf_regetc(stream); + return result==0 ? (errno == EINTR ? 12 : 4) : c; +} - result = (int) pending; - pending = -1L; +#ifdef STANDALONE +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 @@ -739,257 +769,3 @@ int main() #endif #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; psignal) { - 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], die_on_signal ? graceful_exit : 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 */