1 /* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
2 /* Copyright (c) 1992, 1999, 2001, 2002 John E. Davis
3 * This file is part of the S-Lang library.
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Perl Artistic License.
12 /* sequent support thanks to Kenneth Lorber <keni@oasys.dt.navy.mil> */
13 /* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea@erlm.siemens.de */
15 #if defined (_AIX) && !defined (_ALL_SOURCE)
16 # define _ALL_SOURCE /* so NBBY is defined in <sys/types.h> */
20 #include <sys/types.h>
25 # include <sys/termio.h>
26 # include <sys/stream.h>
27 # include <sys/ptem.h>
33 /* Prototype for select */
34 # include <net/socket.h>
40 # include <sys/ioctl.h>
44 # include <sys/select.h>
50 #if defined (_AIX) && !defined (FD_SET)
51 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
61 int SLang_TT_Read_FD
= -1;
62 int SLang_TT_Baud_Rate
;
65 # if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
66 # undef HAVE_TERMIOS_H
70 #ifndef HAVE_TERMIOS_H
72 # if !defined(CBREAK) && defined(sun)
76 # include <sys/ioctl.h>
88 typedef struct termios TTY_Termio_Type
;
91 static TTY_Termio_Type Old_TTY
;
100 static Baud_Rate_Type Baud_Rates
[] =
163 set_baud_rate (TTY_Termio_Type
*tty
)
165 #ifdef HAVE_CFGETOSPEED
167 Baud_Rate_Type
*b
, *bmax
;
169 if (SLang_TT_Baud_Rate
)
170 return; /* already set */
172 speed
= (unsigned int) cfgetospeed (tty
);
175 bmax
= b
+ (sizeof (Baud_Rates
)/sizeof(Baud_Rates
[0]));
180 SLang_TT_Baud_Rate
= b
->value
;
190 #endif /* HAVE_TERMIOS_H */
192 #ifdef HAVE_TERMIOS_H
193 # define GET_TERMIOS(fd, x) tcgetattr(fd, x)
194 # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
197 # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
198 # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
200 # define X(x,m) &(((TTY_Termio_Type *)(x))->m)
201 # define GET_TERMIOS(fd, x) \
202 ((ioctl(fd, TIOCGETC, X(x,t)) || \
203 ioctl(fd, TIOCGLTC, X(x,lt)) || \
204 ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
205 # define SET_TERMIOS(fd, x) \
206 ((ioctl(fd, TIOCSETC, X(x,t)) ||\
207 ioctl(fd, TIOCSLTC, X(x,lt)) || \
208 ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
212 static int TTY_Inited
= 0;
213 static int TTY_Open
= 0;
215 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
216 # define NULL_VALUE -1
218 # ifdef _POSIX_VDISABLE
219 # define NULL_VALUE _POSIX_VDISABLE
221 # define NULL_VALUE 255
225 int SLang_init_tty (int abort_char
, int no_flow_control
, int opost
)
227 TTY_Termio_Type newtty
;
229 SLsig_block_signals ();
233 SLsig_unblock_signals ();
239 if ((SLang_TT_Read_FD
== -1)
240 || (1 != isatty (SLang_TT_Read_FD
)))
243 # if !defined(__BEOS__) && !defined(__APPLE__)
244 /* I have been told that BEOS will HANG if passed /dev/tty */
245 if ((SLang_TT_Read_FD
= open("/dev/tty", O_RDWR
)) >= 0)
253 SLang_TT_Read_FD
= fileno (stderr
);
254 if (1 != isatty (SLang_TT_Read_FD
))
256 SLang_TT_Read_FD
= fileno (stdin
);
257 if (1 != isatty (SLang_TT_Read_FD
))
259 fprintf (stderr
, "Failed to open terminal.");
266 SLang_Abort_Char
= abort_char
;
268 /* Some systems may not permit signals to be blocked. As a result, the
269 * return code must be checked.
271 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
275 SLsig_unblock_signals ();
280 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
284 SLsig_unblock_signals ();
289 #ifndef HAVE_TERMIOS_H
291 (void) no_flow_control
;
292 newtty
.s
.sg_flags
&= ~(ECHO
);
293 newtty
.s
.sg_flags
&= ~(CRMOD
);
294 /* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
296 if (abort_char
== -1) SLang_Abort_Char
= newtty
.t
.t_intrc
;
297 newtty
.t
.t_intrc
= SLang_Abort_Char
; /* ^G */
298 newtty
.t
.t_quitc
= 255;
299 newtty
.lt
.t_suspc
= 255; /* to ignore ^Z */
300 newtty
.lt
.t_dsuspc
= 255; /* to ignore ^Y */
301 newtty
.lt
.t_lnextc
= 255;
302 newtty
.s
.sg_flags
|= CBREAK
; /* do I want cbreak or raw????? */
307 newtty
.c_iflag
&= ~(ECHO
| INLCR
| ICRNL
);
309 /* newtty.c_iflag &= ~ISTRIP; */
311 if (opost
== 0) newtty
.c_oflag
&= ~OPOST
;
313 set_baud_rate (&newtty
);
315 if (no_flow_control
) newtty
.c_iflag
&= ~IXON
; else newtty
.c_iflag
|= IXON
;
317 newtty
.c_cc
[VEOF
] = 1;
318 newtty
.c_cc
[VMIN
] = 1;
319 newtty
.c_cc
[VTIME
] = 0;
320 newtty
.c_lflag
= ISIG
| NOFLSH
;
321 if (abort_char
== -1) SLang_Abort_Char
= newtty
.c_cc
[VINTR
];
322 newtty
.c_cc
[VINTR
] = SLang_Abort_Char
; /* ^G */
323 newtty
.c_cc
[VQUIT
] = NULL_VALUE
;
324 newtty
.c_cc
[VSUSP
] = NULL_VALUE
; /* to ignore ^Z */
326 newtty
.c_cc
[VDSUSP
] = NULL_VALUE
; /* to ignore ^Y */
329 newtty
.c_cc
[VLNEXT
] = NULL_VALUE
; /* to ignore ^V ? */
332 newtty
.c_cc
[VSWTCH
] = NULL_VALUE
; /* to ignore who knows what */
334 #endif /* NOT HAVE_TERMIOS_H */
336 while (-1 == SET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
340 SLsig_unblock_signals ();
346 SLsig_unblock_signals ();
350 void SLtty_set_suspend_state (int mode
)
352 TTY_Termio_Type newtty
;
354 SLsig_block_signals ();
358 SLsig_unblock_signals ();
362 while ((-1 == GET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
366 #ifndef HAVE_TERMIOS_H
367 /* I do not know if all systems define the t_dsuspc field */
370 newtty
.lt
.t_suspc
= 255;
371 newtty
.lt
.t_dsuspc
= 255;
375 newtty
.lt
.t_suspc
= Old_TTY
.lt
.t_suspc
;
376 newtty
.lt
.t_dsuspc
= Old_TTY
.lt
.t_dsuspc
;
381 newtty
.c_cc
[VSUSP
] = NULL_VALUE
;
383 newtty
.c_cc
[VDSUSP
] = NULL_VALUE
;
388 newtty
.c_cc
[VSUSP
] = Old_TTY
.c_cc
[VSUSP
];
390 newtty
.c_cc
[VDSUSP
] = Old_TTY
.c_cc
[VDSUSP
];
395 while ((-1 == SET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
399 SLsig_unblock_signals ();
402 void SLang_reset_tty (void)
404 SLsig_block_signals ();
408 SLsig_unblock_signals ();
412 while ((-1 == SET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
418 while ((-1 == close (SLang_TT_Read_FD
))
423 SLang_TT_Read_FD
= -1;
427 SLsig_unblock_signals ();
430 static void default_sigint (int sig
)
432 sig
= errno
; /* use parameter */
435 if (SLang_Ignore_User_Abort
== 0) SLang_Error
= SL_USER_BREAK
;
436 SLsignal_intr (SIGINT
, default_sigint
);
440 int SLang_set_abort_signal (void (*hand
)(int))
442 int save_errno
= errno
;
445 if (hand
== NULL
) hand
= default_sigint
;
446 f
= SLsignal_intr (SIGINT
, hand
);
450 if (f
== (SLSig_Fun_Type
*) SIG_ERR
)
457 #define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
458 #define FD_ZERO(tthis) *(tthis) = 0
459 #define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
463 static fd_set Read_FD_Set
;
465 /* HACK: If > 0, use 1/10 seconds. If < 0, use 1/1000 seconds */
467 int _SLsys_input_pending(int tsecs
)
472 if ((TTY_Inited
== 0)
473 || (SLang_TT_Read_FD
< 0))
482 usecs
= (tsecs
% 10) * 100000;
488 usecs
= (tsecs
% 1000) * 1000;
492 wait
.tv_usec
= usecs
;
494 FD_ZERO(&Read_FD_Set
);
495 FD_SET(SLang_TT_Read_FD
, &Read_FD_Set
);
497 return select(SLang_TT_Read_FD
+ 1, &Read_FD_Set
, NULL
, NULL
, &wait
);
500 int (*SLang_getkey_intr_hook
) (void);
502 static int handle_interrupt (void)
504 if (SLang_getkey_intr_hook
!= NULL
)
506 int save_tty_fd
= SLang_TT_Read_FD
;
508 if (-1 == (*SLang_getkey_intr_hook
) ())
511 if (save_tty_fd
!= SLang_TT_Read_FD
)
518 unsigned int _SLsys_getkey (void)
524 int ic
= fgetc (stdin
);
525 if (ic
== EOF
) return SLANG_GETKEY_ERROR
;
526 return (unsigned int) ic
;
534 return SLang_Abort_Char
;
536 if (0 == (ret
= _SLsys_input_pending (100)))
543 return SLang_Abort_Char
;
547 if (-1 == handle_interrupt ())
548 return SLANG_GETKEY_ERROR
;
553 break; /* let read handle it */
558 int status
= read(SLang_TT_Read_FD
, (char *) &c
, 1);
565 /* We are at the end of a file. Let application handle it. */
566 return SLANG_GETKEY_ERROR
;
571 if (-1 == handle_interrupt ())
572 return SLANG_GETKEY_ERROR
;
575 return SLang_Abort_Char
;
587 if (errno
== EWOULDBLOCK
)
596 SLang_exit_error ("_SLsys_getkey: EIO error.");
599 return SLANG_GETKEY_ERROR
;
602 return((unsigned int) c
);