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 */
72 int SLang_TT_Read_FD
= -1;
73 int SLang_TT_Baud_Rate
;
77 # if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
78 # undef HAVE_TERMIOS_H
82 #ifndef HAVE_TERMIOS_H
84 # if !defined(CBREAK) && defined(sun)
88 # include <sys/ioctl.h>
100 typedef struct termios TTY_Termio_Type
;
103 static TTY_Termio_Type Old_TTY
;
105 #ifdef HAVE_TERMIOS_H
140 #ifdef HAVE_TERMIOS_H
141 # define GET_TERMIOS(fd, x) tcgetattr(fd, x)
142 # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
145 # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
146 # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
148 # define X(x,m) &(((TTY_Termio_Type *)(x))->m)
149 # define GET_TERMIOS(fd, x) \
150 ((ioctl(fd, TIOCGETC, X(x,t)) || \
151 ioctl(fd, TIOCGLTC, X(x,lt)) || \
152 ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
153 # define SET_TERMIOS(fd, x) \
154 ((ioctl(fd, TIOCSETC, X(x,t)) ||\
155 ioctl(fd, TIOCSLTC, X(x,lt)) || \
156 ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
160 static int TTY_Inited
= 0;
161 static int TTY_Open
= 0;
163 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
164 # define NULL_VALUE -1
166 # ifdef _POSIX_VDISABLE
167 # define NULL_VALUE _POSIX_VDISABLE
169 # define NULL_VALUE 255
174 speed_t2baud_rate (speed_t s
)
178 for (i
= 0; i
< sizeof (Baud_Rates
)/sizeof (Baud_Rates
[0]); i
++)
179 if (Baud_Rates
[i
].key
== s
)
180 return (Baud_Rates
[i
].value
);
184 int SLang_init_tty (int abort_char
, int no_flow_control
, int opost
)
186 TTY_Termio_Type newtty
;
188 SLsig_block_signals ();
192 SLsig_unblock_signals ();
198 if ((SLang_TT_Read_FD
== -1)
199 || (1 != isatty (SLang_TT_Read_FD
)))
203 # ifndef __BEOS__ /* I have been told that BEOS will HANG if passed /dev/tty */
204 if ((SLang_TT_Read_FD
= open("/dev/tty", O_RDWR
)) >= 0)
215 /* In the Midnight Commander we bind stderr sometimes to a pipe. If we
216 use stderr for terminal input and call SLang_getkey while stderr is
217 bound to a pipe MC will hang completly in SLsys_input_pending.
218 NOTE: There's an independent fix for this problem in src/slint.c for
219 the case that the Midnight Commander is linked against a shared slang
220 library compiled from different sources.
222 SLang_TT_Read_FD
= fileno (stderr
);
223 if (1 != isatty (SLang_TT_Read_FD
))
226 SLang_TT_Read_FD
= fileno (stdin
);
227 if (1 != isatty (SLang_TT_Read_FD
))
229 fprintf (stderr
, "Failed to open terminal.");
236 SLang_Abort_Char
= abort_char
;
238 /* Some systems may not permit signals to be blocked. As a result, the
239 * return code must be checked.
241 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
245 SLsig_unblock_signals ();
250 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
254 SLsig_unblock_signals ();
259 #ifndef HAVE_TERMIOS_H
260 newtty
.s
.sg_flags
&= ~(ECHO
);
261 newtty
.s
.sg_flags
&= ~(CRMOD
);
262 /* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
264 if (abort_char
== -1) SLang_Abort_Char
= newtty
.t
.t_intrc
;
265 newtty
.t
.t_intrc
= SLang_Abort_Char
; /* ^G */
266 newtty
.t
.t_quitc
= 255;
267 newtty
.lt
.t_suspc
= 255; /* to ignore ^Z */
268 newtty
.lt
.t_dsuspc
= 255; /* to ignore ^Y */
269 newtty
.lt
.t_lnextc
= 255;
270 newtty
.s
.sg_flags
|= CBREAK
; /* do I want cbreak or raw????? */
275 /* [not only QNX related !?!]
276 * ECHO(0x08) is a c_lflag bit, it means here PARMRK(0x08) in c_iflag!!!
278 /*newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);*/
279 newtty
.c_iflag
&= ~(INLCR
| ICRNL
);
281 /* newtty.c_iflag &= ~ISTRIP; */
283 if (opost
== 0) newtty
.c_oflag
&= ~OPOST
;
285 if (SLang_TT_Baud_Rate
== 0)
287 /* Note: if this generates an compiler error, simply remove
289 #ifdef HAVE_CFGETOSPEED
290 SLang_TT_Baud_Rate
= cfgetospeed (&newtty
);
292 SLang_TT_Baud_Rate
= speed_t2baud_rate (SLang_TT_Baud_Rate
);
294 if (no_flow_control
) newtty
.c_iflag
&= ~IXON
; else newtty
.c_iflag
|= IXON
;
296 newtty
.c_cc
[VMIN
] = 1;
297 newtty
.c_cc
[VTIME
] = 0;
298 newtty
.c_cc
[VEOF
] = 1;
299 newtty
.c_lflag
= ISIG
| NOFLSH
;
300 if (abort_char
== -1) SLang_Abort_Char
= newtty
.c_cc
[VINTR
];
301 newtty
.c_cc
[VINTR
] = SLang_Abort_Char
; /* ^G */
302 newtty
.c_cc
[VQUIT
] = NULL_VALUE
;
303 newtty
.c_cc
[VSUSP
] = NULL_VALUE
; /* to ignore ^Z */
305 newtty
.c_cc
[VSWTCH
] = NULL_VALUE
; /* to ignore who knows what */
307 #endif /* NOT HAVE_TERMIOS_H */
309 while (-1 == SET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
313 SLsig_unblock_signals ();
319 SLsig_unblock_signals ();
323 void SLtty_set_suspend_state (int mode
)
325 TTY_Termio_Type newtty
;
327 SLsig_block_signals ();
331 SLsig_unblock_signals ();
335 while ((-1 == GET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
339 #ifndef HAVE_TERMIOS_H
340 if (mode
== 0) newtty
.lt
.t_suspc
= 255;
341 else newtty
.lt
.t_suspc
= Old_TTY
.lt
.t_suspc
;
343 if (mode
== 0) newtty
.c_cc
[VSUSP
] = NULL_VALUE
;
344 else newtty
.c_cc
[VSUSP
] = Old_TTY
.c_cc
[VSUSP
];
347 while ((-1 == SET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
351 SLsig_unblock_signals ();
354 void SLang_reset_tty (void)
356 SLsig_block_signals ();
360 SLsig_unblock_signals ();
364 while ((-1 == SET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
370 while ((-1 == close (SLang_TT_Read_FD
))
375 SLang_TT_Read_FD
= -1;
379 SLsig_unblock_signals ();
382 static void default_sigint (int sig
)
384 sig
= errno
; /* use parameter */
387 if (SLang_Ignore_User_Abort
== 0) SLang_Error
= USER_BREAK
;
388 SLsignal_intr (SIGINT
, default_sigint
);
392 void SLang_set_abort_signal (void (*hand
)(int))
394 int save_errno
= errno
;
396 if (hand
== NULL
) hand
= default_sigint
;
397 SLsignal_intr (SIGINT
, hand
);
403 #define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
404 #define FD_ZERO(tthis) *(tthis) = 0
405 #define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
409 static fd_set Read_FD_Set
;
412 /* HACK: If > 0, use 1/10 seconds. If < 0, use 1/1000 seconds */
414 int SLsys_input_pending(int tsecs
)
419 if (TTY_Inited
== 0) return -1;
424 usecs
= (tsecs
% 10) * 100000;
430 usecs
= (tsecs
% 1000) * 1000;
434 wait
.tv_usec
= usecs
;
436 FD_ZERO(&Read_FD_Set
);
437 FD_SET(SLang_TT_Read_FD
, &Read_FD_Set
);
439 return select(SLang_TT_Read_FD
+ 1, &Read_FD_Set
, NULL
, NULL
, &wait
);
443 int (*SLang_getkey_intr_hook
) (void);
445 static int handle_interrupt (void)
447 if (SLang_getkey_intr_hook
!= NULL
)
449 int save_tty_fd
= SLang_TT_Read_FD
;
451 if (-1 == (*SLang_getkey_intr_hook
) ())
454 if (save_tty_fd
!= SLang_TT_Read_FD
)
461 unsigned int SLsys_getkey (void)
468 int ic
= fgetc (stdin
);
469 if (ic
== EOF
) return SLANG_GETKEY_ERROR
;
470 return (unsigned int) ic
;
478 return SLang_Abort_Char
;
480 if (0 == (ret
= SLsys_input_pending (100)))
487 return SLang_Abort_Char
;
491 if (-1 == handle_interrupt ())
492 return SLANG_GETKEY_ERROR
;
497 break; /* let read handle it */
500 while (-1 == (i
= read(SLang_TT_Read_FD
, (char *) &c
, 1)))
504 if (-1 == handle_interrupt ())
505 return SLANG_GETKEY_ERROR
;
508 return SLang_Abort_Char
;
520 if (errno
== EWOULDBLOCK
)
529 SLang_exit_error ("SLsys_getkey: EIO error.");
532 return SLANG_GETKEY_ERROR
;
536 return SLANG_GETKEY_ERROR
;
538 return((unsigned int) c
);