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