bug-texinfo
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH].infokey feature and signal handling are broken


From: AIDA Shinra
Subject: [PATCH].infokey feature and signal handling are broken
Date: Mon, 02 Dec 2002 01:06:37 +0900
User-agent: Wanderlust/2.8.1 (Something) SEMI/1.14.3 (Ushinoya) FLIM/1.14.3 (Unebigoryƍmae) APEL/10.3 MULE XEmacs/21.4 (patch 6) (Common Lisp) (i386-unknown-freebsd4.6)

I found infokey feature is broken:

* "info infokey" says key bindings in .info take precedence over
the default mapping, but this is not true. Only bindings to
undefined keys take effects.

* Binding to "invalid" action results crash.

* No code to disable prefix keys. Some users might want to bind
escape or C-x to a non-prefix key, but this does not allowed.

In addition, when I 'C-z', 'fg' and then 'q' on my FreeBSD box,
some of my terminal settings break. I found SIGCONT handler was
invoked before SIGTSTP handler waked up. It seemd to be a reentrance
problem.

This patch fixes these problems. It always allows '^h' in incremental
search. Some terminals map 'backspace' to '^h' by default.

AIDA Shinra

Index: freebsd/src/contrib/texinfo/info/infomap.c
diff -u freebsd/src/contrib/texinfo/info/infomap.c:1.1.1.1 
freebsd/src/contrib/texinfo/info/infomap.c:1.6
--- freebsd/src/contrib/texinfo/info/infomap.c:1.1.1.1  Sun Jun  9 03:33:00 2002
+++ freebsd/src/contrib/texinfo/info/infomap.c  Sun Dec  1 23:12:41 2002
@@ -59,47 +59,154 @@
   return (keymap);
 }
 
+#if defined(INFOKEY)
+static FUNCTION_KEYSEQ *
+find_function_keyseq (map, c, rootmap)
+  Keymap map;
+  int c;
+  Keymap rootmap;
+{
+  FUNCTION_KEYSEQ *k;
+
+  if (map[c].type != ISFUNC)
+    abort();
+  if (map[c].function == NULL)
+    return NULL;
+  for (k = map[c].function->keys; k; k = k->next)
+    {
+      const unsigned char *p;
+      Keymap m = rootmap;
+      if (k->map != rootmap)
+       continue;
+      for (p = k->keyseq; *p && m[*p].type == ISKMAP; p++)
+       m = (Keymap)m[*p].function;
+      if (*p != c || p[1])
+       continue;
+      if (m[*p].type != ISFUNC)
+       abort ();
+      break;
+    }
+  return k;
+}
+
+static void
+add_function_keyseq (function, keyseq, rootmap)
+  InfoCommand *function;
+  const unsigned char *keyseq;
+  Keymap rootmap;
+{
+  FUNCTION_KEYSEQ *ks;
+
+  if (function == NULL ||
+      function == InfoCmd(info_do_lowercase_version) ||
+      function == InfoCmd(ea_insert))
+    return;
+  ks = (FUNCTION_KEYSEQ *)xmalloc (sizeof(FUNCTION_KEYSEQ));
+  ks->next = function->keys;
+  ks->map = rootmap;
+  ks->keyseq = xstrdup(keyseq);
+  function->keys = ks;
+}
+
+static void
+remove_function_keyseq (function, keyseq, rootmap)
+  InfoCommand *function;
+  const unsigned char *keyseq;
+  Keymap rootmap;
+{
+
+  FUNCTION_KEYSEQ *k, *kp;
+
+  if (function == NULL ||
+      function == InfoCmd(info_do_lowercase_version) ||
+      function == InfoCmd(ea_insert))
+    return;
+  for (kp = NULL, k = function->keys; k; kp = k, k = k->next)
+    if (k->map == rootmap && strcmp(k->keyseq, keyseq) == 0)
+      break;
+  if (!k)
+    abort ();
+  if (kp)
+    kp->next = k->next;
+  else
+    function->keys = k->next;
+}
+#endif /* INFOKEY */
+     
 /* Return a new keymap which is a copy of MAP. */
 Keymap
