--- gforth/engine/io.c 2003/03/09 15:17:03 1.16 +++ gforth/engine/io.c 2009/12/31 15:32:36 1.39 @@ -1,12 +1,12 @@ /* direct key io driver - Copyright (C) 1995,1996,1997,1998,1999,2002 Free Software Foundation, Inc. + Copyright (C) 1995,1996,1997,1998,1999,2002,2003,2006,2007,2008,2009 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + along with this program; if not, see http://www.gnu.org/licenses/. The following is stolen from the readline library for bash */ @@ -40,6 +39,7 @@ typedef unsigned int uint32_t; #endif +#include #include #include #include @@ -447,6 +447,8 @@ void deprep_terminal () #define VTIME VEOL #endif +#include + void prep_terminal () { int tty = fileno (stdin); @@ -472,6 +474,9 @@ void prep_terminal () return; /* 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 on POSIX and systems with BSD-like signal handling. */ #if defined (HAVE_POSIX_SIGNALS) @@ -613,50 +618,77 @@ 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 -long pending = -1L; + Implementation: just an array containing all the FILEs with ungotten chars. + Sequential search for membership checking (there should not be many elements) +*/ -long key_avail (FILE * stream) +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 */ { - int tty = fileno (stream); - int chars_avail = pending; - int result; + 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); +} - if(!terminal_prepped) prep_terminal(); +static long search_ungotten(FILE *stream) +{ + long i; + for (i=0; i=0) + ungotten_files[i] = ungotten_files[--n_ungotten]; +} - 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; + + if (gf_ungottenc(stream)) + return 1; + setvbuf(stream, NULL, _IONBF, 0); + if(!terminal_prepped && stream == stdin) + prep_terminal(); + + 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. @@ -671,35 +703,28 @@ Cell getkey(FILE * stream) Cell result; unsigned char c; - if(!terminal_prepped) + if (!gf_ungottenc(stream)) + setvbuf(stream, NULL, _IONBF, 0); + if(!terminal_prepped && stream == stdin) prep_terminal(); - while (pending < 0) - { - 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 - reading from is empty! Return EOF in that case. */ - if (result == 0) - return (EOF); - - /* 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; +} - /* otherwise there is a character pending; - return it and delete pending char */ - result = (Cell) 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