123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- /* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
- /* Copyright (c) 1992, 1999, 2001, 2002, 2003 John E. Davis
- * This file is part of the S-Lang library.
- *
- * You may distribute under the terms of either the GNU General Public
- * License or the Perl Artistic License.
- */
- #include "slinclud.h"
- #include <signal.h>
- /* sequent support thanks to Kenneth Lorber <keni@oasys.dt.navy.mil> */
- /* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea@erlm.siemens.de */
- #if defined (_AIX) && !defined (_ALL_SOURCE)
- # define _ALL_SOURCE /* so NBBY is defined in <sys/types.h> */
- #endif
- #include <sys/time.h>
- #include <sys/types.h>
- #ifdef SYSV
- # include <fcntl.h>
- # ifndef CRAY
- # include <sys/termio.h>
- # include <sys/stream.h>
- # include <sys/ptem.h>
- # include <sys/tty.h>
- # endif
- #endif
- #ifdef __BEOS__
- /* Prototype for select */
- # include <net/socket.h>
- #endif
- #include <sys/file.h>
- #ifndef sun
- # include <sys/ioctl.h>
- #endif
- #ifdef __QNX__
- # include <sys/select.h>
- #endif
- #include <sys/stat.h>
- #include <errno.h>
- #if defined (_AIX) && !defined (FD_SET)
- # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
- #endif
- #ifndef O_RDWR
- # include <fcntl.h>
- #endif
- #include "slang.h"
- #include "_slang.h"
- int SLang_TT_Read_FD = -1;
- int SLang_TT_Baud_Rate;
- #ifdef HAVE_TERMIOS_H
- # if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
- # undef HAVE_TERMIOS_H
- # endif
- #endif
- #ifndef HAVE_TERMIOS_H
- # if !defined(CBREAK) && defined(sun)
- # ifndef BSD_COMP
- # define BSD_COMP 1
- # endif
- # include <sys/ioctl.h>
- # endif
- typedef struct
- {
- struct tchars t;
- struct ltchars lt;
- struct sgttyb s;
- }
- TTY_Termio_Type;
- #else
- # include <termios.h>
- typedef struct termios TTY_Termio_Type;
- #endif
- static TTY_Termio_Type Old_TTY;
- #ifdef HAVE_TERMIOS_H
- typedef const struct
- {
- unsigned int key;
- unsigned int value;
- } Baud_Rate_Type;
- static Baud_Rate_Type Baud_Rates [] =
- {
- #ifdef B0
- {B0, 0},
- #endif
- #ifdef B50
- {B50, 50},
- #endif
- #ifdef B75
- {B75, 75},
- #endif
- #ifdef B110
- {B110, 110},
- #endif
- #ifdef B134
- {B134, 134},
- #endif
- #ifdef B150
- {B150, 150},
- #endif
- #ifdef B200
- {B200, 200},
- #endif
- #ifdef B300
- {B300, 300},
- #endif
- #ifdef B600
- {B600, 600},
- #endif
- #ifdef B1200
- {B1200, 1200},
- #endif
- #ifdef B1800
- {B1800, 1800},
- #endif
- #ifdef B2400
- {B2400, 2400},
- #endif
- #ifdef B4800
- {B4800, 4800},
- #endif
- #ifdef B9600
- {B9600, 9600},
- #endif
- #ifdef B19200
- {B19200, 19200},
- #endif
- #ifdef B38400
- {B38400, 38400},
- #endif
- #ifdef B57600
- {B57600, 57600},
- #endif
- #ifdef B115200
- {B115200, 115200},
- #endif
- #ifdef B230400
- {B230400, 230400},
- #endif
- {0, 0}
- };
- static void
- set_baud_rate (TTY_Termio_Type *tty)
- {
- #ifdef HAVE_CFGETOSPEED
- unsigned int speed;
- Baud_Rate_Type *b, *bmax;
- if (SLang_TT_Baud_Rate)
- return; /* already set */
- speed = (unsigned int) cfgetospeed (tty);
- b = Baud_Rates;
- bmax = b + (sizeof (Baud_Rates)/sizeof(Baud_Rates[0]));
- while (b < bmax)
- {
- if (b->key == speed)
- {
- SLang_TT_Baud_Rate = b->value;
- return;
- }
- b++;
- }
- #else
- (void) tty;
- #endif
- }
- #endif /* HAVE_TERMIOS_H */
- #ifdef HAVE_TERMIOS_H
- # define GET_TERMIOS(fd, x) tcgetattr(fd, x)
- # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
- #else
- # ifdef TCGETS
- # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
- # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
- # else
- # define X(x,m) &(((TTY_Termio_Type *)(x))->m)
- # define GET_TERMIOS(fd, x) \
- ((ioctl(fd, TIOCGETC, X(x,t)) || \
- ioctl(fd, TIOCGLTC, X(x,lt)) || \
- ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
- # define SET_TERMIOS(fd, x) \
- ((ioctl(fd, TIOCSETC, X(x,t)) ||\
- ioctl(fd, TIOCSLTC, X(x,lt)) || \
- ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
- # endif
- #endif
- static int TTY_Inited = 0;
- static int TTY_Open = 0;
- #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
- # define NULL_VALUE -1
- #else
- # ifdef _POSIX_VDISABLE
- # define NULL_VALUE _POSIX_VDISABLE
- # else
- # define NULL_VALUE 255
- # endif
- #endif
- int SLang_init_tty (int abort_char, int no_flow_control, int opost)
- {
- TTY_Termio_Type newtty;
- SLsig_block_signals ();
- if (TTY_Inited)
- {
- SLsig_unblock_signals ();
- return 0;
- }
- TTY_Open = 0;
- if ((SLang_TT_Read_FD == -1)
- || (1 != isatty (SLang_TT_Read_FD)))
- {
- #ifdef O_RDWR
- # if !defined(__BEOS__) && !defined(__APPLE__)
- /* I have been told that BEOS will HANG if passed /dev/tty */
- if ((SLang_TT_Read_FD = open("/dev/tty", O_RDWR)) >= 0)
- {
- TTY_Open = 1;
- }
- # endif
- #endif
- if (TTY_Open == 0)
- {
- SLang_TT_Read_FD = fileno (stderr);
- if (1 != isatty (SLang_TT_Read_FD))
- {
- SLang_TT_Read_FD = fileno (stdin);
- if (1 != isatty (SLang_TT_Read_FD))
- {
- fprintf (stderr, "Failed to open terminal.");
- return -1;
- }
- }
- }
- }
- SLang_Abort_Char = abort_char;
- /* Some systems may not permit signals to be blocked. As a result, the
- * return code must be checked.
- */
- while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
- {
- if (errno != EINTR)
- {
- SLsig_unblock_signals ();
- return -1;
- }
- }
- while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &newtty))
- {
- if (errno != EINTR)
- {
- SLsig_unblock_signals ();
- return -1;
- }
- }
- #ifndef HAVE_TERMIOS_H
- (void) opost;
- (void) no_flow_control;
- newtty.s.sg_flags &= ~(ECHO);
- newtty.s.sg_flags &= ~(CRMOD);
- /* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
- newtty.t.t_eofc = 1;
- if (abort_char == -1) SLang_Abort_Char = newtty.t.t_intrc;
- newtty.t.t_intrc = SLang_Abort_Char; /* ^G */
- newtty.t.t_quitc = 255;
- newtty.lt.t_suspc = 255; /* to ignore ^Z */
- newtty.lt.t_dsuspc = 255; /* to ignore ^Y */
- newtty.lt.t_lnextc = 255;
- newtty.s.sg_flags |= CBREAK; /* do I want cbreak or raw????? */
- #else
- /* get baud rate */
- newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);
- #ifdef ISTRIP
- /* newtty.c_iflag &= ~ISTRIP; */
- #endif
- if (opost == 0) newtty.c_oflag &= ~OPOST;
- set_baud_rate (&newtty);
- if (no_flow_control) newtty.c_iflag &= ~IXON; else newtty.c_iflag |= IXON;
- newtty.c_cc[VEOF] = 1;
- newtty.c_cc[VMIN] = 1;
- newtty.c_cc[VTIME] = 0;
- newtty.c_lflag = ISIG | NOFLSH;
- if (abort_char == -1) SLang_Abort_Char = newtty.c_cc[VINTR];
- newtty.c_cc[VINTR] = SLang_Abort_Char; /* ^G */
- newtty.c_cc[VQUIT] = NULL_VALUE;
- newtty.c_cc[VSUSP] = NULL_VALUE; /* to ignore ^Z */
- #ifdef VDSUSP
- newtty.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
- #endif
- #ifdef VLNEXT
- newtty.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V ? */
- #endif
- #ifdef VSWTCH
- newtty.c_cc[VSWTCH] = NULL_VALUE; /* to ignore who knows what */
- #endif
- #endif /* NOT HAVE_TERMIOS_H */
- while (-1 == SET_TERMIOS(SLang_TT_Read_FD, &newtty))
- {
- if (errno != EINTR)
- {
- SLsig_unblock_signals ();
- return -1;
- }
- }
- TTY_Inited = 1;
- SLsig_unblock_signals ();
- return 0;
- }
- void SLtty_set_suspend_state (int mode)
- {
- TTY_Termio_Type newtty;
- SLsig_block_signals ();
- if (TTY_Inited == 0)
- {
- SLsig_unblock_signals ();
- return;
- }
- while ((-1 == GET_TERMIOS (SLang_TT_Read_FD, &newtty))
- && (errno == EINTR))
- ;
- #ifndef HAVE_TERMIOS_H
- /* I do not know if all systems define the t_dsuspc field */
- if (mode == 0)
- {
- newtty.lt.t_suspc = 255;
- newtty.lt.t_dsuspc = 255;
- }
- else
- {
- newtty.lt.t_suspc = Old_TTY.lt.t_suspc;
- newtty.lt.t_dsuspc = Old_TTY.lt.t_dsuspc;
- }
- #else
- if (mode == 0)
- {
- newtty.c_cc[VSUSP] = NULL_VALUE;
- #ifdef VDSUSP
- newtty.c_cc[VDSUSP] = NULL_VALUE;
- #endif
- }
- else
- {
- newtty.c_cc[VSUSP] = Old_TTY.c_cc[VSUSP];
- #ifdef VDSUSP
- newtty.c_cc[VDSUSP] = Old_TTY.c_cc[VDSUSP];
- #endif
- }
- #endif
- while ((-1 == SET_TERMIOS (SLang_TT_Read_FD, &newtty))
- && (errno == EINTR))
- ;
- SLsig_unblock_signals ();
- }
- void SLang_reset_tty (void)
- {
- SLsig_block_signals ();
- if (TTY_Inited == 0)
- {
- SLsig_unblock_signals ();
- return;
- }
- while ((-1 == SET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
- && (errno == EINTR))
- ;
- if (TTY_Open)
- {
- while ((-1 == close (SLang_TT_Read_FD))
- && (errno == EINTR))
- ;
- TTY_Open = 0;
- SLang_TT_Read_FD = -1;
- }
- TTY_Inited = 0;
- SLsig_unblock_signals ();
- }
- static void default_sigint (int sig)
- {
- sig = errno; /* use parameter */
- SLKeyBoard_Quit = 1;
- if (SLang_Ignore_User_Abort == 0) SLang_Error = SL_USER_BREAK;
- SLsignal_intr (SIGINT, default_sigint);
- errno = sig;
- }
- int SLang_set_abort_signal (void (*hand)(int))
- {
- int save_errno = errno;
- SLSig_Fun_Type *f;
- if (hand == NULL) hand = default_sigint;
- f = SLsignal_intr (SIGINT, hand);
- errno = save_errno;
- if (f == (SLSig_Fun_Type *) SIG_ERR)
- return -1;
- return 0;
- }
- #ifndef FD_SET
- #define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
- #define FD_ZERO(tthis) *(tthis) = 0
- #define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
- typedef int fd_set;
- #endif
- static fd_set Read_FD_Set;
- /* HACK: If > 0, use 1/10 seconds. If < 0, use 1/1000 seconds */
- int _SLsys_input_pending(int tsecs)
- {
- struct timeval wait;
- long usecs, secs;
- if ((TTY_Inited == 0)
- || (SLang_TT_Read_FD < 0))
- {
- errno = EBADF;
- return -1;
- }
- if (tsecs >= 0)
- {
- secs = tsecs / 10;
- usecs = (tsecs % 10) * 100000;
- }
- else
- {
- tsecs = -tsecs;
- secs = tsecs / 1000;
- usecs = (tsecs % 1000) * 1000;
- }
- wait.tv_sec = secs;
- wait.tv_usec = usecs;
- FD_ZERO(&Read_FD_Set);
- FD_SET(SLang_TT_Read_FD, &Read_FD_Set);
- return select(SLang_TT_Read_FD + 1, &Read_FD_Set, NULL, NULL, &wait);
- }
- int (*SLang_getkey_intr_hook) (void);
- static int handle_interrupt (void)
- {
- if (SLang_getkey_intr_hook != NULL)
- {
- int save_tty_fd = SLang_TT_Read_FD;
- if (-1 == (*SLang_getkey_intr_hook) ())
- return -1;
- if (save_tty_fd != SLang_TT_Read_FD)
- return -1;
- }
- return 0;
- }
- unsigned int _SLsys_getkey (void)
- {
- unsigned char c;
- if (TTY_Inited == 0)
- {
- int ic = fgetc (stdin);
- if (ic == EOF) return SLANG_GETKEY_ERROR;
- return (unsigned int) ic;
- }
- while (1)
- {
- int ret;
- if (SLKeyBoard_Quit)
- return SLang_Abort_Char;
- if (0 == (ret = _SLsys_input_pending (100)))
- continue;
- if (ret != -1)
- break;
- if (SLKeyBoard_Quit)
- return SLang_Abort_Char;
- if (errno == EINTR)
- {
- if (-1 == handle_interrupt ())
- return SLANG_GETKEY_ERROR;
- continue;
- }
- break; /* let read handle it */
- }
- while (1)
- {
- int status = read(SLang_TT_Read_FD, (char *) &c, 1);
- if (status > 0)
- break;
- if (status == 0)
- {
- /* We are at the end of a file. Let application handle it. */
- return SLANG_GETKEY_ERROR;
- }
- if (errno == EINTR)
- {
- if (-1 == handle_interrupt ())
- return SLANG_GETKEY_ERROR;
- if (SLKeyBoard_Quit)
- return SLang_Abort_Char;
- continue;
- }
- #ifdef EAGAIN
- if (errno == EAGAIN)
- {
- sleep (1);
- continue;
- }
- #endif
- #ifdef EWOULDBLOCK
- if (errno == EWOULDBLOCK)
- {
- sleep (1);
- continue;
- }
- #endif
- #ifdef EIO
- if (errno == EIO)
- {
- SLang_exit_error ("_SLsys_getkey: EIO error.");
- }
- #endif
- return SLANG_GETKEY_ERROR;
- }
- return((unsigned int) c);
- }
|