1 /* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
3 Copyright (C) 2004, 2005, 2006 John E. Davis
5 This file is part of the S-Lang Library.
7 The S-Lang Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The S-Lang Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
26 /* sequent support thanks to Kenneth Lorber <keni@oasys.dt.navy.mil> */
27 /* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea@erlm.siemens.de */
29 #if defined (_AIX) && !defined (_ALL_SOURCE)
30 # define _ALL_SOURCE /* so NBBY is defined in <sys/types.h> */
34 #include <sys/types.h>
39 # include <sys/termio.h>
40 # include <sys/stream.h>
41 # include <sys/ptem.h>
47 /* Prototype for select */
48 # include <net/socket.h>
54 # include <sys/ioctl.h>
58 # include <sys/select.h>
64 #if defined (_AIX) && !defined (FD_SET)
65 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
75 int SLang_TT_Read_FD
= -1;
76 int SLang_TT_Baud_Rate
;
79 # if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
80 # undef HAVE_TERMIOS_H
84 #ifndef HAVE_TERMIOS_H
86 # if !defined(CBREAK) && defined(sun)
90 # include <sys/ioctl.h>
101 # include <termios.h>
102 typedef struct termios TTY_Termio_Type
;
105 static TTY_Termio_Type Old_TTY
;
107 #ifdef HAVE_TERMIOS_H
108 typedef SLCONST
struct
114 static Baud_Rate_Type Baud_Rates
[] =
177 set_baud_rate (TTY_Termio_Type
*tty
)
179 #ifdef HAVE_CFGETOSPEED
181 Baud_Rate_Type
*b
, *bmax
;
183 if (SLang_TT_Baud_Rate
)
184 return; /* already set */
186 speed
= (unsigned int) cfgetospeed (tty
);
189 bmax
= b
+ (sizeof (Baud_Rates
)/sizeof(Baud_Rates
[0]));
194 SLang_TT_Baud_Rate
= b
->value
;
204 #endif /* HAVE_TERMIOS_H */
206 #ifdef HAVE_TERMIOS_H
207 # define GET_TERMIOS(fd, x) tcgetattr(fd, x)
208 # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
211 # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
212 # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
214 # define X(x,m) &(((TTY_Termio_Type *)(x))->m)
215 # define GET_TERMIOS(fd, x) \
216 ((ioctl(fd, TIOCGETC, X(x,t)) || \
217 ioctl(fd, TIOCGLTC, X(x,lt)) || \
218 ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
219 # define SET_TERMIOS(fd, x) \
220 ((ioctl(fd, TIOCSETC, X(x,t)) ||\
221 ioctl(fd, TIOCSLTC, X(x,lt)) || \
222 ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
226 static int TTY_Inited
= 0;
227 static int TTY_Open
= 0;
229 #ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
230 # define NULL_VALUE -1
232 # ifdef _POSIX_VDISABLE
233 # define NULL_VALUE _POSIX_VDISABLE
235 # define NULL_VALUE 255
239 int SLang_init_tty (int abort_char
, int no_flow_control
, int opost
)
241 TTY_Termio_Type newtty
;
243 SLsig_block_signals ();
247 SLsig_unblock_signals ();
253 if ((SLang_TT_Read_FD
== -1)
254 || (1 != isatty (SLang_TT_Read_FD
)))
257 # if !defined(__BEOS__) && !defined(__APPLE__)
258 /* I have been told that BEOS will HANG if passed /dev/tty */
259 if ((SLang_TT_Read_FD
= open("/dev/tty", O_RDWR
)) >= 0)
267 SLang_TT_Read_FD
= fileno (stderr
);
268 if (1 != isatty (SLang_TT_Read_FD
))
270 SLang_TT_Read_FD
= fileno (stdin
);
271 if (1 != isatty (SLang_TT_Read_FD
))
273 fprintf (stderr
, "Failed to open terminal.");
280 SLang_Abort_Char
= abort_char
;
282 /* Some systems may not permit signals to be blocked. As a result, the
283 * return code must be checked.
285 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
289 SLsig_unblock_signals ();
294 while (-1 == GET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
298 SLsig_unblock_signals ();
303 #ifndef HAVE_TERMIOS_H
305 (void) no_flow_control
;
306 newtty
.s
.sg_flags
&= ~(ECHO
);
307 newtty
.s
.sg_flags
&= ~(CRMOD
);
308 /* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
310 if (abort_char
== -1) SLang_Abort_Char
= newtty
.t
.t_intrc
;
311 newtty
.t
.t_intrc
= SLang_Abort_Char
; /* ^G */
312 newtty
.t
.t_quitc
= 255;
313 newtty
.lt
.t_suspc
= 255; /* to ignore ^Z */
314 newtty
.lt
.t_dsuspc
= 255; /* to ignore ^Y */
315 newtty
.lt
.t_lnextc
= 255;
316 newtty
.s
.sg_flags
|= CBREAK
; /* do I want cbreak or raw????? */
321 newtty
.c_iflag
&= ~(ECHO
| INLCR
| ICRNL
);
323 /* newtty.c_iflag &= ~ISTRIP; */
325 if (opost
== 0) newtty
.c_oflag
&= ~OPOST
;
327 set_baud_rate (&newtty
);
329 if (no_flow_control
) newtty
.c_iflag
&= ~IXON
; else newtty
.c_iflag
|= IXON
;
331 newtty
.c_cc
[VEOF
] = 1;
332 newtty
.c_cc
[VMIN
] = 1;
333 newtty
.c_cc
[VTIME
] = 0;
334 newtty
.c_lflag
= ISIG
| NOFLSH
;
335 if (abort_char
== -1) SLang_Abort_Char
= newtty
.c_cc
[VINTR
];
336 newtty
.c_cc
[VINTR
] = SLang_Abort_Char
; /* ^G */
337 newtty
.c_cc
[VQUIT
] = NULL_VALUE
;
338 newtty
.c_cc
[VSUSP
] = NULL_VALUE
; /* to ignore ^Z */
340 newtty
.c_cc
[VDSUSP
] = NULL_VALUE
; /* to ignore ^Y */
343 newtty
.c_cc
[VLNEXT
] = NULL_VALUE
; /* to ignore ^V ? */
346 newtty
.c_cc
[VSWTCH
] = NULL_VALUE
; /* to ignore who knows what */
348 #endif /* NOT HAVE_TERMIOS_H */
350 while (-1 == SET_TERMIOS(SLang_TT_Read_FD
, &newtty
))
354 SLsig_unblock_signals ();
360 SLsig_unblock_signals ();
364 void SLtty_set_suspend_state (int mode
)
366 TTY_Termio_Type newtty
;
368 SLsig_block_signals ();
372 SLsig_unblock_signals ();
376 while ((-1 == GET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
380 #ifndef HAVE_TERMIOS_H
381 /* I do not know if all systems define the t_dsuspc field */
384 newtty
.lt
.t_suspc
= 255;
385 newtty
.lt
.t_dsuspc
= 255;
389 newtty
.lt
.t_suspc
= Old_TTY
.lt
.t_suspc
;
390 newtty
.lt
.t_dsuspc
= Old_TTY
.lt
.t_dsuspc
;
395 newtty
.c_cc
[VSUSP
] = NULL_VALUE
;
397 newtty
.c_cc
[VDSUSP
] = NULL_VALUE
;
402 newtty
.c_cc
[VSUSP
] = Old_TTY
.c_cc
[VSUSP
];
404 newtty
.c_cc
[VDSUSP
] = Old_TTY
.c_cc
[VDSUSP
];
409 while ((-1 == SET_TERMIOS (SLang_TT_Read_FD
, &newtty
))
413 SLsig_unblock_signals ();
416 void SLang_reset_tty (void)
418 SLsig_block_signals ();
422 SLsig_unblock_signals ();
426 while ((-1 == SET_TERMIOS(SLang_TT_Read_FD
, &Old_TTY
))
432 while ((-1 == close (SLang_TT_Read_FD
))
437 SLang_TT_Read_FD
= -1;
441 SLsig_unblock_signals ();
444 static void default_sigint (int sig
)
446 sig
= errno
; /* use parameter */
449 if (SLang_Ignore_User_Abort
== 0) SLang_set_error (SL_USER_BREAK
);
450 SLsignal_intr (SIGINT
, default_sigint
);
454 int SLang_set_abort_signal (void (*hand
)(int))
456 int save_errno
= errno
;
459 if (hand
== NULL
) hand
= default_sigint
;
460 f
= SLsignal_intr (SIGINT
, hand
);
464 if (f
== (SLSig_Fun_Type
*) SIG_ERR
)
471 #define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
472 #define FD_ZERO(tthis) *(tthis) = 0
473 #define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
477 static fd_set Read_FD_Set
;
479 /* HACK: If > 0, use 1/10 seconds. If < 0, use 1/1000 seconds */
481 int _pSLsys_input_pending(int tsecs
)
486 if ((TTY_Inited
== 0)
487 || (SLang_TT_Read_FD
< 0))
496 usecs
= (tsecs
% 10) * 100000;
502 usecs
= (tsecs
% 1000) * 1000;
506 wait
.tv_usec
= usecs
;
508 FD_ZERO(&Read_FD_Set
);
509 FD_SET(SLang_TT_Read_FD
, &Read_FD_Set
);
511 return select(SLang_TT_Read_FD
+ 1, &Read_FD_Set
, NULL
, NULL
, &wait
);
514 int (*SLang_getkey_intr_hook
) (void);
516 static int handle_interrupt (void)
518 if (SLang_getkey_intr_hook
!= NULL
)
520 int save_tty_fd
= SLang_TT_Read_FD
;
522 if (-1 == (*SLang_getkey_intr_hook
) ())
525 if (save_tty_fd
!= SLang_TT_Read_FD
)
532 unsigned int _pSLsys_getkey (void)
538 int ic
= fgetc (stdin
);
539 if (ic
== EOF
) return SLANG_GETKEY_ERROR
;
540 return (unsigned int) ic
;
548 return SLang_Abort_Char
;
550 if (0 == (ret
= _pSLsys_input_pending (100)))
557 return SLang_Abort_Char
;
561 if (-1 == handle_interrupt ())
562 return SLANG_GETKEY_ERROR
;
567 break; /* let read handle it */
572 int status
= read(SLang_TT_Read_FD
, (char *) &c
, 1);
579 /* We are at the end of a file. Let application handle it. */
580 return SLANG_GETKEY_ERROR
;
585 if (-1 == handle_interrupt ())
586 return SLANG_GETKEY_ERROR
;
589 return SLang_Abort_Char
;
601 if (errno
== EWOULDBLOCK
)
610 SLang_verror (SL_Read_Error
, "_pSLsys_getkey: EIO error");
613 return SLANG_GETKEY_ERROR
;
616 return((unsigned int) c
);