/* unixio.c - Unix terminal and signal handling $Id: unixio.c,v 0.2 1997/03/28 03:17:33 tjchol01 Exp $ Authors: Andrew Trevorrow, Ian Dall, Geoffrey Tobin, Tomasz J. Cholewo */ #include "dvgt.h" #include "unixio.h" #include "screenio.h" /* for MesgString, MesgLine */ /* Set DV_FD (ioctl file descriptor) to 0 or 1 ? */ #define DV_FD STDIN_FILENO sig_flags_t sig_flags; cmode_flags_t cmode_flags; /* Alex Dickinson Procedures for setting and resetting UNIX tty characteristics. Interesting functions are: save_init_tty; restore_init_tty; save_temp_tty; restore_temp_tty; echoon; echooff; singlecharon; singlecharoff; buffercount; suspend; A side effect of calling save_temp_tty is to set up signal handling to reset the terminal characteristics appropriately for the various interrupt signals. */ /***************************************************************** * terminal handling */ #if defined(HAVE_TERMIO_H) #include #include #define TERMIO #ifdef NCC #define MAXCC NCC #else #define MAXCC 256 #endif #define DV_GTTY TCGETA #define DV_STTY TCSETAW typedef struct termio dv_tty; unsigned char saved_cc[NCC]; #else #include #define DV_GTTY TIOCGETP #define DV_STTY TIOCSETN typedef struct sgttyb dv_tty; #endif /* TERMIOS || TERMIO */ #include #include static dv_tty init_tty_state; /* store initial terminal characteristics */ static dv_tty temp_tty_state; /* current terminal characteristics */ /* locally defined and used functions and data */ static void setsignals (); static void reportio PARAMS ((int iostat)); static int iostatus; /* return status of ioctl system function */ static void reportio (int iostat) { if (iostat < 0) { /* an ioctl error */ char *str = ""; String cstr; switch (errno) { /* generic errors */ #ifdef EBADF case EBADF: str = "Not a valid, open, file descriptor!"; break; #endif #ifdef EINTR case EINTR: str = "Signal caught."; break; #endif #ifdef ENOTTY case ENOTTY: str = "No device driver, or doesn't accept control functions!"; break; #endif /* specialised errors */ #ifdef EFAULT case EFAULT: str = "Illegal data transfer address!"; break; #endif #ifdef EINVAL case EINVAL: str = "Driver ignorant of this request or arg!"; break; #endif #ifdef EIO case EIO: str = "Physical I/O error!"; break; #endif #ifdef ENOLINK case ENOLINK: str = "Remote machine link no longer active!"; break; #endif #ifdef ENXIO case ENXIO: str = "Subdevice cannot perform requested service!"; break; #endif /* gt - should be ample space in cstr. */ default: sprintf (cstr, "Unknown error %d !", errno); str = cstr; break; } MesgString ("ioctl: "); MesgString (str); MesgLine (); } } /* reportio */ void save_init_tty () { /* Save the original tty characteristics and set up the signalling. */ save_temp_tty (); init_tty_state = temp_tty_state; } /* save_init_tty */ void restore_init_tty () { /* Restore the original tty characteristics. */ temp_tty_state = init_tty_state; restore_temp_tty (); } /* restore_init_tty */ void save_temp_tty () { /* Save the current tty characteristics and set up the signalling. */ iostatus = ioctl (DV_FD, DV_GTTY, &temp_tty_state); reportio (iostatus); setsignals (); } /* save_temp_tty */ void restore_temp_tty () { /* Restore the recent tty characteristics. */ iostatus = ioctl (DV_FD, DV_STTY, &temp_tty_state); reportio (iostatus); } /* restore_temp_tty */ void singlecharon () { /* Set driver to read characters as they are typed without waiting for a terminator. Echo remains unchanged. */ dv_tty s; if (cmode_flags.cbreak != 1) { reportio (ioctl (DV_FD, DV_GTTY, &s)); #ifndef TERMIO s.sg_flags |= CBREAK; #else /* TERMIO */ saved_cc[VEOL] = s.c_cc[VEOL]; saved_cc[VEOF] = s.c_cc[VEOF]; s.c_lflag &= ~ICANON; /* Disable erase/kill processing */ s.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */ s.c_cc[VTIME] = 0; /* no matter how long that takes. */ #endif /* TERMIO */ reportio (ioctl (DV_FD, DV_STTY, &s)); #ifdef FLUSH_STDIN fflush (stdin); #endif /* FLUSH_STDIN */ cmode_flags.cbreak = 1; } } /* singlecharon */ void singlecharoff () { /* Turn off single character read mode. */ dv_tty s; if (cmode_flags.cbreak != 0) { iostatus = ioctl (DV_FD, DV_GTTY, &s); reportio (iostatus); #ifndef TERMIO s.sg_flags &= ~CBREAK; #else /* TERMIO */ s.c_lflag |= ICANON; /* Enable erase/kill processing */ s.c_cc[VEOL] = saved_cc[VEOL]; s.c_cc[VEOF] = saved_cc[VEOF]; #endif /* TERMIO */ iostatus = ioctl (DV_FD, DV_STTY, &s); reportio (iostatus); cmode_flags.cbreak = 0; } } /* singlecharoff */ void echoon () { /* Turn character echoing on. */ dv_tty s; reportio (ioctl (DV_FD, DV_GTTY, &s)); #ifndef TERMIO s.sg_flags |= ECHO; #else /* TERMIO */ s.c_lflag |= ECHO; #endif /* TERMIO */ reportio (ioctl (DV_FD, DV_STTY, &s)); cmode_flags.echo = 1; } /* echoon */ void echooff () { /* Turn character echoing off. */ dv_tty s; iostatus = ioctl (DV_FD, DV_GTTY, &s); reportio (iostatus); #ifndef TERMIO s.sg_flags &= ~ECHO; #else /* TERMIO */ s.c_lflag &= ~ECHO; #endif /* TERMIO */ iostatus = ioctl (DV_FD, DV_STTY, &s); reportio (iostatus); cmode_flags.echo = 0; } /* echooff */ void rawouton () { dv_tty s; iostatus = ioctl (DV_FD, DV_GTTY, &s); reportio (iostatus); #ifdef TERMIO s.c_oflag &= ~OPOST; /* Disables tab interpretation etc. */ #endif /* TERMIO */ iostatus = ioctl (DV_FD, DV_STTY, &s); reportio (iostatus); cmode_flags.raw = 1; } /* rawouton */ void rawoutoff () { dv_tty s; iostatus = ioctl (DV_FD, DV_GTTY, &s); reportio (iostatus); #ifdef TERMIO /* TERMIO */ s.c_oflag |= OPOST; #endif /* TERMIO */ iostatus = ioctl (DV_FD, DV_STTY, &s); reportio (iostatus); cmode_flags.raw = 0; } /* rawoutoff */ int buffercount () { /* Return true if there are any characters currently in the input buffer. */ #ifndef TERMIO long count; iostatus = ioctl (DV_FD, FIONREAD, &count); reportio (iostatus); return (count > 0); #else /* TERMIO */ int c, flags, ret; /* Save the current fcntl flags and make reads return without waiting */ flags = fcntl (0, F_GETFL, 0); fcntl (0, F_SETFL, flags | O_NDELAY); /* This might be SysV specific */ if ((c = getchar ()) != EOF) { ungetc (c, stdin); ret = 1; } else { ret = 0; } fcntl (0, F_SETFL, flags); /* This might be SysV specific */ return ret; #endif /* TERMIO */ } /* buffercount */ RETSIGTYPE handleint (int sig) { /* Catch signals from tty. If sig is an interrupt, set the intr flag, Otherwise it was a suspend, so set the tstop flag. */ fflush (stdin); if (sig == SIGINT) { sig_flags.intr = 1; } else { sig_flags.tstop = 1; } #ifdef TERMIO /* TERMIO */ setsignals (); /* Because SysV forgets its handlers */ #endif /* TERMIO */ } /* handleint */ static void setsignals () { /* Signal initialization. */ signal (SIGINT, handleint); #ifndef TERMIO signal (SIGTSTP, handleint); #endif /* TERMIO */ } /* setsignals */ void suspend () { /* Suspend the process */ #ifndef TERMIO signal (SIGTSTP, SIG_DFL); kill (0, SIGTSTP); /* resumed again, goody! */ setsignals (); #else /* don't know what to do */ #endif /* TERMIO */ } /* suspend */ #undef IN_UNIXIO_C