use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / keyboard.c
index cc578c5..20498d0 100644 (file)
@@ -417,8 +417,8 @@ static Lisp_Object make_lispy_focus_in (Lisp_Object);
 static Lisp_Object make_lispy_focus_out (Lisp_Object);
 #endif /* HAVE_WINDOW_SYSTEM */
 static bool help_char_p (Lisp_Object);
-static void save_getcjmp (sys_jmp_buf);
-static void restore_getcjmp (sys_jmp_buf);
+static void save_getcjmp (sys_jmp_buf *);
+static void restore_getcjmp (sys_jmp_buf *);
 static Lisp_Object apply_modifiers (int, Lisp_Object);
 static void clear_event (struct input_event *);
 static void restore_kboard_configuration (int);
@@ -740,7 +740,7 @@ add_command_key (Lisp_Object key)
 Lisp_Object
 recursive_edit_1 (void)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object val;
 
   if (command_loop_level > 0)
@@ -777,7 +777,8 @@ recursive_edit_1 (void)
   if (STRINGP (val))
     xsignal1 (Qerror, val);
 
-  return unbind_to (count, Qnil);
+  dynwind_end ();
+  return Qnil;
 }
 
 /* When an auto-save happens, record the "time", and don't do again soon.  */
@@ -812,13 +813,15 @@ one level up.
 This function is called by the editor initialization to begin editing.  */)
   (void)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object buffer;
 
   /* If we enter while input is blocked, don't lock up here.
      This may happen through the debugger during redisplay.  */
-  if (input_blocked_p ())
+  if (input_blocked_p ()) {
+    dynwind_end ();
     return Qnil;
+  }
 
   if (command_loop_level >= 0
       && current_buffer != XBUFFER (XWINDOW (selected_window)->contents))
@@ -841,7 +844,8 @@ This function is called by the editor initialization to begin editing.  */)
     temporarily_switch_to_single_kboard (SELECTED_FRAME ());
 
   recursive_edit_1 ();
-  return unbind_to (count, Qnil);
+  dynwind_end ();
+  return Qnil;
 }
 
 void
@@ -1269,7 +1273,7 @@ Normally, mouse motion is ignored.
 usage: (track-mouse BODY...)  */)
   (Lisp_Object args)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object val;
 
   record_unwind_protect (tracking_off, do_mouse_tracking);
@@ -1277,7 +1281,8 @@ usage: (track-mouse BODY...)  */)
   do_mouse_tracking = Qt;
 
   val = Fprogn (args);
-  return unbind_to (count, val);
+  dynwind_end ();
+  return val;
 }
 
 /* If mouse has moved on some frame, return one of those frames.
@@ -1404,7 +1409,7 @@ command_loop_1 (void)
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
-         ptrdiff_t count = SPECPDL_INDEX ();
+          dynwind_begin ();
          specbind (Qinhibit_quit, Qt);
 
          sit_for (Vminibuffer_message_timeout, 0, 2);
@@ -1413,7 +1418,7 @@ command_loop_1 (void)
          message1 (0);
          safe_run_hooks (Qecho_area_clear_hook);
 
-         unbind_to (count, Qnil);
+         dynwind_end ();
 
          /* If a C-g came in before, treat it as input now.  */
          if (!NILP (Vquit_flag))
@@ -1527,7 +1532,7 @@ command_loop_1 (void)
          /* Here for a command that isn't executed directly.  */
 
 #ifdef HAVE_WINDOW_SYSTEM
-            ptrdiff_t scount = SPECPDL_INDEX ();
+            dynwind_begin ();
 
             if (display_hourglass_p
                 && NILP (Vexecuting_kbd_macro))
@@ -1553,8 +1558,7 @@ command_loop_1 (void)
             hourglass cursor anyway.
             But don't cancel the hourglass within a macro
             just because a command in the macro finishes.  */
-         if (NILP (Vexecuting_kbd_macro))
-            unbind_to (scount, Qnil);
+            dynwind_end ();
 #endif
           }
       kset_last_prefix_arg (current_kboard, Vcurrent_prefix_arg);
@@ -1930,12 +1934,12 @@ safe_run_hooks (Lisp_Object hook)
   /* FIXME: our `internal_condition_case' does not provide any way to pass data
      to its body or to its handlers other than via globals such as
      dynamically-bound variables ;-)  */
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   specbind (Qinhibit_quit, hook);
 
   run_hook_with_args (1, &hook, safe_run_hook_funcall);
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 }
 
 \f
