From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.clark.net ([168.143.0.10]) by hawkwind.utcs.utoronto.ca with SMTP id <24628>; Wed, 5 Mar 1997 22:09:30 -0500 Received: from clark.net (culliton@explorer.clark.net [168.143.0.7]) by mail.clark.net (8.8.5/8.6.5) with ESMTP id WAA10865; Wed, 5 Mar 1997 22:08:30 -0500 (EST) From: Tom Culliton Received: (from culliton@localhost) by clark.net (8.8.5/8.7.1) id WAA06759; Wed, 5 Mar 1997 22:08:49 -0500 (EST) Date: Wed, 5 Mar 1997 22:08:49 -0500 Message-Id: <199703060308.WAA06759@clark.net> To: byron@netapp.com, rc@hawkwind.utcs.toronto.edu Subject: My patches for Linux, readline and signals (1 of 2) (This is the first of two parts. The first are my patches against rc-1.5betadev-1, which are a collection of "fix only" patches from the mailing list and my own work. The second is my Linux configuration, which should also be generally useful for using readline and building on Posix systems. So without further ado...) diff -rc rc-1.5betadev-1/builtins.c rc-1.5tjc/builtins.c *** rc-1.5betadev-1/builtins.c Sun Mar 6 22:32:49 1994 --- rc-1.5tjc/builtins.c Wed Mar 5 21:02:10 1997 *************** *** 8,14 **** */ #include - #include #include #include "rc.h" #include "jbwrap.h" --- 8,13 ---- *************** *** 72,78 **** Jbwrap j; Estack e1, e2; Edata jreturn, star; ! if (setjmp(j.j)) return; starassign(*av, av+1, TRUE); jreturn.jb = &j; --- 71,77 ---- Jbwrap j; Estack e1, e2; Edata jreturn, star; ! if (rc_setjmp(j.j)) return; starassign(*av, av+1, TRUE); jreturn.jb = &j; diff -rc rc-1.5betadev-1/except.c rc-1.5tjc/except.c *** rc-1.5betadev-1/except.c Sun Mar 6 22:32:50 1994 --- rc-1.5tjc/except.c Wed Mar 5 20:38:33 1997 *************** *** 1,4 **** - #include #include #include "rc.h" #include "jbwrap.h" --- 1,3 ---- *************** *** 91,97 **** interactive = estack->interactive; estack = estack->prev; ! longjmp(j->j, 1); } } rc_exit(1); /* top of exception stack */ --- 90,96 ---- interactive = estack->interactive; estack = estack->prev; ! rc_longjmp(j->j, 1); } } rc_exit(1); /* top of exception stack */ diff -rc rc-1.5betadev-1/exec.c rc-1.5tjc/exec.c *** rc-1.5betadev-1/exec.c Sun Mar 6 22:32:52 1994 --- rc-1.5tjc/exec.c Wed Mar 5 20:39:26 1997 *************** *** 1,9 **** /* exec.c */ #include #include - #include #include "rc.h" - #include "jbwrap.h" /* Takes an argument list and does the appropriate thing (calls a --- 1,7 ---- diff -rc rc-1.5betadev-1/input.c rc-1.5tjc/input.c *** rc-1.5betadev-1/input.c Sun Mar 6 22:33:03 1994 --- rc-1.5tjc/input.c Wed Mar 5 21:02:23 1997 *************** *** 1,7 **** /* input.c: i/o routines for files and pseudo-files (strings) */ #include - #include #include "rc.h" #include "jbwrap.h" --- 1,6 ---- *************** *** 88,114 **** /* signal-safe readline wrapper */ #ifdef READLINE ! #ifndef SVSIGS static char *rc_readline(char *prompt) { char *r; interrupt_happened = FALSE; ! if (!setjmp(slowbuf.j)) { slow = TRUE; if (!interrupt_happened) r = readline(prompt); ! else r = NULL; ! } else r = NULL; - slow = FALSE; - if (r == NULL) errno = EINTR; sigchk(); return r; } #else #define rc_readline readline - #endif /* SVSIGS */ #endif /* READLINE */ /* --- 87,119 ---- /* signal-safe readline wrapper */ #ifdef READLINE ! int in_readline = 0; /* a flag for readline clean up */ ! static char *rc_readline(char *prompt) { char *r; interrupt_happened = FALSE; ! if (!rc_setjmp(slowbuf.j)) { slow = TRUE; if (!interrupt_happened) + { + errno = 0; /* this is relatively evil */ + in_readline = TRUE; r = readline(prompt); ! in_readline = FALSE; ! } else { r = NULL; ! errno = EINTR; ! } ! } else { r = NULL; errno = EINTR; + } + slow = FALSE; sigchk(); return r; } #else #define rc_readline readline #endif /* READLINE */ /* *************** *** 121,128 **** while (1) { #ifdef READLINE if (interactive && istack->fd == 0) { ! rlinebuf = readline(prompt); if (rlinebuf == NULL) { chars_in = 0; } else { if (*rlinebuf != '\0') --- 126,135 ---- while (1) { #ifdef READLINE if (interactive && istack->fd == 0) { ! rlinebuf = rc_readline(prompt); if (rlinebuf == NULL) { + if (errno == EINTR) + continue; chars_in = 0; } else { if (*rlinebuf != '\0') *************** *** 140,145 **** --- 147,154 ---- long /*ssize_t*/ r = rc_read(istack->fd, inbuf + 2, BUFSIZE); sigchk(); if (r < 0) { + if (errno == EINTR) + continue; uerror("read"); rc_exit(1); } *************** *** 255,261 **** Edata jerror; if (dashen) execit = FALSE; ! setjmp(j.j); jerror.jb = &j; except(eError, jerror, &e1); for (eof = FALSE; !eof;) { --- 264,270 ---- Edata jerror; if (dashen) execit = FALSE; ! rc_setjmp(j.j); jerror.jb = &j; except(eError, jerror, &e1); for (eof = FALSE; !eof;) { *************** *** 279,288 **** } if ((s = varlookup("prompt")) != NULL) { #ifdef READLINE ! prompt = s->w; ! #else ! fprint(2, "%s", s->w); #endif prompt2 = (s->n == NULL ? "" : s->n->w); } } --- 288,298 ---- } if ((s = varlookup("prompt")) != NULL) { #ifdef READLINE ! if (istack->fd == 0) ! prompt = s->w; ! else #endif + fprint(2, "%s", s->w); prompt2 = (s->n == NULL ? "" : s->n->w); } } *************** *** 301,306 **** --- 311,329 ---- popinput(); unexcept(); /* eError */ return parsetree; + } + + extern void print_prompt2() { + lineno++; + if (interactive) + { + #ifdef READLINE + if (istack->fd == 0) + prompt = prompt2; + else + #endif + fprint(2, "%s", prompt2); + } } /* parse a function imported from the environment */ diff -rc rc-1.5betadev-1/jbwrap.h rc-1.5tjc/jbwrap.h *** rc-1.5betadev-1/jbwrap.h Thu Dec 19 15:10:03 1991 --- rc-1.5tjc/jbwrap.h Wed Mar 5 21:04:42 1997 *************** *** 1,10 **** /* certain braindamaged environments don't define jmp_buf as an array, so... */ struct Jbwrap { jmp_buf j; }; - extern Jbwrap slowbuf; /* for getting out of interrupts while performing slow i/o on BSD */ - extern int setjmp(jmp_buf); extern void longjmp(jmp_buf, int); --- 1,33 ---- /* certain braindamaged environments don't define jmp_buf as an array, so... */ + #include + #include "config.h" + + #ifndef USESIGSETJMP + struct Jbwrap { jmp_buf j; }; extern int setjmp(jmp_buf); extern void longjmp(jmp_buf, int); + + #define rc_setjmp(a) setjmp(a) + #define rc_longjmp(a, b) longjmp(a, b) + + #else + + struct Jbwrap { + sigjmp_buf j; + }; + + /* extern int sigsetjmp(sigjmp_buf, int); */ + /* extern void siglongjmp(sigjmp_buf, int); */ + + #define rc_setjmp(a) sigsetjmp(a, 1) + #define rc_longjmp(a, b) siglongjmp(a, b) + + #endif + + extern Jbwrap slowbuf; /* for getting out of interrupts while performing slow i/o on BSD */ + diff -rc rc-1.5betadev-1/lex.c rc-1.5tjc/lex.c *** rc-1.5betadev-1/lex.c Sun Mar 6 22:33:05 1994 --- rc-1.5tjc/lex.c Sat Feb 22 21:58:54 1997 *************** *** 336,351 **** realbuf = ealloc(bufsize); } - extern void print_prompt2() { - lineno++; - #ifdef READLINE - prompt = prompt2; - #else - if (interactive) - fprint(2, "%s", prompt2); - #endif - } - /* Scan in a pair of integers for redirections like >[2=1]. CLOSED represents a closed file descriptor (i.e., >[2=]) and UNSET represents an undesignated file descriptor (e.g., --- 336,341 ---- diff -rc rc-1.5betadev-1/print.c rc-1.5tjc/print.c *** rc-1.5betadev-1/print.c Sun Mar 6 22:33:10 1994 --- rc-1.5tjc/print.c Wed Mar 5 21:11:13 1997 *************** *** 1,7 **** /* print.c -- formatted printing routines (Paul Haahr, 12/91) */ #include "rc.h" ! #include #define PRINT_ALLOCSIZE ((SIZE_T)64) #define SPRINT_BUFSIZ ((SIZE_T)1024) --- 1,7 ---- /* print.c -- formatted printing routines (Paul Haahr, 12/91) */ #include "rc.h" ! #include "jbwrap.h" #define PRINT_ALLOCSIZE ((SIZE_T)64) #define SPRINT_BUFSIZ ((SIZE_T)1024) *************** *** 411,425 **** } static void snprint_grow(Format *format, SIZE_T more) { ! longjmp(format->u.p, 1); } extern int snprint(char *buf, int buflen, const char *fmt,...) { int n; ! jmp_buf jbuf; Format format; ! if (setjmp(jbuf)) { *format.buf = '\0'; return format.buf - format.bufbegin; } --- 411,425 ---- } static void snprint_grow(Format *format, SIZE_T more) { ! rc_longjmp(format->u.p, 1); } extern int snprint(char *buf, int buflen, const char *fmt,...) { int n; ! Jbwrap jbuf; Format format; ! if (rc_setjmp(jbuf.j)) { *format.buf = '\0'; return format.buf - format.bufbegin; } *************** *** 429,435 **** format.bufend = buf + buflen - 1; format.grow = snprint_grow; format.flushed = 0; ! format.u.p = jbuf; va_start(format.args, fmt); n = printfmt(&format, fmt); --- 429,435 ---- format.bufend = buf + buflen - 1; format.grow = snprint_grow; format.flushed = 0; ! format.u.p = jbuf.j; va_start(format.args, fmt); n = printfmt(&format, fmt); *************** *** 441,450 **** extern int sprint(char *buf, const char *fmt,...) { int n; ! jmp_buf jbuf; Format format; ! if (setjmp(jbuf)) { *format.buf = '\0'; return format.buf - format.bufbegin; } --- 441,450 ---- extern int sprint(char *buf, const char *fmt,...) { int n; ! Jbwrap jbuf; Format format; ! if (rc_setjmp(jbuf.j)) { *format.buf = '\0'; return format.buf - format.bufbegin; } *************** *** 454,460 **** format.bufend = buf + SPRINT_BUFSIZ - 1; format.grow = snprint_grow; format.flushed = 0; ! format.u.p = jbuf; va_start(format.args, fmt); n = printfmt(&format, fmt); --- 454,460 ---- format.bufend = buf + SPRINT_BUFSIZ - 1; format.grow = snprint_grow; format.flushed = 0; ! format.u.p = jbuf.j; va_start(format.args, fmt); n = printfmt(&format, fmt); diff -rc rc-1.5betadev-1/signal.c rc-1.5tjc/signal.c *** rc-1.5betadev-1/signal.c Sun Mar 6 22:33:16 1994 --- rc-1.5tjc/signal.c Wed Mar 5 21:45:51 1997 *************** *** 1,7 **** /* signal.c: a Hugh-approved signal handler. */ #include - #include #include "rc.h" #include "sigmsgs.h" #include "jbwrap.h" --- 1,6 ---- *************** *** 12,17 **** --- 11,34 ---- static volatile SIG_ATOMIC_T sigcount, caught[NUMOFSIGNALS]; + /* + The situation with readline is fairly hairy... It tries to catch SIGINT, + SIGALRM SIGTSTP, SIGTTOU SIGTTIN, SIGCONT and SIGWINCH. The SIGWINCH + handler in readline assumes Berkley semantics and doesn't reset itself, + it also tries to daisy chain to the "old" signal handler (in this case + rc's catcher()), which will do lord only knows what, without cleaning up + the terminal settings. The rest of the signals readline catches seem to + be well behaved. However for any signal that readline doesn't catch, + the terminal is never reset! + + Also for any caught signal, unless you treat it as a slow "system call" + and longjmp out of the signal handler, rc ignores it and resumes the + read. This means that SIGINT does not abort input like it's supposed + to. The way I've got it set up, all signals abort readline input and + clean up after themselves. I'm willing to entertain discussions on more + "proper" behaviour, but for now this is simple and predictable. ;-) + */ + extern void catcher(int s) { if (caught[s] == 0) { sigcount++; *************** *** 19,27 **** } signal(s, catcher); interrupt_happened = TRUE; ! #ifndef SVSIGS ! if (slow) ! longjmp(slowbuf.j, 1); #endif } --- 36,70 ---- } signal(s, catcher); interrupt_happened = TRUE; ! #if defined(SVSIGS) || defined(READLINE) ! if (slow) { ! #if defined(READLINE) ! /* It's very important that readline is always */ ! /* treated as a slow system call! */ ! extern int rl_pending_input; ! extern int in_readline; ! if (in_readline) { ! in_readline = FALSE; /* Not any more!!! */ ! switch (s) { ! default: ! rl_clean_up_for_exit(); ! rl_deprep_terminal(); ! rl_clear_signals(); /* this should be OK */ ! rl_pending_input = 0; ! /* readline already cleans up for these */ ! case SIGINT: ! case SIGALRM: ! #if defined(SIGTSTP) ! case SIGTSTP: ! case SIGTTOU: ! case SIGTTIN: ! break; ! #endif ! } ! } ! #endif ! rc_longjmp(slowbuf.j, 1); ! } #endif } *************** *** 66,72 **** void (*h)(int); int i; for (i = 1; i < NUMOFSIGNALS; i++) { ! if ((h = signal(i, SIG_DFL)) != SIG_DFL) signal(i, h); sighandlers[i] = h; } --- 109,115 ---- void (*h)(int); int i; for (i = 1; i < NUMOFSIGNALS; i++) { ! if ((h = signal(i, SIG_DFL)) != SIG_DFL && h != SIG_ERR) signal(i, h); sighandlers[i] = h; } diff -rc rc-1.5betadev-1/utils.c rc-1.5tjc/utils.c *** rc-1.5betadev-1/utils.c Sun Mar 6 22:33:19 1994 --- rc-1.5tjc/utils.c Wed Mar 5 21:00:21 1997 *************** *** 1,7 **** /* utils.c: functions of general utility */ #include - #include #include "rc.h" #include "jbwrap.h" --- 1,6 ---- *************** *** 71,77 **** int i; for (i = 0; remain > 0; buf += i, remain -= i) { interrupt_happened = FALSE; ! if (!setjmp(slowbuf.j)) { slow = TRUE; if (interrupt_happened) break; --- 70,76 ---- int i; for (i = 0; remain > 0; buf += i, remain -= i) { interrupt_happened = FALSE; ! if (!rc_setjmp(slowbuf.j)) { slow = TRUE; if (interrupt_happened) break; *************** *** 88,94 **** extern int rc_read(int fd, char *buf, SIZE_T n) { long /*ssize_t*/ r; interrupt_happened = FALSE; ! if (!setjmp(slowbuf.j)) { slow = TRUE; if (!interrupt_happened) r = read(fd, buf, n); --- 87,93 ---- extern int rc_read(int fd, char *buf, SIZE_T n) { long /*ssize_t*/ r; interrupt_happened = FALSE; ! if (!rc_setjmp(slowbuf.j)) { slow = TRUE; if (!interrupt_happened) r = read(fd, buf, n); diff -rc rc-1.5betadev-1/wait.c rc-1.5tjc/wait.c *** rc-1.5betadev-1/wait.c Sun Mar 6 22:33:23 1994 --- rc-1.5tjc/wait.c Wed Mar 5 21:00:29 1997 *************** *** 1,5 **** #include - #include #include "rc.h" #include "jbwrap.h" --- 1,4 ---- *************** *** 112,118 **** static int rc_wait(int *stat) { int r; interrupt_happened = FALSE; ! if (!setjmp(slowbuf.j)) { slow = TRUE; if (!interrupt_happened) r = wait(stat); --- 111,117 ---- static int rc_wait(int *stat) { int r; interrupt_happened = FALSE; ! if (!rc_setjmp(slowbuf.j)) { slow = TRUE; if (!interrupt_happened) r = wait(stat); diff -rc rc-1.5betadev-1/walk.c rc-1.5tjc/walk.c *** rc-1.5betadev-1/walk.c Sun Mar 6 22:33:26 1994 --- rc-1.5tjc/walk.c Wed Mar 5 21:00:40 1997 *************** *** 1,7 **** /* walk.c: walks the parse tree. */ #include - #include #include "rc.h" #include "jbwrap.h" --- 1,6 ---- *************** *** 108,114 **** cond = oldcond; break; } ! if (setjmp(j.j)) break; jbreak.jb = &j; except(eBreak, jbreak, &e1); --- 107,113 ---- cond = oldcond; break; } ! if (rc_setjmp(j.j)) break; jbreak.jb = &j; except(eBreak, jbreak, &e1); *************** *** 131,137 **** Jbwrap j; Estack e1, e2; Edata jbreak; ! if (setjmp(j.j)) break; jbreak.jb = &j; except(eBreak, jbreak, &e1); --- 130,136 ---- Jbwrap j; Estack e1, e2; Edata jbreak; ! if (rc_setjmp(j.j)) break; jbreak.jb = &j; except(eBreak, jbreak, &e1);