Original patch as attached on the bugreport
[midnight-commander.git] / slang / slutty.c
blobda07d9851fbfcd148eed53808c0de43a75586745
1 /* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
2 /*
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,
20 USA.
23 #include "slinclud.h"
25 #include <signal.h>
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> */
31 #endif
33 #include <sys/time.h>
34 #include <sys/types.h>
36 #ifdef SYSV
37 # include <fcntl.h>
38 # ifndef CRAY
39 # include <sys/termio.h>
40 # include <sys/stream.h>
41 # include <sys/ptem.h>
42 # include <sys/tty.h>
43 # endif
44 #endif
46 #ifdef __BEOS__
47 /* Prototype for select */
48 # include <net/socket.h>
49 #endif
51 #include <sys/file.h>
53 #ifndef sun
54 # include <sys/ioctl.h>
55 #endif
57 #ifdef __QNX__
58 # include <sys/select.h>
59 #endif
61 #include <sys/stat.h>
62 #include <errno.h>
64 #if defined (_AIX) && !defined (FD_SET)
65 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
66 #endif
68 #ifndef O_RDWR
69 # include <fcntl.h>
70 #endif
72 #include "slang.h"
73 #include "_slang.h"
75 int SLang_TT_Read_FD = -1;
76 int SLang_TT_Baud_Rate;
78 #ifdef HAVE_TERMIOS_H
79 # if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
80 # undef HAVE_TERMIOS_H
81 # endif
82 #endif
84 #ifndef HAVE_TERMIOS_H
86 # if !defined(CBREAK) && defined(sun)
87 # ifndef BSD_COMP
88 # define BSD_COMP 1
89 # endif
90 # include <sys/ioctl.h>
91 # endif
93 typedef struct
95 struct tchars t;
96 struct ltchars lt;
97 struct sgttyb s;
99 TTY_Termio_Type;
100 #else
101 # include <termios.h>
102 typedef struct termios TTY_Termio_Type;
103 #endif
105 static TTY_Termio_Type Old_TTY;
107 #ifdef HAVE_TERMIOS_H
108 typedef SLCONST struct
110 unsigned int key;
111 unsigned int value;
112 } Baud_Rate_Type;
114 static Baud_Rate_Type Baud_Rates [] =
116 #ifdef B0
117 {B0, 0},
118 #endif
119 #ifdef B50
120 {B50, 50},
121 #endif
122 #ifdef B75
123 {B75, 75},
124 #endif
125 #ifdef B110
126 {B110, 110},
127 #endif
128 #ifdef B134
129 {B134, 134},
130 #endif
131 #ifdef B150
132 {B150, 150},
133 #endif
134 #ifdef B200
135 {B200, 200},
136 #endif
137 #ifdef B300
138 {B300, 300},
139 #endif
140 #ifdef B600
141 {B600, 600},
142 #endif
143 #ifdef B1200
144 {B1200, 1200},
145 #endif
146 #ifdef B1800
147 {B1800, 1800},
148 #endif
149 #ifdef B2400
150 {B2400, 2400},
151 #endif
152 #ifdef B4800
153 {B4800, 4800},
154 #endif
155 #ifdef B9600
156 {B9600, 9600},
157 #endif
158 #ifdef B19200
159 {B19200, 19200},
160 #endif
161 #ifdef B38400
162 {B38400, 38400},
163 #endif
164 #ifdef B57600
165 {B57600, 57600},
166 #endif
167 #ifdef B115200
168 {B115200, 115200},
169 #endif
170 #ifdef B230400
171 {B230400, 230400},
172 #endif
173 {0, 0}
176 static void
177 set_baud_rate (TTY_Termio_Type *tty)
179 #ifdef HAVE_CFGETOSPEED
180 unsigned int speed;
181 Baud_Rate_Type *b, *bmax;
183 if (SLang_TT_Baud_Rate)
184 return; /* already set */
186 speed = (unsigned int) cfgetospeed (tty);
188 b = Baud_Rates;
189 bmax = b + (sizeof (Baud_Rates)/sizeof(Baud_Rates[0]));
190 while (b < bmax)
192 if (b->key == speed)
194 SLang_TT_Baud_Rate = b->value;
195 return;
197 b++;
199 #else
200 (void) tty;
201 #endif
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)
209 #else
210 # ifdef TCGETS
211 # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
212 # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
213 # else
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)
223 # endif
224 #endif
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
231 #else
232 # ifdef _POSIX_VDISABLE
233 # define NULL_VALUE _POSIX_VDISABLE
234 # else
235 # define NULL_VALUE 255
236 # endif
237 #endif
239 int SLang_init_tty (int abort_char, int no_flow_control, int opost)
241 TTY_Termio_Type newtty;
243 SLsig_block_signals ();
245 if (TTY_Inited)
247 SLsig_unblock_signals ();
248 return 0;
251 TTY_Open = 0;
253 if ((SLang_TT_Read_FD == -1)
254 || (1 != isatty (SLang_TT_Read_FD)))
256 #ifdef O_RDWR
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)
261 TTY_Open = 1;
263 # endif
264 #endif
265 if (TTY_Open == 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.");
274 return -1;
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))
287 if (errno != EINTR)
289 SLsig_unblock_signals ();
290 return -1;
294 while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &newtty))
296 if (errno != EINTR)
298 SLsig_unblock_signals ();
299 return -1;
303 #ifndef HAVE_TERMIOS_H
304 (void) opost;
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; */
309 newtty.t.t_eofc = 1;
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????? */
317 #else
319 /* get baud rate */
321 newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);
322 #ifdef ISTRIP
323 /* newtty.c_iflag &= ~ISTRIP; */
324 #endif
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 */
339 #ifdef VDSUSP
340 newtty.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
341 #endif
342 #ifdef VLNEXT
343 newtty.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V ? */
344 #endif
345 #ifdef VSWTCH
346 newtty.c_cc[VSWTCH] = NULL_VALUE; /* to ignore who knows what */
347 #endif
348 #endif /* NOT HAVE_TERMIOS_H */
350 while (-1 == SET_TERMIOS(SLang_TT_Read_FD, &newtty))
352 if (errno != EINTR)
354 SLsig_unblock_signals ();
355 return -1;
359 TTY_Inited = 1;
360 SLsig_unblock_signals ();
361 return 0;
364 void SLtty_set_suspend_state (int mode)
366 TTY_Termio_Type newtty;
368 SLsig_block_signals ();
370 if (TTY_Inited == 0)
372 SLsig_unblock_signals ();
373 return;
376 while ((-1 == GET_TERMIOS (SLang_TT_Read_FD, &newtty))
377 && (errno == EINTR))
380 #ifndef HAVE_TERMIOS_H
381 /* I do not know if all systems define the t_dsuspc field */
382 if (mode == 0)
384 newtty.lt.t_suspc = 255;
385 newtty.lt.t_dsuspc = 255;
387 else
389 newtty.lt.t_suspc = Old_TTY.lt.t_suspc;
390 newtty.lt.t_dsuspc = Old_TTY.lt.t_dsuspc;
392 #else
393 if (mode == 0)
395 newtty.c_cc[VSUSP] = NULL_VALUE;
396 #ifdef VDSUSP
397 newtty.c_cc[VDSUSP] = NULL_VALUE;
398 #endif
400 else
402 newtty.c_cc[VSUSP] = Old_TTY.c_cc[VSUSP];
403 #ifdef VDSUSP
404 newtty.c_cc[VDSUSP] = Old_TTY.c_cc[VDSUSP];
405 #endif
407 #endif
409 while ((-1 == SET_TERMIOS (SLang_TT_Read_FD, &newtty))
410 && (errno == EINTR))
413 SLsig_unblock_signals ();
416 void SLang_reset_tty (void)
418 SLsig_block_signals ();
420 if (TTY_Inited == 0)
422 SLsig_unblock_signals ();
423 return;
426 while ((-1 == SET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
427 && (errno == EINTR))
430 if (TTY_Open)
432 while ((-1 == close (SLang_TT_Read_FD))
433 && (errno == EINTR))
436 TTY_Open = 0;
437 SLang_TT_Read_FD = -1;
440 TTY_Inited = 0;
441 SLsig_unblock_signals ();
444 static void default_sigint (int sig)
446 sig = errno; /* use parameter */
448 SLKeyBoard_Quit = 1;
449 if (SLang_Ignore_User_Abort == 0) SLang_set_error (SL_USER_BREAK);
450 SLsignal_intr (SIGINT, default_sigint);
451 errno = sig;
454 int SLang_set_abort_signal (void (*hand)(int))
456 int save_errno = errno;
457 SLSig_Fun_Type *f;
459 if (hand == NULL) hand = default_sigint;
460 f = SLsignal_intr (SIGINT, hand);
462 errno = save_errno;
464 if (f == (SLSig_Fun_Type *) SIG_ERR)
465 return -1;
467 return 0;
470 #ifndef FD_SET
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))
474 typedef int fd_set;
475 #endif
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)
483 struct timeval wait;
484 long usecs, secs;
486 if ((TTY_Inited == 0)
487 || (SLang_TT_Read_FD < 0))
489 errno = EBADF;
490 return -1;
493 if (tsecs >= 0)
495 secs = tsecs / 10;
496 usecs = (tsecs % 10) * 100000;
498 else
500 tsecs = -tsecs;
501 secs = tsecs / 1000;
502 usecs = (tsecs % 1000) * 1000;
505 wait.tv_sec = secs;
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) ())
523 return -1;
525 if (save_tty_fd != SLang_TT_Read_FD)
526 return -1;
529 return 0;
532 unsigned int _pSLsys_getkey (void)
534 unsigned char c;
536 if (TTY_Inited == 0)
538 int ic = fgetc (stdin);
539 if (ic == EOF) return SLANG_GETKEY_ERROR;
540 return (unsigned int) ic;
543 while (1)
545 int ret;
547 if (SLKeyBoard_Quit)
548 return SLang_Abort_Char;
550 if (0 == (ret = _pSLsys_input_pending (100)))
551 continue;
553 if (ret != -1)
554 break;
556 if (SLKeyBoard_Quit)
557 return SLang_Abort_Char;
559 if (errno == EINTR)
561 if (-1 == handle_interrupt ())
562 return SLANG_GETKEY_ERROR;
564 continue;
567 break; /* let read handle it */
570 while (1)
572 int status = read(SLang_TT_Read_FD, (char *) &c, 1);
574 if (status > 0)
575 break;
577 if (status == 0)
579 /* We are at the end of a file. Let application handle it. */
580 return SLANG_GETKEY_ERROR;
583 if (errno == EINTR)
585 if (-1 == handle_interrupt ())
586 return SLANG_GETKEY_ERROR;
588 if (SLKeyBoard_Quit)
589 return SLang_Abort_Char;
591 continue;
593 #ifdef EAGAIN
594 if (errno == EAGAIN)
596 sleep (1);
597 continue;
599 #endif
600 #ifdef EWOULDBLOCK
601 if (errno == EWOULDBLOCK)
603 sleep (1);
604 continue;
606 #endif
607 #ifdef EIO
608 if (errno == EIO)
610 SLang_verror (SL_Read_Error, "_pSLsys_getkey: EIO error");
612 #endif
613 return SLANG_GETKEY_ERROR;
616 return((unsigned int) c);