1 /* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
2 /* Copyright (c) 1992, 1995 John E. Davis
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Perl Artistic License.
14 /* sequent support thanks to Kenneth Lorber <keni@oasys.dt.navy.mil> */
15 /* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea@erlm.siemens.de */
17 #if defined (_AIX) && !defined (_ALL_SOURCE)
18 # define _ALL_SOURCE /* so NBBY is defined in <sys/types.h> */
30 #include <sys/types.h>
35 # include <sys/termio.h>
36 # include <sys/stream.h>
37 # include <sys/ptem.h>
44 /* Prototype for select */
45 # include <net/socket.h>
51 # include <sys/ioctl.h>
55 # include <sys/select.h>
61 #if defined (_AIX) && !defined (FD_SET)
62 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
73 int SLang_TT_Read_FD
= -1;
74 int SLang_TT_Baud_Rate
;
78 # if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
79 # undef HAVE_TERMIOS_H
83 #ifndef HAVE_TERMIOS_H
85 # if !defined(CBREAK) && defined(sun)
89 # include <sys/ioctl.h>
100 # include <termios.h>
101 typedef struct termios TTY_Termio_Type
;
104 static TTY_Termio_Type Old_TTY
;
106 #ifdef HAVE_TERMIOS_H
141 #ifdef HAVE_TERMIOS_H
142 # define GET_TERMIOS(fd, x) tcgetattr(fd, x)
143 # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
146 # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
147 # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
149 # define X(x,m) &(((TTY_Termio_Type *)(x))->m)
150 # define GET_TERMIOS(fd, x) \
151 ((ioctl(fd, TIOCGETC, X(x,t)) || \
152 ioctl(fd, TIOCGLTC, X(x,lt)) || \
153 ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
154 # define SET_TERMIOS(fd, x) \
155 ((ioctl(fd, TIOCSETC, X(x,t)) ||\
156 ioctl(fd, TIOCSLTC, X(x,lt)) || \
157 ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
161 static int TTY_Inited
= 0;
162 static int TTY_Open
= 0;
164 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
165 # define NULL_VALUE -1
167 # ifdef _POSIX_VDISABLE
168 # define NULL_VALUE _POSIX_VDISABLE
170 # define NULL_VALUE 255
175 speed_t2baud_rate (speed_t s
)
179 for (i
= 0; i
< sizeof (Baud_Rates
)/sizeof (Baud_Rates
[0]); i
++)
180 if (Baud_Rates
[i
].key
== s
)
181 return (Baud_Rates
[i
].value
);
185 int SLang_init_tty (int abort_char
, int no_flow_control
, int opost
)
187 TTY_Termio_Type newtty
;
189 SLsig_block_signals ();
193 SLsig_unblock_signals ();
199 if ((SLang_TT_Read_FD
== -1)
200 || (1 != isatty (SLang_TT_Read_FD
)))
204 # ifndef __BEOS__ /* I have been told that BEOS will HANG if passed /dev/tty */
205 if ((SLang_TT_Read_FD
= open("/dev/tty", O_RDWR
)) >= 0)
216 /* In the Midnight Commander we bind stderr sometimes to a pipe. If we
217 use stderr for terminal input and call SLang_getkey while stderr is
218 bound to a pipe MC will hang completly in SLsys_input_pending.
219 NOTE: There's an independent fix for this problem in src/slint.c for
220 the case that the Midnight Commander is linked against a shared slang
221 library compiled from different sources.
223 SLang_TT_Read_FD
= fileno (stderr
);
224 if (1 != isatty (SLang_TT_Read_FD
))
227 SLang_TT_Read_FD
= fileno (stdin
);
228 if (1 != isatty (SLang_TT_Read_FD
))
230 fprintf (stderr
, "Failed to open terminal.");
237 SLang_Abort_Char
= abort_char
;
239 /* Some systems may not permit signals to be blocked. As a result, the
240 * return code must be checked.
242 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
246 SLsig_unblock_signals ();
251 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
255 SLsig_unblock_signals ();
260 #ifndef HAVE_TERMIOS_H
261 newtty
.s
.sg_flags
&= ~(ECHO
);
262 newtty
.s
.sg_flags
&= ~(CRMOD
);
263 /* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
265 if (abort_char
== -1) SLang_Abort_Char
= newtty
.t
.t_intrc
;
266 newtty
.t
.t_intrc
= SLang_Abort_Char
; /* ^G */
267 newtty
.t
.t_quitc
= 255;
268 newtty
.lt
.t_suspc
= 255; /* to ignore ^Z */
269 newtty
.lt
.t_dsuspc
= 255; /* to ignore ^Y */
270 newtty
.lt
.t_lnextc
= 255;
271 newtty
.s
.sg_flags
|= CBREAK
; /* do I want cbreak or raw????? */
276 /* [not only QNX related !?!]
277 * ECHO(0x08) is a c_lflag bit, it means here PARMRK(0x08) in c_iflag!!!
279 /*newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);*/
280 newtty
.c_iflag
&= ~(INLCR
| ICRNL
);
282 /* newtty.c_iflag &= ~ISTRIP; */
284 if (opost
== 0) newtty
.c_oflag
&= ~OPOST
;
286 if (SLang_TT_Baud_Rate
== 0)
288 /* Note: if this generates an compiler error, simply remove
290 #ifdef HAVE_CFGETOSPEED
291 SLang_TT_Baud_Rate
= cfgetospeed (&newtty
);
293 SLang_TT_Baud_Rate
= speed_t2baud_rate (SLang_TT_Baud_Rate
);
295 if (no_flow_control
) newtty
.c_iflag
&= ~IXON
; else newtty
.c_iflag
|= IXON
;
297 newtty
.c_cc
[VMIN
] = 1;
298 newtty
.c_cc
[VTIME
] = 0;
299 newtty
.c_cc
[VEOF
] = 1;
300 newtty
.c_lflag
= ISIG
| NOFLSH
;
301 if (abort_char
== -1) SLang_Abort_Char
= newtty
.c_cc
[VINTR
];
302 newtty
.c_cc
[VINTR
] = SLang_Abort_Char
; /* ^G */
303 newtty
.c_cc
[VQUIT
] = NULL_VALUE
;
304 newtty
.c_cc
[VSUSP
] = NULL_VALUE
; /* to ignore ^Z */
306 newtty
.c_cc
[VSWTCH
] = NULL_VALUE
; /* to ignore who knows what */
308 #endif /* NOT HAVE_TERMIOS_H */
310 while (-1 == SET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
314 SLsig_unblock_signals ();
320 SLsig_unblock_signals ();
324 void SLtty_set_suspend_state (int mode
)
326 TTY_Termio_Type newtty
;
328 SLsig_block_signals ();
332 SLsig_unblock_signals ();
336 while ((-1 == GET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
340 #ifndef HAVE_TERMIOS_H
341 if (mode
== 0) newtty
.lt
.t_suspc
= 255;
342 else newtty
.lt
.t_suspc
= Old_TTY
.lt
.t_suspc
;
344 if (mode
== 0) newtty
.c_cc
[VSUSP
] = NULL_VALUE
;
345 else newtty
.c_cc
[VSUSP
] = Old_TTY
.c_cc
[VSUSP
];
348 while ((-1 == SET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
352 SLsig_unblock_signals ();
355 void SLang_reset_tty (void)
357 SLsig_block_signals ();
361 SLsig_unblock_signals ();
365 while ((-1 == SET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
371 while ((-1 == close (SLang_TT_Read_FD
))
376 SLang_TT_Read_FD
= -1;
380 SLsig_unblock_signals ();
383 static void default_sigint (int sig
)
385 sig
= errno
; /* use parameter */
388 if (SLang_Ignore_User_Abort
== 0) SLang_Error
= USER_BREAK
;
389 SLsignal_intr (SIGINT
, default_sigint
);
393 void SLang_set_abort_signal (void (*hand
)(int))
395 int save_errno
= errno
;
397 if (hand
== NULL
) hand
= default_sigint
;
398 SLsignal_intr (SIGINT
, hand
);
404 #define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
405 #define FD_ZERO(tthis) *(tthis) = 0
406 #define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
410 static fd_set Read_FD_Set
;
413 /* HACK: If > 0, use 1/10 seconds. If < 0, use 1/1000 seconds */
415 int SLsys_input_pending(int tsecs
)
420 if (TTY_Inited
== 0) return -1;
425 usecs
= (tsecs
% 10) * 100000;
431 usecs
= (tsecs
% 1000) * 1000;
435 wait
.tv_usec
= usecs
;
437 FD_ZERO(&Read_FD_Set
);
438 FD_SET(SLang_TT_Read_FD
, &Read_FD_Set
);
440 return select(SLang_TT_Read_FD
+ 1, &Read_FD_Set
, NULL
, NULL
, &wait
);
444 int (*SLang_getkey_intr_hook
) (void);
446 static int handle_interrupt (void)
448 if (SLang_getkey_intr_hook
!= NULL
)
450 int save_tty_fd
= SLang_TT_Read_FD
;
452 if (-1 == (*SLang_getkey_intr_hook
) ())
455 if (save_tty_fd
!= SLang_TT_Read_FD
)
462 unsigned int SLsys_getkey (void)
469 int ic
= fgetc (stdin
);
470 if (ic
== EOF
) return SLANG_GETKEY_ERROR
;
471 return (unsigned int) ic
;
479 return SLang_Abort_Char
;
481 if (0 == (ret
= SLsys_input_pending (100)))
488 return SLang_Abort_Char
;
492 if (-1 == handle_interrupt ())
493 return SLANG_GETKEY_ERROR
;
498 break; /* let read handle it */
501 while (-1 == (i
= read(SLang_TT_Read_FD
, (char *) &c
, 1)))
505 if (-1 == handle_interrupt ())
506 return SLANG_GETKEY_ERROR
;
509 return SLang_Abort_Char
;
521 if (errno
== EWOULDBLOCK
)
530 SLang_exit_error ("SLsys_getkey: EIO error.");
533 return SLANG_GETKEY_ERROR
;
537 return SLANG_GETKEY_ERROR
;
539 return((unsigned int) c
);