1: /* direct key io driver; signal handler
2:
3: Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
4:
5: This file is part of Gforth.
6:
7: Gforth is free software; you can redistribute it and/or
8: modify it under the terms of the GNU General Public License
9: as published by the Free Software Foundation; either version 2
10: of the License, or (at your option) any later version.
11:
12: This program 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
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with this program; if not, write to the Free Software
19: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20:
21: The following is stolen from the readline library for bash
22: */
23:
24: /*
25: Use -D_POSIX_VERSION for POSIX systems.
26: */
27:
28: #include "config.h"
29: #include <sys/time.h>
30: #include <sys/types.h>
31: #include <unistd.h>
32:
33: #if defined(apollo) || defined(_WIN32)
34: #define _POSIX_VERSION
35: #endif
36:
37: #if !defined(Solaris) && defined(sun) && defined(__svr4__)
38: #define Solaris
39: typedef unsigned int uint32_t;
40: #endif
41:
42: #include <stdio.h>
43: #include <signal.h>
44: #include <string.h>
45: #if !defined(apollo) && !defined(MSDOS)
46: #include <sys/ioctl.h>
47: #endif
48: #include <fcntl.h>
49: #include <sys/file.h>
50: #if defined(Solaris) && !defined(FIONREAD)
51: #include <sys/filio.h>
52: #endif
53: #include <setjmp.h>
54: #include "forth.h"
55: #include "io.h"
56:
57: #ifndef MSDOS
58: #if defined (__GNUC__)
59: # define alloca __builtin_alloca
60: #else
61: # if defined (sparc) || defined (HAVE_ALLOCA_H)
62: # include <alloca.h>
63: # endif
64: #endif
65:
66: #define NEW_TTY_DRIVER
67: #define HAVE_BSD_SIGNALS
68: /*
69: #ifndef apollo
70: #define USE_XON_XOFF
71: #endif
72: */
73:
74: #define HANDLE_SIGNALS
75:
76: /* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */
77: #if defined (USG) && !defined (hpux)
78: #undef HAVE_BSD_SIGNALS
79: #endif
80:
81: /* System V machines use termio. */
82: #if !defined (_POSIX_VERSION)
83: # if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX) || defined (ultrix) || defined (Solaris) || defined(_WIN32)
84: # undef NEW_TTY_DRIVER
85: # define TERMIO_TTY_DRIVER
86: # include <termio.h>
87: # if !defined (TCOON)
88: # define TCOON 1
89: # endif
90: # endif /* USG || hpux || Xenix || sgi || DUGX || ultrix*/
91: #endif /* !_POSIX_VERSION */
92:
93: /* Posix systems use termios and the Posix signal functions. */
94: #if defined (_POSIX_VERSION) || defined (NeXT)
95: # if !defined (TERMIOS_MISSING)
96: # undef NEW_TTY_DRIVER
97: # define TERMIOS_TTY_DRIVER
98: # include <termios.h>
99: # endif /* !TERMIOS_MISSING */
100: #endif /* _POSIX_VERSION || NeXT */
101:
102: #if defined (_POSIX_VERSION)
103: # define HAVE_POSIX_SIGNALS
104: # if !defined (O_NDELAY)
105: # define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */
106: # endif /* O_NDELAY */
107: #endif /* _POSIX_VERSION */
108:
109: /* Other (BSD) machines use sgtty. */
110: #if defined (NEW_TTY_DRIVER)
111: #include <sgtty.h>
112: #endif
113:
114: /* Define _POSIX_VDISABLE if we are not using the `new' tty driver and
115: it is not already defined. It is used both to determine if a
116: special character is disabled and to disable certain special
117: characters. Posix systems should set to 0, USG systems to -1. */
118: #if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)
119: # if defined (_POSIX_VERSION) || defined (NeXT)
120: # define _POSIX_VDISABLE 0
121: # else /* !_POSIX_VERSION */
122: # define _POSIX_VDISABLE -1
123: # endif /* !_POSIX_VERSION */
124: #endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE */
125:
126: #include <errno.h>
127: /* extern int errno; */
128:
129: #if defined (SHELL)
130: # include <posixstat.h>
131: #else
132: # include <sys/stat.h>
133: #endif /* !SHELL */
134: /* #define HACK_TERMCAP_MOTION */
135:
136: #if defined (USG) && defined (hpux)
137: # if !defined (USGr3)
138: # define USGr3
139: # endif /* USGr3 */
140: #endif /* USG && hpux */
141:
142: #if (defined (_POSIX_VERSION) || defined (USGr3)) && !defined(apollo)
143: # include <dirent.h>
144: # define direct dirent
145: # if defined (_POSIX_VERSION)
146: # define D_NAMLEN(d) (strlen ((d)->d_name))
147: # else /* !_POSIX_VERSION */
148: # define D_NAMLEN(d) ((d)->d_reclen)
149: # endif /* !_POSIX_VERSION */
150: #else /* !_POSIX_VERSION && !USGr3 */
151: # define D_NAMLEN(d) ((d)->d_namlen)
152: # if !defined (USG)
153: # include <sys/dir.h>
154: # else /* USG */
155: # if defined (Xenix)
156: # include <sys/ndir.h>
157: # else /* !Xenix */
158: # include <ndir.h>
159: # endif /* !Xenix */
160: # endif /* USG */
161: #endif /* !POSIX_VERSION && !USGr3 */
162:
163: #if defined (USG) && defined (TIOCGWINSZ)
164: # include <sys/stream.h>
165: # if defined (USGr4) || defined (USGr3)
166: # if defined (Symmetry) || defined (_SEQUENT_)
167: # include <sys/pte.h>
168: # else
169: # include <sys/ptem.h>
170: # endif /* !Symmetry || _SEQUENT_ */
171: # endif /* USGr4 */
172: #endif /* USG && TIOCGWINSZ */
173:
174: #if defined (TERMIOS_TTY_DRIVER)
175: static struct termios otio;
176: #else
177: static struct termio otio;
178: #endif /* !TERMIOS_TTY_DRIVER */
179:
180: /* Non-zero means echo characters as they are read. */
181: int readline_echoing_p = 1;
182:
183: /* The character that can generate an EOF. Really read from
184: the terminal driver... just defaulted here. */
185:
186: #ifndef CTRL
187: #define CTRL(key) ((key)-'@')
188: #endif
189:
190: static int eof_char = CTRL ('D');
191:
192: /* **************************************************************** */
193: /* */
194: /* Saving and Restoring the TTY */
195: /* */
196: /* **************************************************************** */
197:
198: /* Non-zero means that the terminal is in a prepped state. */
199: int terminal_prepped = 0;
200:
201: #if defined (NEW_TTY_DRIVER)
202:
203: /* Standard flags, including ECHO. */
204: static int original_tty_flags = 0;
205:
206: /* Local mode flags, like LPASS8. */
207: static int local_mode_flags = 0;
208:
209: /* Terminal characters. This has C-s and C-q in it. */
210: static struct tchars original_tchars;
211:
212: /* Local special characters. This has the interrupt characters in it. */
213: #if defined (TIOCGLTC)
214: static struct ltchars original_ltchars;
215: #endif
216:
217: /* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */
218:
219: #if defined (TIOCGETC)
220: #if defined (USE_XON_XOFF)
221:
222: int
223: bind_key (key, function)
224: int key;
225: Function *function;
226: {
227: if (key < 0)
228: return (key);
229:
230: if (key > 127 && key < 256)
231: {
232: if (keymap[ESC].type == ISKMAP)
233: {
234: Keymap escmap = (Keymap)keymap[ESC].function;
235:
236: key -= 128;
237: escmap[key].type = ISFUNC;
238: escmap[key].function = function;
239: return (0);
240: }
241: return (key);
242: }
243:
244: keymap[key].type = ISFUNC;
245: keymap[key].function = function;
246: return (0);
247: }
248: #endif
249: #endif
250:
251: /* We use this to get and set the tty_flags. */
252: static struct sgttyb the_ttybuff;
253:
254: #if defined (USE_XON_XOFF)
255: /* If the terminal was in xoff state when we got to it, then xon_char
256: contains the character that is supposed to start it again. */
257: static int xon_char, xoff_state;
258: #endif /* USE_XON_XOFF */
259:
260: /* **************************************************************** */
261: /* */
262: /* Bogus Flow Control */
263: /* */
264: /* **************************************************************** */
265:
266: restart_output (count, key)
267: int count, key;
268: {
269: int fildes = fileno (stdin);
270: #if defined (TIOCSTART)
271: #if defined (apollo)
272: ioctl (&fildes, TIOCSTART, 0);
273: #else
274: ioctl (fildes, TIOCSTART, 0);
275: #endif /* apollo */
276:
277: #else
278: # if defined (TERMIOS_TTY_DRIVER)
279: tcflow (fildes, TCOON);
280: # else
281: # if defined (TCXONC)
282: ioctl (fildes, TCXONC, TCOON);
283: # endif /* TCXONC */
284: # endif /* !TERMIOS_TTY_DRIVER */
285: #endif /* TIOCSTART */
286: }
287:
288: /* Put the terminal in CBREAK mode so that we can detect key presses. */
289: void prep_terminal ()
290: {
291: int tty = fileno (stdin);
292: #if defined (HAVE_BSD_SIGNALS)
293: int oldmask;
294: #endif /* HAVE_BSD_SIGNALS */
295:
296: if (terminal_prepped)
297: return;
298:
299: if (!isatty(tty)) { /* added by MdG */
300: terminal_prepped = 1; /* added by MdG */
301: return; /* added by MdG */
302: } /* added by MdG */
303:
304: oldmask = sigblock (sigmask (SIGINT));
305:
306: /* We always get the latest tty values. Maybe stty changed them. */
307: ioctl (tty, TIOCGETP, &the_ttybuff);
308: original_tty_flags = the_ttybuff.sg_flags;
309:
310: readline_echoing_p = (original_tty_flags & ECHO);
311:
312: #if defined (TIOCLGET)
313: ioctl (tty, TIOCLGET, &local_mode_flags);
314: #endif
315:
316: #if !defined (ANYP)
317: # define ANYP (EVENP | ODDP)
318: #endif
319:
320: /* If this terminal doesn't care how the 8th bit is used,
321: then we can use it for the meta-key. We check by seeing
322: if BOTH odd and even parity are allowed. */
323: if (the_ttybuff.sg_flags & ANYP)
324: {
325: #if defined (PASS8)
326: the_ttybuff.sg_flags |= PASS8;
327: #endif
328:
329: /* Hack on local mode flags if we can. */
330: #if defined (TIOCLGET) && defined (LPASS8)
331: {
332: int flags;
333: flags = local_mode_flags | LPASS8;
334: ioctl (tty, TIOCLSET, &flags);
335: }
336: #endif /* TIOCLGET && LPASS8 */
337: }
338:
339: #if defined (TIOCGETC)
340: {
341: struct tchars temp;
342:
343: ioctl (tty, TIOCGETC, &original_tchars);
344: temp = original_tchars;
345:
346: #if defined (USE_XON_XOFF)
347: /* Get rid of C-s and C-q.
348: We remember the value of startc (C-q) so that if the terminal is in
349: xoff state, the user can xon it by pressing that character. */
350: xon_char = temp.t_startc;
351: temp.t_stopc = -1;
352: temp.t_startc = -1;
353:
354: /* If there is an XON character, bind it to restart the output. */
355: if (xon_char != -1)
356: bind_key (xon_char, restart_output);
357: #endif /* USE_XON_XOFF */
358:
359: /* If there is an EOF char, bind eof_char to it. */
360: if (temp.t_eofc != -1)
361: eof_char = temp.t_eofc;
362:
363: #if defined (NO_KILL_INTR)
364: /* Get rid of C-\ and C-c. */
365: temp.t_intrc = temp.t_quitc = -1;
366: #endif /* NO_KILL_INTR */
367:
368: ioctl (tty, TIOCSETC, &temp);
369: }
370: #endif /* TIOCGETC */
371:
372: #if defined (TIOCGLTC)
373: {
374: struct ltchars temp;
375:
376: ioctl (tty, TIOCGLTC, &original_ltchars);
377: temp = original_ltchars;
378:
379: /* Make the interrupt keys go away. Just enough to make people
380: happy. */
381: temp.t_dsuspc = -1; /* C-y */
382: temp.t_lnextc = -1; /* C-v */
383:
384: ioctl (tty, TIOCSLTC, &temp);
385: }
386: #endif /* TIOCGLTC */
387:
388: the_ttybuff.sg_flags &= ~(ECHO | CRMOD);
389: the_ttybuff.sg_flags |= CBREAK;
390: ioctl (tty, TIOCSETN, &the_ttybuff);
391:
392: terminal_prepped = 1;
393:
394: #if defined (HAVE_BSD_SIGNALS)
395: sigsetmask (oldmask);
396: #endif
397: }
398:
399: /* Restore the terminal to its original state. */
400: void deprep_terminal ()
401: {
402: int tty = fileno (stdin);
403: #if defined (HAVE_BSD_SIGNALS)
404: int oldmask;
405: #endif
406:
407: if (!terminal_prepped)
408: return;
409:
410: /* Added by MdG */
411: if (!isatty(tty)) {
412: terminal_prepped = 0;
413: return;
414: }
415:
416: oldmask = sigblock (sigmask (SIGINT));
417:
418: the_ttybuff.sg_flags = original_tty_flags;
419: ioctl (tty, TIOCSETN, &the_ttybuff);
420: readline_echoing_p = 1;
421:
422: #if defined (TIOCLGET)
423: ioctl (tty, TIOCLSET, &local_mode_flags);
424: #endif
425:
426: #if defined (TIOCSLTC)
427: ioctl (tty, TIOCSLTC, &original_ltchars);
428: #endif
429:
430: #if defined (TIOCSETC)
431: ioctl (tty, TIOCSETC, &original_tchars);
432: #endif
433: terminal_prepped = 0;
434:
435: #if defined (HAVE_BSD_SIGNALS)
436: sigsetmask (oldmask);
437: #endif
438: }
439:
440: #else /* !defined (NEW_TTY_DRIVER) */
441:
442: #if !defined (VMIN)
443: #define VMIN VEOF
444: #endif
445:
446: #if !defined (VTIME)
447: #define VTIME VEOL
448: #endif
449:
450: void prep_terminal ()
451: {
452: int tty = fileno (stdin);
453: #if defined (TERMIOS_TTY_DRIVER)
454: struct termios tio;
455: #else
456: struct termio tio;
457: #endif /* !TERMIOS_TTY_DRIVER */
458:
459: #if defined (HAVE_POSIX_SIGNALS)
460: sigset_t set, oset;
461: #else
462: # if defined (HAVE_BSD_SIGNALS)
463: int oldmask;
464: # endif /* HAVE_BSD_SIGNALS */
465: #endif /* !HAVE_POSIX_SIGNALS */
466:
467: if (terminal_prepped)
468: return;
469:
470: if (!isatty(tty)) { /* added by MdG */
471: terminal_prepped = 1; /* added by MdG */
472: return; /* added by MdG */
473: } /* added by MdG */
474:
475: /* Try to keep this function from being INTerrupted. We can do it
476: on POSIX and systems with BSD-like signal handling. */
477: #if defined (HAVE_POSIX_SIGNALS)
478: sigemptyset (&set);
479: sigemptyset (&oset);
480: sigaddset (&set, SIGINT);
481: sigprocmask (SIG_BLOCK, &set, &oset);
482: #else /* !HAVE_POSIX_SIGNALS */
483: # if defined (HAVE_BSD_SIGNALS)
484: oldmask = sigblock (sigmask (SIGINT));
485: # endif /* HAVE_BSD_SIGNALS */
486: #endif /* !HAVE_POSIX_SIGNALS */
487:
488: #if defined (TERMIOS_TTY_DRIVER)
489: tcgetattr (tty, &tio);
490: #else
491: ioctl (tty, TCGETA, &tio);
492: #endif /* !TERMIOS_TTY_DRIVER */
493:
494: otio = tio;
495:
496: readline_echoing_p = (tio.c_lflag & ECHO);
497:
498: tio.c_lflag &= ~(ICANON | ECHO);
499:
500: if (otio.c_cc[VEOF] != _POSIX_VDISABLE)
501: eof_char = otio.c_cc[VEOF];
502:
503: #if defined (USE_XON_XOFF)
504: #if defined (IXANY)
505: tio.c_iflag &= ~(IXON | IXOFF | IXANY);
506: #else
507: /* `strict' Posix systems do not define IXANY. */
508: tio.c_iflag &= ~(IXON | IXOFF);
509: #endif /* IXANY */
510: #endif /* USE_XON_XOFF */
511:
512: /* Only turn this off if we are using all 8 bits. */
513: if ((tio.c_cflag & CSIZE) == CS8)
514: tio.c_iflag &= ~(ISTRIP | INPCK);
515:
516: /* Make sure we differentiate between CR and NL on input. */
517: tio.c_iflag &= ~(ICRNL | INLCR);
518:
519: #if !defined (HANDLE_SIGNALS)
520: tio.c_lflag &= ~ISIG;
521: #else
522: tio.c_lflag |= ISIG;
523: #endif
524:
525: tio.c_cc[VMIN] = 1;
526: tio.c_cc[VTIME] = 0;
527:
528: /* Turn off characters that we need on Posix systems with job control,
529: just to be sure. This includes ^Y and ^V. This should not really
530: be necessary. */
531: #if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_JOB_CONTROL)
532:
533: #if defined (VLNEXT)
534: tio.c_cc[VLNEXT] = _POSIX_VDISABLE;
535: #endif
536:
537: #if defined (VDSUSP)
538: tio.c_cc[VDSUSP] = _POSIX_VDISABLE;
539: #endif
540:
541: #endif /* POSIX && JOB_CONTROL */
542:
543: #if defined (TERMIOS_TTY_DRIVER)
544: tcsetattr (tty, TCSADRAIN, &tio);
545: tcflow (tty, TCOON); /* Simulate a ^Q. */
546: #else
547: ioctl (tty, TCSETAW, &tio);
548: ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */
549: #endif /* !TERMIOS_TTY_DRIVER */
550:
551: terminal_prepped = 1;
552:
553: #if defined (HAVE_POSIX_SIGNALS)
554: sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
555: #else
556: # if defined (HAVE_BSD_SIGNALS)
557: sigsetmask (oldmask);
558: # endif /* HAVE_BSD_SIGNALS */
559: #endif /* !HAVE_POSIX_SIGNALS */
560: }
561:
562: void deprep_terminal ()
563: {
564: int tty = fileno (stdin);
565:
566: /* Try to keep this function from being INTerrupted. We can do it
567: on POSIX and systems with BSD-like signal handling. */
568: #if defined (HAVE_POSIX_SIGNALS)
569: sigset_t set, oset;
570: #else /* !HAVE_POSIX_SIGNALS */
571: # if defined (HAVE_BSD_SIGNALS)
572: int oldmask;
573: # endif /* HAVE_BSD_SIGNALS */
574: #endif /* !HAVE_POSIX_SIGNALS */
575:
576: if (!terminal_prepped)
577: return;
578:
579: /* Added by MdG */
580: if (!isatty(tty)) {
581: terminal_prepped = 0;
582: return;
583: }
584:
585: #if defined (HAVE_POSIX_SIGNALS)
586: sigemptyset (&set);
587: sigemptyset (&oset);
588: sigaddset (&set, SIGINT);
589: sigprocmask (SIG_BLOCK, &set, &oset);
590: #else /* !HAVE_POSIX_SIGNALS */
591: # if defined (HAVE_BSD_SIGNALS)
592: oldmask = sigblock (sigmask (SIGINT));
593: # endif /* HAVE_BSD_SIGNALS */
594: #endif /* !HAVE_POSIX_SIGNALS */
595:
596: #if defined (TERMIOS_TTY_DRIVER)
597: tcsetattr (tty, TCSADRAIN, &otio);
598: tcflow (tty, TCOON); /* Simulate a ^Q. */
599: #else /* TERMIOS_TTY_DRIVER */
600: ioctl (tty, TCSETAW, &otio);
601: ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */
602: #endif /* !TERMIOS_TTY_DRIVER */
603:
604: terminal_prepped = 0;
605:
606: #if defined (HAVE_POSIX_SIGNALS)
607: sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
608: #else /* !HAVE_POSIX_SIGNALS */
609: # if defined (HAVE_BSD_SIGNALS)
610: sigsetmask (oldmask);
611: # endif /* HAVE_BSD_SIGNALS */
612: #endif /* !HAVE_POSIX_SIGNALS */
613: }
614: #endif /* NEW_TTY_DRIVER */
615:
616: /* If a character is available to be read, then read it
617: and stuff it into IBUFFER. Otherwise, just return. */
618:
619: long pending = -1L;
620:
621: long key_avail (FILE * stream)
622: {
623: int tty = fileno (stream);
624: int chars_avail = pending;
625: int result;
626:
627: if(!terminal_prepped) prep_terminal();
628:
629: #ifndef _WIN32
630: if(isatty (tty)) {
631: result = ioctl (tty, FIONREAD, &chars_avail);
632: }
633: #else
634: {
635: fd_set selin;
636: static int now[2] = { 0 , 0 };
637: int res;
638:
639: FD_ZERO(&selin);
640: FD_SET(tty, &selin);
641: chars_avail=select(1, &selin, NULL, NULL, now);
642: }
643: #endif
644:
645: if(chars_avail == -1L) {
646: unsigned char inchar;
647:
648: fcntl(tty, F_SETFL, O_NDELAY);
649: result = read(tty, &inchar, sizeof(char));
650: if(result == sizeof(char)) {
651: chars_avail = 1;
652: pending = (long)inchar;
653: } else {
654: chars_avail = 0;
655: }
656: fcntl(tty, F_SETFL, 0);
657: }
658:
659: return chars_avail;
660: }
661:
662: /* Get a key from the buffer of characters to be read.
663: Return the key in KEY.
664: Result is KEY if there was a key, or 0 if there wasn't. */
665:
666: /* When compiling and running in the `Posix' environment, Ultrix does
667: not restart system calls, so this needs to do it. */
668:
669: unsigned char getkey(FILE * stream)
670: {
671: int result;
672: unsigned char c;
673:
674: if(!terminal_prepped) prep_terminal();
675:
676: while (pending < 0)
677: {
678: result = read (fileno (stream), &c, sizeof (char));
679:
680: if (result == sizeof (char))
681: return /* (c == 0x7F ? 0x08 :*/ c /*)*/;
682:
683: /* If zero characters are returned, then the file that we are
684: reading from is empty! Return EOF in that case. */
685: if (result == 0)
686: return CTRL('D');
687:
688: /* If the error that we received was SIGINT, then try again,
689: this is simply an interrupted system call to read ().
690: Otherwise, some error ocurred, also signifying EOF. */
691: if (errno != EINTR)
692: return (EOF);
693: }
694:
695: result = (int) pending;
696: pending = -1L;
697:
698: return result;
699: }
700:
701: #ifdef TEST
702:
703: #include <time.h>
704:
705: int timewait=100000;
706:
707: int main()
708: {
709: unsigned char c;
710:
711: prep_terminal();
712:
713: do
714: {
715: int i=0;
716:
717: while(!key_avail(stdin))
718: {
719: printf("%04d",i);
720: fflush(stdout);
721: {
722: struct timeval timeout;
723: timeout.tv_sec=timewait/1000000;
724: timeout.tv_usec=timewait%1000000;
725: (void)select(0,0,0,0,&timeout);
726: }
727: i++;
728: printf("\b\b\b\b");
729: fflush(stdout);
730: }
731: c = getkey(stdin);
732: printf("%02x,",(int)c);
733: fflush(stdout);
734: } while(c != 0x1B);
735:
736: deprep_terminal();
737: puts("");
738: }
739: #endif
740: #endif /* MSDOS */
741:
742: /* signal handling adapted from pfe by Dirk Zoller (Copylefted) - anton */
743:
744: static void
745: graceful_exit (int sig)
746: {
747: deprep_terminal();
748: fprintf (stderr, "\n\n%s.\n", strsignal (sig));
749: exit (0x80|sig);
750: }
751:
752: jmp_buf throw_jmp_buf;
753:
754: static void
755: signal_throw(int sig)
756: {
757: int code;
758: struct {
759: int signal;
760: int throwcode;
761: } *p, throwtable[] = {
762: { SIGINT, -28 },
763: { SIGFPE, -55 },
764: #ifdef SIGBUS
765: { SIGBUS, -23 },
766: #endif
767: { SIGSEGV, -9 },
768: };
769: signal(sig,signal_throw);
770: for (code=-256-sig, p=throwtable; p<throwtable+(sizeof(throwtable)/sizeof(*p)); p++)
771: if (sig == p->signal) {
772: code = p->throwcode;
773: break;
774: }
775: longjmp(throw_jmp_buf,code); /* or use siglongjmp ? */
776: }
777:
778: UCell cols=80;
779: #if defined(MSDOS) || defined (_WIN32)
780: UCell rows=25;
781: #else
782: UCell rows=24;
783: #endif
784:
785: #ifdef SIGCONT
786: static void termprep (int sig)
787: {
788: signal(sig,termprep);
789: terminal_prepped=0;
790: }
791: #endif
792:
793: #ifdef SIGWINCH
794: void get_winsize()
795: {
796: #ifdef TIOCGWINSZ
797: struct winsize size;
798:
799: if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) {
800: rows = size.ws_row;
801: cols = size.ws_col;
802: }
803: #else
804: char *s, *ends;
805: unsigned long ul;
806: if (s=getenv("LINES")) {
807: rows=atoi(s);
808: if (rows==0)
809: rows=24;
810: }
811: if (s=getenv("COLUMNS")) {
812: rows=atoi(s);
813: if (rows==0)
814: cols=80;
815: }
816: #endif
817: }
818:
819: static void change_winsize(int sig)
820: {
821: signal(sig,change_winsize);
822: #ifdef TIOCGWINSZ
823: get_winsize();
824: #endif
825: }
826: #endif
827:
828: void install_signal_handlers (void)
829: {
830:
831: #if 0
832: /* these signals are handled right by default, no need to handle them;
833: they are listed here just for fun */
834: static short sigs_to_default [] = {
835: #ifdef SIGCHLD
836: SIGCHLD,
837: #endif
838: #ifdef SIGINFO
839: SIGINFO,
840: #endif
841: #ifdef SIGIO
842: SIGIO,
843: #endif
844: #ifdef SIGLOST
845: SIGLOST,
846: #endif
847: #ifdef SIGKILL
848: SIGKILL,
849: #endif
850: #ifdef SIGSTOP
851: SIGSTOP,
852: #endif
853: #ifdef SIGPWR
854: SIGPWR,
855: #endif
856: #ifdef SIGMSG
857: SIGMSG,
858: #endif
859: #ifdef SIGDANGER
860: SIGDANGER,
861: #endif
862: #ifdef SIGMIGRATE
863: SIGMIGRATE,
864: #endif
865: #ifdef SIGPRE
866: SIGPRE,
867: #endif
868: #ifdef SIGVIRT
869: SIGVIRT,
870: #endif
871: #ifdef SIGGRANT
872: SIGGRANT,
873: #endif
874: #ifdef SIGRETRACT
875: SIGRETRACT,
876: #endif
877: #ifdef SIGSOUND
878: SIGSOUND,
879: #endif
880: #ifdef SIGSAK
881: SIGSAK,
882: #endif
883: #ifdef SIGTSTP
884: SIGTSTP,
885: #endif
886: #ifdef SIGTTIN
887: SIGTTIN,
888: #endif
889: #ifdef SIGTTOU
890: SIGTTOU,
891: #endif
892: #ifdef SIGSTKFLT
893: SIGSTKFLT,
894: #endif
895: #ifdef SIGUNUSED
896: SIGUNUSED,
897: #endif
898: };
899: #endif
900:
901: static short sigs_to_throw [] = {
902: #ifdef SIGBREAK
903: SIGBREAK,
904: #endif
905: #ifdef SIGINT
906: SIGINT,
907: #endif
908: #ifdef SIGILL
909: SIGILL,
910: #endif
911: #ifdef SIGEMT
912: SIGEMT,
913: #endif
914: #ifdef SIGFPE
915: SIGFPE,
916: #endif
917: #ifdef SIGIOT
918: SIGIOT,
919: #endif
920: #ifdef SIGSEGV
921: SIGSEGV,
922: #endif
923: #ifdef SIGALRM
924: SIGALRM,
925: #endif
926: #ifdef SIGPIPE
927: SIGPIPE,
928: #endif
929: #ifdef SIGPOLL
930: SIGPOLL,
931: #endif
932: #ifdef SIGPROF
933: SIGPROF,
934: #endif
935: #ifdef SIGBUS
936: SIGBUS,
937: #endif
938: #ifdef SIGSYS
939: SIGSYS,
940: #endif
941: #ifdef SIGTRAP
942: SIGTRAP,
943: #endif
944: #ifdef SIGURG
945: SIGURG,
946: #endif
947: #ifdef SIGUSR1
948: SIGUSR1,
949: #endif
950: #ifdef SIGUSR2
951: SIGUSR2,
952: #endif
953: #ifdef SIGVTALRM
954: SIGVTALRM,
955: #endif
956: #ifdef SIGXFSZ
957: SIGXFSZ,
958: #endif
959: };
960: static short sigs_to_quit [] = {
961: #ifdef SIGHUP
962: SIGHUP,
963: #endif
964: #ifdef SIGQUIT
965: SIGQUIT,
966: #endif
967: #ifdef SIGABRT
968: SIGABRT,
969: #endif
970: #ifdef SIGTERM
971: SIGTERM,
972: #endif
973: #ifdef SIGXCPU
974: SIGXCPU,
975: #endif
976: };
977: int i;
978:
979: #define DIM(X) (sizeof (X) / sizeof *(X))
980: /*
981: for (i = 0; i < DIM (sigs_to_ignore); i++)
982: signal (sigs_to_ignore [i], SIG_IGN);
983: */
984: for (i = 0; i < DIM (sigs_to_throw); i++)
985: signal (sigs_to_throw [i], die_on_signal ? graceful_exit : signal_throw);
986: for (i = 0; i < DIM (sigs_to_quit); i++)
987: signal (sigs_to_quit [i], graceful_exit);
988: #ifdef SIGCONT
989: signal (SIGCONT, termprep);
990: #endif
991: #ifdef SIGWINCH
992: signal (SIGWINCH, change_winsize);
993: #endif
994: }
995: /* end signal handling */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>