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