-keymap_copy_keymap (map)
-     Keymap map;
+keymap_copy_keymap (map, rootmap, newroot)
+  Keymap map;
+  Keymap rootmap;
+  Keymap newroot;
 {
   int i;
   Keymap keymap;
+#if defined(INFOKEY)
+  FUNCTION_KEYSEQ *ks;
+#endif /* INFOKEY */
 
   keymap = keymap_make_keymap ();
+  if (!newroot)
+    newroot = keymap;
 
   for (i = 0; i < 256; i++)
     {
       keymap[i].type = map[i].type;
-      keymap[i].function = map[i].function;
+      switch (map[i].type)
+       {
+       case ISFUNC:
+         keymap[i].function = map[i].function;
+#if defined(INFOKEY)
+         ks = find_function_keyseq (map, i, rootmap, NULL);
+         if (ks)
+           add_function_keyseq(map[i].function, ks->keyseq, newroot);
+#endif /* INFOKEY */
+         break;
+       case ISKMAP:
+         keymap[i].function = (InfoCommand *)keymap_copy_keymap (
+             (Keymap)map[i].function, rootmap);
+         break;
+       }
     }
   return (keymap);
 }
 
 /* Free the keymap and its descendants. */
 void
-keymap_discard_keymap (map)
-     Keymap (map);
+keymap_discard_keymap (map, rootmap)
+  Keymap map;
+  Keymap rootmap;
 {
   int i;
 
   if (!map)
     return;
+  if (!rootmap)
+    rootmap = map;
 
   for (i = 0; i < 256; i++)
     {
+#if defined(INFOKEY)
+      FUNCTION_KEYSEQ *ks;
+#endif /* INFOKEY */
       switch (map[i].type)
         {
         case ISFUNC:
+#if defined(INFOKEY)
+         ks = find_function_keyseq(map, i, rootmap);
+         if (ks)
+           remove_function_keyseq (map[i].function, ks->keyseq, rootmap);
+#endif /* INFOKEY */
           break;
 
         case ISKMAP:
-          keymap_discard_keymap ((Keymap)map[i].function);
+          keymap_discard_keymap ((Keymap)map[i].function, rootmap);
           break;
 
         }
     }
+  free(map);
 }
 
 /* Conditionally bind key sequence. */
