--- gforth/engine/io.c 2008/08/09 13:24:25 1.33 +++ gforth/engine/io.c 2009/06/30 19:22:24 1.38 @@ -1,6 +1,6 @@ /* direct key io driver - Copyright (C) 1995,1996,1997,1998,1999,2002,2003,2006,2007 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. @@ -39,6 +39,7 @@ typedef unsigned int uint32_t; #endif +#include #include #include #include @@ -617,19 +618,77 @@ void deprep_terminal () } #endif /* NEW_TTY_DRIVER */ -long key_avail (FILE * stream) +/* 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) { 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); - return select(1, &selin, NULL, NULL, &now); + 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. @@ -644,11 +703,14 @@ Cell getkey(FILE * stream) Cell result; unsigned char c; - setvbuf(stream, NULL, _IONBF, 0); + if (!gf_ungottenc(stream)) + setvbuf(stream, NULL, _IONBF, 0); if(!terminal_prepped && stream == stdin) prep_terminal(); result = fread(&c, sizeof(c), 1, stream); + if (result>0) + gf_regetc(stream); return result==0 ? (errno == EINTR ? 12 : 4) : c; }