Translated til menu left and right ...
[midnight-commander.git] / slang / slutty.c
blobdc7e78118133035ea46eff0a5c1574a0591cccf9
1 /* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
2 /* Copyright (c) 1992, 1995 John E. Davis
3 * All rights reserved.
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Perl Artistic License.
7 */
10 #include "config.h"
12 #include <stdio.h>
13 #include <signal.h>
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> */
19 #endif
21 #ifdef HAVE_STDLIB_H
22 # include <stdlib.h>
23 #endif
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
29 #include <sys/time.h>
30 #include <sys/types.h>
32 #ifdef SYSV
33 # include <fcntl.h>
34 # ifndef CRAY
35 # include <sys/termio.h>
36 # include <sys/stream.h>
37 # include <sys/ptem.h>
38 # include <sys/tty.h>
39 # endif
40 #endif
43 #ifdef __BEOS__
44 /* Prototype for select */
45 # include <net/socket.h>
46 #endif
48 #include <sys/file.h>
50 #ifndef sun
51 # include <sys/ioctl.h>
52 #endif
54 #ifdef __QNX__
55 # include <sys/select.h>
56 #endif
58 #include <sys/stat.h>
59 #include <errno.h>
61 #if defined (_AIX) && !defined (FD_SET)
62 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
63 #endif
65 #ifndef O_RDWR
66 # include <fcntl.h>
67 #endif
70 #include "_slang.h"
72 int SLang_TT_Read_FD = -1;
73 int SLang_TT_Baud_Rate;
76 #ifdef HAVE_TERMIOS_H
77 # if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
78 # undef HAVE_TERMIOS_H
79 # endif
80 #endif
82 #ifndef HAVE_TERMIOS_H
84 # if !defined(CBREAK) && defined(sun)
85 # ifndef BSD_COMP
86 # define BSD_COMP 1
87 # endif
88 # include <sys/ioctl.h>
89 # endif
91 typedef struct
93 struct tchars t;
94 struct ltchars lt;
95 struct sgttyb s;
97 TTY_Termio_Type;
98 #else
99 # include <termios.h>
100 typedef struct termios TTY_Termio_Type;
101 #endif
103 static TTY_Termio_Type Old_TTY;
105 #ifdef HAVE_TERMIOS_H
106 static struct
108 speed_t key;
109 int value;
110 } Baud_Rates[] =
112 {B0, 0},
113 {B50, 50},
114 {B75, 75},
115 {B110, 110},
116 {B134, 134},
117 {B150, 150},
118 {B200, 200},
119 {B300, 300},
120 {B600, 600},
121 {B1200, 1200},
122 {B1800, 1800},
123 {B2400, 2400},
124 {B4800, 4800},
125 {B9600, 9600},
126 {B19200, 19200},
127 {B38400, 38400}
128 #ifdef B57600
129 , {B57600, 57600}
130 #endif
131 #ifdef B115200
132 , {B115200, 115200}
133 #endif
134 #ifdef B230400
135 , {B230400, 230400}
136 #endif
138 #endif
140 #ifdef HAVE_TERMIOS_H
141 # define GET_TERMIOS(fd, x) tcgetattr(fd, x)
142 # define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
143 #else
144 # ifdef TCGETS
145 # define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
146 # define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
147 # else
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)
157 # endif
158 #endif
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
165 #else
166 # ifdef _POSIX_VDISABLE
167 # define NULL_VALUE _POSIX_VDISABLE
168 # else
169 # define NULL_VALUE 255
170 # endif
171 #endif
173 static int
174 speed_t2baud_rate (speed_t s)
176 int i;
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);
181 return 0;
184 int SLang_init_tty (int abort_char, int no_flow_control, int opost)
186 TTY_Termio_Type newtty;
188 SLsig_block_signals ();
190 if (TTY_Inited)
192 SLsig_unblock_signals ();
193 return 0;
196 TTY_Open = 0;
198 if ((SLang_TT_Read_FD == -1)
199 || (1 != isatty (SLang_TT_Read_FD)))
201 #if 0
202 #ifdef O_RDWR
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)
206 TTY_Open = 1;
208 # endif
209 #endif
210 #endif /* 0 */
211 if (TTY_Open == 0)
214 #if 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))
224 #endif
226 SLang_TT_Read_FD = fileno (stdin);
227 if (1 != isatty (SLang_TT_Read_FD))
229 fprintf (stderr, "Failed to open terminal.");
230 return -1;
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))
243 if (errno != EINTR)
245 SLsig_unblock_signals ();
246 return -1;
250 while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &newtty))
252 if (errno != EINTR)
254 SLsig_unblock_signals ();
255 return -1;
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; */
263 newtty.t.t_eofc = 1;
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????? */
271 #else
273 /* get baud rate */
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);
280 #ifdef ISTRIP
281 /* newtty.c_iflag &= ~ISTRIP; */
282 #endif
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
288 the statement */
289 #ifdef HAVE_CFGETOSPEED
290 SLang_TT_Baud_Rate = cfgetospeed (&newtty);
291 #endif
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 */
304 #ifdef VSWTCH
305 newtty.c_cc[VSWTCH] = NULL_VALUE; /* to ignore who knows what */
306 #endif
307 #endif /* NOT HAVE_TERMIOS_H */
309 while (-1 == SET_TERMIOS(SLang_TT_Read_FD, &newtty))
311 if (errno != EINTR)
313 SLsig_unblock_signals ();
314 return -1;
318 TTY_Inited = 1;
319 SLsig_unblock_signals ();
320 return 0;
323 void SLtty_set_suspend_state (int mode)
325 TTY_Termio_Type newtty;
327 SLsig_block_signals ();
329 if (TTY_Inited == 0)
331 SLsig_unblock_signals ();
332 return;
335 while ((-1 == GET_TERMIOS (SLang_TT_Read_FD, &newtty))
336 && (errno == EINTR))
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;
342 #else
343 if (mode == 0) newtty.c_cc[VSUSP] = NULL_VALUE;
344 else newtty.c_cc[VSUSP] = Old_TTY.c_cc[VSUSP];
345 #endif
347 while ((-1 == SET_TERMIOS (SLang_TT_Read_FD, &newtty))
348 && (errno == EINTR))
351 SLsig_unblock_signals ();
354 void SLang_reset_tty (void)
356 SLsig_block_signals ();
358 if (TTY_Inited == 0)
360 SLsig_unblock_signals ();
361 return;
364 while ((-1 == SET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
365 && (errno == EINTR))
368 if (TTY_Open)
370 while ((-1 == close (SLang_TT_Read_FD))
371 && (errno == EINTR))
374 TTY_Open = 0;
375 SLang_TT_Read_FD = -1;
378 TTY_Inited = 0;
379 SLsig_unblock_signals ();
382 static void default_sigint (int sig)
384 sig = errno; /* use parameter */
386 SLKeyBoard_Quit = 1;
387 if (SLang_Ignore_User_Abort == 0) SLang_Error = USER_BREAK;
388 SLsignal_intr (SIGINT, default_sigint);
389 errno = sig;
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);
399 errno = save_errno;
402 #ifndef FD_SET
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))
406 typedef int fd_set;
407 #endif
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)
416 struct timeval wait;
417 long usecs, secs;
419 if (TTY_Inited == 0) return -1;
421 if (tsecs >= 0)
423 secs = tsecs / 10;
424 usecs = (tsecs % 10) * 100000;
426 else
428 tsecs = -tsecs;
429 secs = tsecs / 1000;
430 usecs = (tsecs % 1000) * 1000;
433 wait.tv_sec = secs;
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) ())
452 return -1;
454 if (save_tty_fd != SLang_TT_Read_FD)
455 return -1;
458 return 0;
461 unsigned int SLsys_getkey (void)
463 unsigned char c;
464 unsigned int i;
466 if (TTY_Inited == 0)
468 int ic = fgetc (stdin);
469 if (ic == EOF) return SLANG_GETKEY_ERROR;
470 return (unsigned int) ic;
473 while (1)
475 int ret;
477 if (SLKeyBoard_Quit)
478 return SLang_Abort_Char;
480 if (0 == (ret = SLsys_input_pending (100)))
481 continue;
483 if (ret != -1)
484 break;
486 if (SLKeyBoard_Quit)
487 return SLang_Abort_Char;
489 if (errno == EINTR)
491 if (-1 == handle_interrupt ())
492 return SLANG_GETKEY_ERROR;
494 continue;
497 break; /* let read handle it */
500 while (-1 == (i = read(SLang_TT_Read_FD, (char *) &c, 1)))
502 if (errno == EINTR)
504 if (-1 == handle_interrupt ())
505 return SLANG_GETKEY_ERROR;
507 if (SLKeyBoard_Quit)
508 return SLang_Abort_Char;
510 continue;
512 #ifdef EAGAIN
513 if (errno == EAGAIN)
515 sleep (1);
516 continue;
518 #endif
519 #ifdef EWOULDBLOCK
520 if (errno == EWOULDBLOCK)
522 sleep (1);
523 continue;
525 #endif
526 #ifdef EIO
527 if (errno == EIO)
529 SLang_exit_error ("SLsys_getkey: EIO error.");
531 #endif
532 return SLANG_GETKEY_ERROR;
535 if (i == 0)
536 return SLANG_GETKEY_ERROR;
538 return((unsigned int) c);