@@ -117,16 +224,23 @@
 
   while ((c = *s++) != '\0')
     {
+#if defined(INFOKEY)
+      FUNCTION_KEYSEQ *ks;
+#endif /* INFOKEY */
       switch (m[c].type)
         {
         case ISFUNC:
+#if defined(INFOKEY)
+         ks = find_function_keyseq(m, c, map);
+         if (ks)
+           remove_function_keyseq (m[c].function, ks->keyseq, map);
+#else /* !INFOKEY */
           if (!(m[c].function == NULL || (
-#if !defined(INFOKEY)
                 m != map &&
-#endif /* !INFOKEY */
                 m[c].function == InfoCmd(info_do_lowercase_version))
              ))
             return 0;
+#endif /* !INFOKEY */
 
           if (*s != '\0')
             {
@@ -136,8 +250,13 @@
           break;
 
         case ISKMAP:
+#if defined(INFOKEY)
+         if (*s == '\0')
+           keymap_discard_keymap ((Keymap)m[c].function, map);
+#else /* !INFOKEY */
           if (*s == '\0')
             return 0;
+#endif
           break;
         }
       if (*s != '\0')
@@ -147,18 +266,7 @@
       else
         {
 #if defined(INFOKEY)
-         FUNCTION_KEYSEQ *k;
-
-         for (k = keyentry->function->keys; k && k->map != map; k = k->next)
-           ;
-         if (!k)
-           {
-             FUNCTION_KEYSEQ *ks = (FUNCTION_KEYSEQ *)xmalloc 
(sizeof(FUNCTION_KEYSEQ));
-             ks->next = keyentry->function->keys;
-             ks->map = map;
-             ks->keyseq = xstrdup (keyseq);
-             keyentry->function->keys = ks;
-           }
+         add_function_keyseq (keyentry->function, keyseq, map);
 #endif /* INFOKEY */
           m[c] = *keyentry;
         }
@@ -1722,3 +1830,4 @@
 }
 
 #endif /* defined(INFOKEY) */
+/* vim: set sw=2 cino={1s>2sn-s^-se-s: */
Index: freebsd/src/contrib/texinfo/info/session.c
diff -u freebsd/src/contrib/texinfo/info/session.c:1.1.1.1 
freebsd/src/contrib/texinfo/info/session.c:1.3
--- freebsd/src/contrib/texinfo/info/session.c:1.1.1.1  Sun Jun  9 03:33:00 2002
+++ freebsd/src/contrib/texinfo/info/session.c  Sun Dec  1 01:48:49 2002
@@ -3937,7 +3937,7 @@
       key = info_get_input_char ();
       window_get_state (window, &mystate);
 
-      if (key == DEL)
+      if (key == DEL || key == Control ('h'))
         {
           /* User wants to delete one level of search? */
           if (!isearch_states_index)
Index: freebsd/src/contrib/texinfo/info/signals.c
diff -u freebsd/src/contrib/texinfo/info/signals.c:1.1.1.1 
freebsd/src/contrib/texinfo/info/signals.c:1.5
--- freebsd/src/contrib/texinfo/info/signals.c:1.1.1.1  Mon Jan 17 19:46:55 2000
+++ freebsd/src/contrib/texinfo/info/signals.c  Mon Dec  2 00:45:43 2002
@@ -29,9 +29,6 @@
 /*                                                                  */
 /* **************************************************************** */
 
-/* Non-zero when our signal handler has been called to handle SIGWINCH. */
-static int in_sigwinch = 0;
-
 #if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK)
 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
 static void
@@ -64,35 +61,88 @@
 /*                                                                  */
 /* **************************************************************** */
 
-typedef RETSIGTYPE signal_handler ();
+#if defined (HAVE_SIGACTION) || defined (HAVE_SIGPROCMASK) ||\
+  defined (HAVE_SIGSETMASK)
+static void
+mask_termsig (set)
+  sigset_t *set;
+{
+# if defined (SIGTSTP)
+  sigaddset (set, SIGTSTP);
+  sigaddset (set, SIGTTOU);
+  sigaddset (set, SIGTTIN);
+# endif
+# if defined (SIGWINCH)
+  sigaddset (set, SIGWINCH);
+# endif
+#if defined (SIGINT)
+  sigaddset (set, SIGINT);
+#endif
+# if defined (SIGUSR1)
+  sigaddset (set, SIGUSR1);
+# endif
+}
+#endif /* HAVE_SIGACTION || HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
 
-static RETSIGTYPE info_signal_handler ();
-static signal_handler *old_TSTP, *old_TTOU, *old_TTIN;
-static signal_handler *old_WINCH, *old_INT, *old_USR1, *old_CONT;
+static RETSIGTYPE info_signal_proc ();
+#if defined (HAVE_SIGACTION)
+typedef struct sigaction signal_info;
+signal_info info_signal_handler = {
+  info_signal_proc,
+  0, /* set later */
+  0
+};
+
+static void
+set_termsig (sig, old)
+  int sig;
+  signal_info *old;
+{
+  sigaction (sig, info_signal_handler, old);
+}
+
+static void
+restore_termsig (sig, saved)
+  int sig;
+  const signal_info *saved;
+{
+  sigaction (sig, saved, NULL);
+}
+#else /* !HAVE_SIGACTION */
+typedef RETSIGTYPE (*signal_info) ();
+#define set_termsig(sig, old) (void)(*(old) = signal (sig, info_signal_proc))
+#define restore_termsig(sig, saved) (void)signal (sig, *(saved))
+#define info_signal_handler info_signal_proc
+static int term_conf_busy = 0;
+#endif /* !HAVE_SIGACTION */
+
+static signal_info old_TSTP, old_TTOU, old_TTIN;
+static signal_info old_WINCH, old_INT, old_USR1;
 
 void
 initialize_info_signal_handler ()
 {
+#if defined (HAVE_SIGACTION)
+  mask_termsig (&info_signal_handler.sa_mask);
+#endif /* HAVE_SIGACTION */
+
 #if defined (SIGTSTP)
-  old_TSTP = (signal_handler *) signal (SIGTSTP, info_signal_handler);
-  old_TTOU = (signal_handler *) signal (SIGTTOU, info_signal_handler);
-  old_TTIN = (signal_handler *) signal (SIGTTIN, info_signal_handler);
+  set_termsig (SIGTSTP, &old_TSTP);
+  set_termsig (SIGTTOU, &old_TTOU);
+  set_termsig (SIGTTIN, &old_TTIN);
 #endif /* SIGTSTP */
 
 #if defined (SIGWINCH)
-  old_WINCH = (signal_handler *) signal (SIGWINCH, info_signal_handler);
-#if defined (SIGCONT)
-  old_CONT = (signal_handler *) signal (SIGCONT, info_signal_handler);
-#endif
+  set_termsig (SIGWINCH, &old_WINCH);
 #endif
 
 #if defined (SIGINT)
-  old_INT = (signal_handler *) signal (SIGINT, info_signal_handler);
+  set_termsig (SIGINT, &old_INT);
 #endif
 
 #if defined (SIGUSR1)
   /* Used by DJGPP to simulate SIGTSTP on Ctrl-Z.  */
-  old_USR1 = (signal_handler *) signal (SIGUSR1, info_signal_handler);
+  set_termsig (SIGUSR1, &old_USR1);
 #endif
 }
 
@@ -121,11 +171,25 @@
 }
 
 static RETSIGTYPE
-info_signal_handler (sig)
+info_signal_proc (sig)
      int sig;
 {
-  signal_handler **old_signal_handler;
+  signal_info *old_signal_handler;
 
+#if !defined (HAVE_SIGACTION)
+  /* best effort: first increment this counter and later block signals */
+  if (term_conf_busy)
+    return;
+  term_conf_busy++;
+#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK)
+    {
+      sigset_t nvar, ovar;
+      sigemptyset (&nvar);
+      mask_termsig (&nvar);
+      sigprocmask (SIG_BLOCK, &nvar, &ovar);
+    }
+#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
+#endif /* !HAVE_SIGACTION */
   switch (sig)
     {
 #if defined (SIGTSTP)
@@ -145,8 +209,10 @@
         if (sig == SIGTTIN)
           old_signal_handler = &old_TTIN;
 #endif /* SIGTSTP */
+#if defined (SIGINT)
         if (sig == SIGINT)
           old_signal_handler = &old_INT;
+#endif /* SIGINT */
 
         /* For stop signals, restore the terminal IO, leave the cursor
            at the bottom of the window, and stop us. */
@@ -154,67 +220,64 @@
         terminal_clear_to_eol ();
         fflush (stdout);
         terminal_unprep_terminal ();
-        signal (sig, *old_signal_handler);
-        UNBLOCK_SIGNAL (sig);
-        kill (getpid (), sig);
+       restore_termsig (sig, old_signal_handler);
+       UNBLOCK_SIGNAL (sig);
+       kill (getpid (), sig);
 
         /* The program is returning now.  Restore our signal handler,
            turn on terminal handling, redraw the screen, and place the
            cursor where it belongs. */
         terminal_prep_terminal ();
-        *old_signal_handler = (signal_handler *) signal (sig, 
info_signal_handler);
-        redisplay_after_signal ();
-        fflush (stdout);
+       set_termsig (sig, old_signal_handler);
+       /* window size might be changed while sleeping */
+       reset_info_window_sizes ();
       }
       break;
 
 #if defined (SIGWINCH) || defined (SIGUSR1)
 #ifdef SIGWINCH
-#ifdef SIGCONT
-    case SIGCONT:
-      /* pretend a SIGWINCH in case the terminal window size has changed
-        while we've been asleep */
-      /* FALLTHROUGH */
-#endif
     case SIGWINCH:
 #endif
 #ifdef SIGUSR1
     case SIGUSR1:
 #endif
       {
-        if (!in_sigwinch) {
-          in_sigwinch++;
-          
-          /* Turn off terminal IO, tell our parent that the window has changed,
-             then reinitialize the terminal and rebuild our windows. */
+       /* Turn off terminal IO, tell our parent that the window has changed,
+          then reinitialize the terminal and rebuild our windows. */
 #ifdef SIGWINCH
-          if (sig == SIGWINCH)
-            old_signal_handler = &old_WINCH;
-#ifdef SIGCONT
-         else if (sig == SIGCONT)
-           old_signal_handler = &old_CONT;
-#endif
+       if (sig == SIGWINCH)
+         old_signal_handler = &old_WINCH;
 #endif
 #ifdef SIGUSR1
-          if (sig == SIGUSR1)
-            old_signal_handler = &old_USR1;
+       if (sig == SIGUSR1)
+         old_signal_handler = &old_USR1;
 #endif
-          terminal_goto_xy (0, 0);
-          fflush (stdout);
-          terminal_unprep_terminal ();
-          signal (sig, *old_signal_handler);
-          UNBLOCK_SIGNAL (sig);
-          kill (getpid (), sig);
-
-          /* After our old signal handler returns... */
-          *old_signal_handler
-            = (signal_handler *) signal (sig, info_signal_handler);
-          terminal_prep_terminal ();
-          reset_info_window_sizes ();
-          in_sigwinch--;
-        }
+       terminal_goto_xy (0, 0);
+       fflush (stdout);
+       terminal_unprep_terminal (); /* needless? */
+       restore_termsig (sig, old_signal_handler);
+       UNBLOCK_SIGNAL (sig);
+       kill (getpid (), sig);
+
+       /* After our old signal handler returns... */
+       set_termsig (sig, old_signal_handler); /* needless? */
+       terminal_prep_terminal ();
+       reset_info_window_sizes ();
       }
       break;
 #endif /* SIGWINCH || SIGUSR1 */
     }
+#if !defined (HAVE_SIGACTION)
+  /* at this time it is safer to perform unblock after decrement */
+  term_conf_busy--;
+#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK)
+    {
+      sigset_t nvar, ovar;
+      sigemptyset (&nvar);
+      mask_termsig (&nvar);
+      sigprocmask (SIG_UNBLOCK, &nvar, &ovar);
+    }
+#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */
+#endif /* !HAVE_SIGACTION */
 }
+/* vim: set sw=2 cino={1s>2sn-s^-se-s: */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]