@@ -2209,11 +2213,11 @@ do { if (polling_stopped_here) start_polling ();        \
 
 static Lisp_Object
 read_event_from_main_queue (struct timespec *end_time,
-                            sys_jmp_buf local_getcjmp,
+                            sys_jmp_buf *local_getcjmp,
                             bool *used_mouse_menu)
 {
   Lisp_Object c = Qnil;
-  sys_jmp_buf save_jump;
+  sys_jmp_buf *save_jump = xmalloc (sizeof *save_jump);
   KBOARD *kb IF_LINT (= NULL);
 
  start:
@@ -2283,7 +2287,7 @@ read_event_from_main_queue (struct timespec *end_time,
    to tty input.  */
 static Lisp_Object
 read_decoded_event_from_main_queue (struct timespec *end_time,
-                                    sys_jmp_buf local_getcjmp,
+                                    sys_jmp_buf *local_getcjmp,
                                     Lisp_Object prev_event,
                                     bool *used_mouse_menu)
 {
@@ -2396,33 +2400,125 @@ echo_keystrokes_p (void)
 
    Value is t if we showed a menu and the user rejected it.  */
 
+struct read_char_state
+{
+  int commandflag;
+  Lisp_Object map;
+  Lisp_Object prev_event;
+  bool *used_mouse_menu;
+  struct timespec *end_time;
+  Lisp_Object c;
+  ptrdiff_t jmpcount;
+  sys_jmp_buf *local_getcjmp;
+  sys_jmp_buf *save_jump;
+  Lisp_Object previous_echo_area_message;
+  Lisp_Object also_record;
+  bool reread;
+  bool polling_stopped_here;
+  struct kboard *orig_kboard;
+};
+
+static Lisp_Object read_char_1 (bool, volatile struct read_char_state *);
+
+/* {{coccinelle:skip_start}} */
 Lisp_Object
 read_char (int commandflag, Lisp_Object map,
           Lisp_Object prev_event,
           bool *used_mouse_menu, struct timespec *end_time)
 {
-  Lisp_Object c;
-  ptrdiff_t jmpcount;
-  sys_jmp_buf local_getcjmp;
-  sys_jmp_buf save_jump;
-  Lisp_Object tem, save;
-  volatile Lisp_Object previous_echo_area_message;
-  volatile Lisp_Object also_record;
-  volatile bool reread;
-  struct gcpro gcpro1, gcpro2;
-  bool volatile polling_stopped_here = 0;
-  struct kboard *orig_kboard = current_kboard;
+  volatile struct read_char_state *state = xmalloc (sizeof *state);
+
+  state->commandflag = commandflag;
+  state->map = map;
+  state->prev_event = prev_event;
+  state->used_mouse_menu = used_mouse_menu;
+  state->end_time = end_time;
+  state->c = Qnil;
+  state->local_getcjmp = xmalloc (sizeof (*state->local_getcjmp));
+  state->save_jump = xmalloc (sizeof (*state->save_jump));
+  state->previous_echo_area_message = Qnil;
+  state->also_record = Qnil;
+  state->reread = false;
+  state->polling_stopped_here = false;
+  state->orig_kboard = current_kboard;
 
-  also_record = Qnil;
+  /* Make a longjmp point for quits to use, but don't alter getcjmp just yet.
+     We will do that below, temporarily for short sections of code,
+     when appropriate.  local_getcjmp must be in effect
+     around any call to sit_for or kbd_buffer_get_event;
+     it *must not* be in effect when we call redisplay.  */
 
-#if 0  /* This was commented out as part of fixing echo for C-u left.  */
-  before_command_key_count = this_command_key_count;
-  before_command_echo_length = echo_length ();
-#endif
-  c = Qnil;
-  previous_echo_area_message = Qnil;
+  state->jmpcount = SPECPDL_INDEX ();
+  if (sys_setjmp (*state->local_getcjmp))
+    {
+      /* Handle quits while reading the keyboard.  */
+      /* We must have saved the outer value of getcjmp here,
+        so restore it now.  */
+      restore_getcjmp (state->save_jump);
+      pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
+      unbind_to (state->jmpcount, Qnil);
+      XSETINT (state->c, quit_char);
+      internal_last_event_frame = selected_frame;
+      Vlast_event_frame = internal_last_event_frame;
+      /* If we report the quit char as an event,
+        don't do so more than once.  */
+      if (!NILP (Vinhibit_quit))
+       Vquit_flag = Qnil;
+
+      {
+       KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
+       if (kb != current_kboard)
+         {
+           Lisp_Object last = KVAR (kb, kbd_queue);
+           /* We shouldn't get here if we were in single-kboard mode!  */
+           if (single_kboard)
+             emacs_abort ();
+           if (CONSP (last))
+             {
+               while (CONSP (XCDR (last)))
+                 last = XCDR (last);
+               if (!NILP (XCDR (last)))
+                 emacs_abort ();
+             }
+           if (!CONSP (last))
+             kset_kbd_queue (kb, list1 (state->c));
+           else
+             XSETCDR (last, list1 (state->c));
+           kb->kbd_queue_has_data = 1;
+           current_kboard = kb;
+           /* This is going to exit from read_char
+              so we had better get rid of this frame's stuff.  */
+           UNGCPRO;
+            return make_number (-2); /* wrong_kboard_jmpbuf */
+         }
+      }
+      return read_char_1 (true, state);
+    }
+
+  return read_char_1 (false, state);
+}
 
-  GCPRO2 (c, previous_echo_area_message);
+static Lisp_Object
+read_char_1 (bool jump, volatile struct read_char_state *state)
+{
+#define commandflag state->commandflag
+#define map state->map
+#define prev_event state->prev_event
+#define used_mouse_menu state->used_mouse_menu
+#define end_time state->end_time
+#define c state->c
+#define jmpcount state->jmpcount
+#define local_getcjmp state->local_getcjmp
+#define save_jump state->save_jump
+#define previous_echo_area_message state->previous_echo_area_message
+#define also_record state->also_record
+#define reread state->reread
+#define polling_stopped_here state->polling_stopped_here
+#define orig_kboard state->orig_kboard
+  Lisp_Object tem, save;
+
+  if (jump)
+    goto non_reread;
 
  retry:
 
@@ -2635,59 +2731,6 @@ read_char (int commandflag, Lisp_Object map,
        goto exit;
     }
 
-  /* Make a longjmp point for quits to use, but don't alter getcjmp just yet.
-     We will do that below, temporarily for short sections of code,
-     when appropriate.  local_getcjmp must be in effect
-     around any call to sit_for or kbd_buffer_get_event;
-     it *must not* be in effect when we call redisplay.  */
-
-  jmpcount = SPECPDL_INDEX ();
-  if (sys_setjmp (local_getcjmp))
-    {
-      /* Handle quits while reading the keyboard.  */
-      /* We must have saved the outer value of getcjmp here,
-        so restore it now.  */
-      restore_getcjmp (save_jump);
-      pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
-      unbind_to (jmpcount, Qnil);
-      XSETINT (c, quit_char);
-      internal_last_event_frame = selected_frame;
-      Vlast_event_frame = internal_last_event_frame;
-      /* If we report the quit char as an event,
-        don't do so more than once.  */
-      if (!NILP (Vinhibit_quit))
-       Vquit_flag = Qnil;
-
-      {
-       KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
-       if (kb != current_kboard)
-         {
-           Lisp_Object last = KVAR (kb, kbd_queue);
-           /* We shouldn't get here if we were in single-kboard mode!  */
-           if (single_kboard)
-             emacs_abort ();
-           if (CONSP (last))
-             {
-               while (CONSP (XCDR (last)))
-                 last = XCDR (last);
-               if (!NILP (XCDR (last)))
-                 emacs_abort ();
-             }
-           if (!CONSP (last))
-             kset_kbd_queue (kb, list1 (c));
-           else
-             XSETCDR (last, list1 (c));
-           kb->kbd_queue_has_data = 1;
-           current_kboard = kb;
-           /* This is going to exit from read_char
-              so we had better get rid of this frame's stuff.  */
-           UNGCPRO;
-            return make_number (-2); /* wrong_kboard_jmpbuf */
-         }
-      }
-      goto non_reread;
-    }
-
   /* Start idle timers if no time limit is supplied.  We don't do it
      if a time limit is supplied to avoid an infinite recursion in the
      situation where an idle timer calls `sit-for'.  */
@@ -3057,7 +3100,6 @@ read_char (int commandflag, Lisp_Object map,
       ptrdiff_t key_count;
       bool key_count_reset;
       struct gcpro gcpro1;
-      ptrdiff_t count = SPECPDL_INDEX ();
 
       /* Save the echo status.  */
       bool saved_immediate_echo = current_kboard->immediate_echo;
@@ -3065,6 +3107,8 @@ read_char (int commandflag, Lisp_Object map,
       Lisp_Object saved_echo_string = KVAR (current_kboard, echo_string);
       ptrdiff_t saved_echo_after_prompt = current_kboard->echo_after_prompt;
 
+      dynwind_begin ();
+
 #if 0
       if (before_command_restore_flag)
        {
@@ -3106,7 +3150,7 @@ read_char (int commandflag, Lisp_Object map,
       /* Call the input method.  */
       tem = call1 (Vinput_method_function, c);
 
-      tem = unbind_to (count, tem);
+      dynwind_end ();
 
       /* Restore the saved echoing state
         and this_command_keys state.  */
@@ -3193,7 +3237,7 @@ read_char (int commandflag, Lisp_Object map,
   /* Process the help character specially if enabled.  */
   if (!NILP (Vhelp_form) && help_char_p (c))
     {
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
 
       help_form_saved_window_configs
        = Fcons (Fcurrent_window_configuration (Qnil),
@@ -3211,7 +3255,7 @@ read_char (int commandflag, Lisp_Object map,
        }
       while (BUFFERP (c));
       /* Remove the help from the frame.  */
-      unbind_to (count, Qnil);
+      dynwind_end ();
 
       redisplay ();
       if (EQ (c, make_number (040)))
@@ -3226,7 +3270,22 @@ read_char (int commandflag, Lisp_Object map,
  exit:
   RESUME_POLLING;
   RETURN_UNGCPRO (c);
-}
+#undef commandflag
+#undef map
+#undef prev_event
+#undef used_mouse_menu
+#undef end_time
+#undef c
+#undef jmpcount
+#undef local_getcjmp
+#undef save_jump
+#undef previous_echo_area_message
+#undef also_record
+#undef reread
+#undef polling_stopped_here
+#undef orig_kboard
+}
+/* {{coccinelle:skip_end}} */
 
 /* Record a key that came from a mouse menu.
    Record it for echoing, for this-command-keys, and so on.  */
@@ -3419,15 +3478,15 @@ record_char (Lisp_Object c)
    See read_process_output.  */
 
 static void
-save_getcjmp (sys_jmp_buf temp)
+save_getcjmp (sys_jmp_buf *temp)
 {
-  memcpy (temp, getcjmp, sizeof getcjmp);
+  memcpy (*temp, getcjmp, sizeof getcjmp);
 }
 
 static void
-restore_getcjmp (sys_jmp_buf temp)
+restore_getcjmp (sys_jmp_buf *temp)
 {
-  memcpy (getcjmp, temp, sizeof getcjmp);
+  memcpy (getcjmp, *temp, sizeof getcjmp);
 }
 \f
 /* Low level keyboard/mouse input.
@@ -4498,7 +4557,7 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers)
        {
          if (NILP (AREF (chosen_timer, 0)))
            {
-             ptrdiff_t count = SPECPDL_INDEX ();
+             dynwind_begin ();
              Lisp_Object old_deactivate_mark = Vdeactivate_mark;
 
              /* Mark the timer as triggered to prevent problems if the lisp
@@ -4510,7 +4569,7 @@ timer_check_2 (Lisp_Object timers, Lisp_Object idle_timers)
              call1 (Qtimer_event_handler, chosen_timer);
              Vdeactivate_mark = old_deactivate_mark;
              timers_run++;
-             unbind_to (count, Qnil);
+             dynwind_end ();
 
              /* Since we have handled the event,
                 we don't need to tell the caller to wake up and do it.  */
@@ -7597,12 +7656,13 @@ eval_dyn (Lisp_Object form)
 Lisp_Object
 menu_item_eval_property (Lisp_Object sexpr)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object val;
   specbind (Qinhibit_redisplay, Qt);
   val = internal_condition_case_1 (eval_dyn, sexpr, Qerror,
                                   menu_item_eval_property_1);
-  return unbind_to (count, val);
+  dynwind_end ();
+  return val;
 }
 
 /* This function parses a menu item and leaves the result in the
@@ -8251,7 +8311,7 @@ parse_tool_bar_item (Lisp_Object key, Lisp_Object item)
       const char *capt = STRINGP (tcapt) ? SSDATA (tcapt) : "";
       ptrdiff_t max_lbl =
        2 * max (0, min (tool_bar_max_label_size, STRING_BYTES_BOUND / 2));
-      char *buf = xmalloc (max_lbl + 1);
+      char *buf = xmalloc_atomic (max_lbl + 1);
       Lisp_Object new_lbl;
       ptrdiff_t caption_len = strlen (capt);
 
@@ -8849,8 +8909,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
                   bool dont_downcase_last, bool can_return_switch_frame,
                   bool fix_current_buffer, bool prevent_redisplay)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
-
   /* How many keys there are in the current key sequence.  */
   int t;
 
@@ -8917,6 +8975,8 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
 
   struct gcpro gcpro1;
 
+  dynwind_begin ();
+
   GCPRO1 (fake_prefixed_keys);
   raw_keybuf_count = 0;
 
@@ -9148,7 +9208,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
             Just return -1.  */
          if (EQ (key, Qt))
            {
-             unbind_to (count, Qnil);
+              dynwind_end ();
              UNGCPRO;
              return -1;
            }
@@ -9707,7 +9767,7 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
     : Qnil;
 
   unread_switch_frame = delayed_switch_frame;
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   /* Don't downcase the last character if the caller says don't.
      Don't downcase it if the result is undefined, either.  */
@@ -9751,7 +9811,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
   Lisp_Object keybuf[30];
   register int i;
   struct gcpro gcpro1;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   if (!NILP (prompt))
     CHECK_STRING (prompt);
@@ -9797,9 +9857,9 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
       QUIT;
     }
   UNGCPRO;
-  return unbind_to (count,
-                   ((allow_string ? make_event_array : Fvector)
-                    (i, keybuf)));
+  Lisp_Object tem0 = ((allow_string ? make_event_array : Fvector) (i, keybuf));
+  dynwind_end ();
+  return tem0;
 }
 
 DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
@@ -10146,7 +10206,7 @@ Some operating systems cannot stop the Emacs process and resume it later.
 On such systems, Emacs starts a subshell instead of suspending.  */)
   (Lisp_Object stuffstring)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   int old_height, old_width;
   int width, height;
   struct gcpro gcpro1;
@@ -10173,7 +10233,7 @@ On such systems, Emacs starts a subshell instead of suspending.  */)
     sys_subshell ();
   else
     sys_suspend ();
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   /* Check if terminal/window size has changed.
      Note that this is not useful when we are running directly
@@ -10935,6 +10995,8 @@ static const struct event_head head_table[] = {
 void
 syms_of_keyboard (void)
 {
+#include "keyboard.x"
+
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
@@ -11114,38 +11176,6 @@ syms_of_keyboard (void)
   help_form_saved_window_configs = Qnil;
   staticpro (&help_form_saved_window_configs);
 
-  defsubr (&Scurrent_idle_time);
-  defsubr (&Sevent_symbol_parse_modifiers);
-  defsubr (&Sevent_convert_list);
-  defsubr (&Sread_key_sequence);
-  defsubr (&Sread_key_sequence_vector);
-  defsubr (&Srecursive_edit);
-  defsubr (&Strack_mouse);
-  defsubr (&Sinput_pending_p);
-  defsubr (&Srecent_keys);
-  defsubr (&Sthis_command_keys);
-  defsubr (&Sthis_command_keys_vector);
-  defsubr (&Sthis_single_command_keys);
-  defsubr (&Sthis_single_command_raw_keys);
-  defsubr (&Sreset_this_command_lengths);
-  defsubr (&Sclear_this_command_keys);
-  defsubr (&Ssuspend_emacs);
-  defsubr (&Sabort_recursive_edit);
-  defsubr (&Sexit_recursive_edit);
-  defsubr (&Srecursion_depth);
-  defsubr (&Scommand_error_default_function);
-  defsubr (&Stop_level);
-  defsubr (&Sdiscard_input);
-  defsubr (&Sopen_dribble_file);
-  defsubr (&Sset_input_interrupt_mode);
-  defsubr (&Sset_output_flow_control);
-  defsubr (&Sset_input_meta_mode);
-  defsubr (&Sset_quit_char);
-  defsubr (&Sset_input_mode);
-  defsubr (&Scurrent_input_mode);
-  defsubr (&Sposn_at_point);
-  defsubr (&Sposn_at_x_y);
-
   DEFVAR_LISP ("last-command-event", last_command_event,
                     doc: /* Last input event that was part of a command.  */);