version 1.33, 2008/08/09 13:24:25
|
version 1.45, 2012/12/31 15:25:19
|
Line 1
|
Line 1
|
/* direct key io driver |
/* 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,2009,2010,2012 Free Software Foundation, Inc. |
|
|
This file is part of Gforth. |
This file is part of Gforth. |
|
|
Line 39
|
Line 39
|
typedef unsigned int uint32_t; |
typedef unsigned int uint32_t; |
#endif |
#endif |
|
|
|
#include <stdlib.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <signal.h> |
#include <signal.h> |
#include <string.h> |
#include <string.h> |
Line 54 typedef unsigned int uint32_t;
|
Line 55 typedef unsigned int uint32_t;
|
#include "io.h" |
#include "io.h" |
|
|
#ifndef MSDOS |
#ifndef MSDOS |
|
#include <poll.h> |
#if defined (__GNUC__) |
#if defined (__GNUC__) |
# define alloca __builtin_alloca |
# define alloca __builtin_alloca |
#else |
#else |
Line 446 void deprep_terminal ()
|
Line 448 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 473 void prep_terminal ()
|
Line 473 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 617 void deprep_terminal ()
|
Line 614 void deprep_terminal ()
|
} |
} |
#endif /* NEW_TTY_DRIVER */ |
#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<n_ungotten; i++) |
|
if (ungotten_files[i] == stream) |
|
return i; |
|
return -1; |
|
} |
|
|
|
void gf_regetc(FILE *stream) |
|
/* remove STREAM from ungotten_files */ |
|
{ |
|
long i = search_ungotten(stream); |
|
if (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); |
int tty = fileno (stream); |
fd_set selin; |
struct pollfd fds = { tty, POLLIN, 0 }; |
static struct timeval now = { 0 , 0 }; |
int chars_avail; |
|
|
|
if (gf_ungottenc(stream)) |
|
return 1; |
setvbuf(stream, NULL, _IONBF, 0); |
setvbuf(stream, NULL, _IONBF, 0); |
if(!terminal_prepped && stream == stdin) |
if(!terminal_prepped && stream == stdin) |
prep_terminal(); |
prep_terminal(); |
|
|
FD_ZERO(&selin); |
#if defined(FIONREAD) && !defined(_WIN32) |
FD_SET(tty, &selin); |
if(isatty (tty)) { |
return select(1, &selin, NULL, NULL, &now); |
int result = ioctl (tty, FIONREAD, &chars_avail); |
|
} else |
|
#endif |
|
{ |
|
chars_avail = poll(&fds, 1, 0); |
|
} |
|
#ifndef __ANDROID__ |
|
if (chars_avail > 0) { |
|
/* getc won't block */ |
|
int c = getc(stream); |
|
if (c==EOF) |
|
return 0; |
|
gf_ungetc(c, stream); |
|
} |
|
#endif |
|
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 644 Cell getkey(FILE * stream)
|
Line 705 Cell getkey(FILE * stream)
|
Cell result; |
Cell result; |
unsigned char c; |
unsigned char c; |
|
|
setvbuf(stream, NULL, _IONBF, 0); |
if (!gf_ungottenc(stream)) |
|
setvbuf(stream, NULL, _IONBF, 0); |
if(!terminal_prepped && stream == stdin) |
if(!terminal_prepped && stream == stdin) |
prep_terminal(); |
prep_terminal(); |
|
|
result = fread(&c, sizeof(c), 1, stream); |
result = fread(&c, sizeof(c), 1, stream); |
|
if (result>0) |
|
gf_regetc(stream); |
return result==0 ? (errno == EINTR ? 12 : 4) : c; |
return result==0 ? (errno == EINTR ? 12 : 4) : c; |
} |
} |
|
|