]> code.delx.au - gnu-emacs/blobdiff - src/callint.c
Merge from origin/emacs-24
[gnu-emacs] / src / callint.c
index 212dd2e3d62ff4ebeaf5f251156d956a423200e0..0c6c03036c8167306b47a8e4ac24276e717a61af 100644 (file)
@@ -1,5 +1,5 @@
 /* Call a Lisp function interactively.
-   Copyright (C) 1985-1986, 1993-1995, 1997, 2000-2013 Free Software
+   Copyright (C) 1985-1986, 1993-1995, 1997, 2000-2015 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -28,17 +28,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "window.h"
 #include "keymap.h"
 
-Lisp_Object Qminus, Qplus;
-static Lisp_Object Qcall_interactively;
-static Lisp_Object Qcommand_debug_status;
-static Lisp_Object Qenable_recursive_minibuffers;
-
-static Lisp_Object Qhandle_shift_selection;
-
-Lisp_Object Qmouse_leave_buffer_hook;
-
-static Lisp_Object Qlist, Qlet, Qletx, Qsave_excursion, Qprogn, Qif;
-Lisp_Object Qwhen;
 static Lisp_Object preserved_fns;
 
 /* Marker used within call-interactively to refer to point.  */
@@ -112,7 +101,8 @@ If the string begins with `^' and `shift-select-mode' is non-nil,
  Emacs first calls the function `handle-shift-selection'.
 You may use `@', `*', and `^' together.  They are processed in the
  order that they appear, before reading any arguments.
-usage: (interactive &optional ARGS)  */)
+usage: (interactive &optional ARGS)  */
+       attributes: const)
   (Lisp_Object args)
 {
   return Qnil;
@@ -126,7 +116,7 @@ quotify_arg (register Lisp_Object exp)
   if (CONSP (exp)
       || (SYMBOLP (exp)
          && !NILP (exp) && !EQ (exp, Qt)))
-    return Fcons (Qquote, Fcons (exp, Qnil));
+    return list2 (Qquote, exp);
 
   return exp;
 }
@@ -232,6 +222,36 @@ fix_command (Lisp_Object input, Lisp_Object values)
     }
 }
 
+/* Helper function to call `read-file-name' from C.  */
+
+static Lisp_Object
+read_file_name (Lisp_Object default_filename, Lisp_Object mustmatch,
+               Lisp_Object initial, Lisp_Object predicate)
+{
+  struct gcpro gcpro1;
+  GCPRO1 (default_filename);
+  RETURN_UNGCPRO (CALLN (Ffuncall, intern ("read-file-name"),
+                        callint_message, Qnil, default_filename,
+                        mustmatch, initial, predicate));
+}
+
+/* BEWARE: Calling this directly from C would defeat the purpose!  */
+DEFUN ("funcall-interactively", Ffuncall_interactively, Sfuncall_interactively,
+       1, MANY, 0, doc: /* Like `funcall' but marks the call as interactive.
+I.e. arrange that within the called function `called-interactively-p' will
+return non-nil.
+usage: (funcall-interactively FUNCTION &rest ARGUMENTS)  */)
+     (ptrdiff_t nargs, Lisp_Object *args)
+{
+  ptrdiff_t speccount = SPECPDL_INDEX ();
+  temporarily_switch_to_single_kboard (NULL);
+
+  /* Nothing special to do here, all the work is inside
+     `called-interactively-p'.  Which will look for us as a marker in the
+     backtrace.  */
+  return unbind_to (speccount, Ffuncall (nargs, args));
+}
+
 DEFUN ("call-interactively", Fcall_interactively, Scall_interactively, 1, 3, 0,
        doc: /* Call FUNCTION, providing args according to its interactive calling specs.
 Return the value FUNCTION returns.
@@ -250,12 +270,16 @@ invoke it.  If KEYS is omitted or nil, the return value of
 `this-command-keys-vector' is used.  */)
   (Lisp_Object function, Lisp_Object record_flag, Lisp_Object keys)
 {
+  /* `args' will contain the array of arguments to pass to the function.
+     `visargs' will contain the same list but in a nicer form, so that if we
+     pass it to `Fformat' it will be understandable to a human.  */
   Lisp_Object *args, *visargs;
   Lisp_Object specs;
   Lisp_Object filter_specs;
   Lisp_Object teml;
   Lisp_Object up_event;
   Lisp_Object enable;
+  USE_SAFE_ALLOCA;
   ptrdiff_t speccount = SPECPDL_INDEX ();
 
   /* The index of the next element of this_command_keys to examine for
@@ -304,7 +328,7 @@ invoke it.  If KEYS is omitted or nil, the return value of
 
   specs = Qnil;
   string = 0;
-  /* The idea of FILTER_SPECS is to provide away to
+  /* The idea of FILTER_SPECS is to provide a way to
      specify how to represent the arguments in command history.
      The feature is not fully implemented.  */
   filter_specs = Qnil;
@@ -325,15 +349,8 @@ invoke it.  If KEYS is omitted or nil, the return value of
       wrong_type_argument (Qcommandp, function);
   }
 
-  /* If SPECS is set to a string, use it as an interactive prompt.  */
-  if (STRINGP (specs))
-    {
-      /* Make a copy of string so that if a GC relocates specs,
-        `string' will still be valid.  */
-      string = alloca (SBYTES (specs) + 1);
-      memcpy (string, SSDATA (specs), SBYTES (specs) + 1);
-    }
-  else
+  /* If SPECS is not a string, invent one.  */
+  if (! STRINGP (specs))
     {
       Lisp_Object input;
       Lisp_Object funval = Findirect_function (function, Qt);
@@ -373,10 +390,17 @@ invoke it.  If KEYS is omitted or nil, the return value of
       Vreal_this_command = save_real_this_command;
       kset_last_command (current_kboard, save_last_command);
 
-      temporarily_switch_to_single_kboard (NULL);
-      return unbind_to (speccount, apply1 (function, specs));
+      Lisp_Object result
+       = unbind_to (speccount, CALLN (Fapply, Qfuncall_interactively,
+                                      function, specs));
+      SAFE_FREE ();
+      return result;
     }
 
+  /* SPECS is set to a string; use it as an interactive prompt.
+     Copy it so that STRING will be valid even if a GC relocates SPECS.  */
+  SAFE_ALLOCA_STRING (string, specs);
+
   /* Here if function specifies a string to control parsing the defaults.  */
 
   /* Set next_event to point to the first event with parameters.  */
@@ -402,13 +426,13 @@ invoke it.  If KEYS is omitted or nil, the return value of
                    {
                      if (! (*p == 'r' || *p == 'p' || *p == 'P'
                             || *p == '\n'))
-                       Fbarf_if_buffer_read_only ();
+                       Fbarf_if_buffer_read_only (Qnil);
                      p++;
                    }
                  record_then_fail = 1;
                }
              else
-               Fbarf_if_buffer_read_only ();
+               Fbarf_if_buffer_read_only (Qnil);
            }
        }
       /* Ignore this for semi-compatibility with Lucid.  */
@@ -431,7 +455,7 @@ invoke it.  If KEYS is omitted or nil, the return value of
                error ("Attempt to select inactive minibuffer window");
 
              /* If the current buffer wants to clean up, let it.  */
-              Frun_hooks (1, &Qmouse_leave_buffer_hook);
+              run_hook (Qmouse_leave_buffer_hook);
 
              Fselect_window (w, Qnil);
            }
@@ -445,10 +469,11 @@ invoke it.  If KEYS is omitted or nil, the return value of
       else break;
     }
 
-  /* Count the number of arguments, which is one plus the number of arguments
-     the interactive spec would have us give to the function.  */
+  /* Count the number of arguments, which is two (the function itself and
+     `funcall-interactively') plus the number of arguments the interactive spec
+     would have us give to the function.  */
   tem = string;
-  for (nargs = 1; *tem; )
+  for (nargs = 2; *tem; )
     {
       /* 'r' specifications ("point and mark as 2 numeric args")
         produce *two* arguments.  */
@@ -463,21 +488,17 @@ invoke it.  If KEYS is omitted or nil, the return value of
        break;
     }
 
-  if (min (MOST_POSITIVE_FIXNUM,
-          min (PTRDIFF_MAX, SIZE_MAX) / word_size)
-      < nargs)
+  if (MOST_POSITIVE_FIXNUM < min (PTRDIFF_MAX, SIZE_MAX) / word_size
+      && MOST_POSITIVE_FIXNUM < nargs)
     memory_full (SIZE_MAX);
 
-  args = alloca (nargs * sizeof *args);
-  visargs = alloca (nargs * sizeof *visargs);
-  varies = alloca (nargs * sizeof *varies);
+  /* Allocate them all at one go.  This wastes a bit of memory, but
+     it's OK to trade space for speed.  */
+  SAFE_NALLOCA (args, 3, nargs);
+  visargs = args + nargs;
+  varies = (signed char *) (visargs + nargs);
 
-  for (i = 0; i < nargs; i++)
-    {
-      args[i] = Qnil;
-      visargs[i] = Qnil;
-      varies[i] = 0;
-    }
+  memclear (args, nargs * (2 * word_size + 1));
 
   GCPRO5 (prefix_arg, function, *args, *visargs, up_event);
   gcpro3.nvars = nargs;
@@ -487,13 +508,13 @@ invoke it.  If KEYS is omitted or nil, the return value of
     specbind (Qenable_recursive_minibuffers, Qt);
 
   tem = string;
-  for (i = 1; *tem; i++)
+  for (i = 2; *tem; i++)
     {
-      visargs[0] = make_string (tem + 1, strcspn (tem + 1, "\n"));
-      if (strchr (SSDATA (visargs[0]), '%'))
-       callint_message = Fformat (i, visargs);
+      visargs[1] = make_string (tem + 1, strcspn (tem + 1, "\n"));
+      if (strchr (SSDATA (visargs[1]), '%'))
+       callint_message = Fformat (i - 1, visargs + 1);
       else
-       callint_message = visargs[0];
+       callint_message = visargs[1];
 
       switch (*tem)
        {
@@ -525,7 +546,7 @@ invoke it.  If KEYS is omitted or nil, the return value of
                              make_number (SCHARS (callint_message)),
                              Qface, Qminibuffer_prompt, callint_message);
          args[i] = Fread_char (callint_message, Qnil, Qnil);
-         message1_nolog ((char *) 0);
+         message1_nolog (0);
          /* Passing args[i] directly stimulates compiler bug.  */
          teml = args[i];
          /* See bug#8479.  */
@@ -550,25 +571,21 @@ invoke it.  If KEYS is omitted or nil, the return value of
          break;
 
        case 'D':               /* Directory name.  */
-         args[i] = Fread_file_name (callint_message, Qnil,
-                                    BVAR (current_buffer, directory), Qlambda, Qnil,
-                                    Qfile_directory_p);
+         args[i] = read_file_name (BVAR (current_buffer, directory), Qlambda, Qnil,
+                                   Qfile_directory_p);
          break;
 
        case 'f':               /* Existing file name.  */
-         args[i] = Fread_file_name (callint_message,
-                                    Qnil, Qnil, Qlambda, Qnil, Qnil);
+         args[i] = read_file_name (Qnil, Qlambda, Qnil, Qnil);
          break;
 
        case 'F':               /* Possibly nonexistent file name.  */
-         args[i] = Fread_file_name (callint_message,
-                                    Qnil, Qnil, Qnil, Qnil, Qnil);
+         args[i] = read_file_name (Qnil, Qnil, Qnil, Qnil);
          break;
 
        case 'G':               /* Possibly nonexistent file name,
                                   default to directory alone.  */
-         args[i] = Fread_file_name (callint_message,
-                                    Qnil, Qnil, Qnil, empty_unibyte_string, Qnil);
+         args[i] = read_file_name (Qnil, Qnil, empty_unibyte_string, Qnil);
          break;
 
        case 'i':               /* Ignore an argument -- Does not do I/O.  */
@@ -598,9 +615,9 @@ invoke it.  If KEYS is omitted or nil, the return value of
              {
                Lisp_Object tem2;
 
-               teml = Fget (teml, intern ("event-symbol-elements"));
+               teml = Fget (teml, Qevent_symbol_elements);
                /* Ignore first element, which is the base key.  */
-               tem2 = Fmemq (intern ("down"), Fcdr (teml));
+               tem2 = Fmemq (Qdown, Fcdr (teml));
                if (! NILP (tem2))
                  up_event = Fread_event (Qnil, Qnil, Qnil);
              }
@@ -615,8 +632,8 @@ invoke it.  If KEYS is omitted or nil, the return value of
            Fput_text_property (make_number (0),
                                make_number (SCHARS (callint_message)),
                                Qface, Qminibuffer_prompt, callint_message);
-           args[i] = Fread_key_sequence (callint_message,
-                                         Qnil, Qt, Qnil, Qnil);
+           args[i] = Fread_key_sequence_vector (callint_message,
+                                                Qnil, Qt, Qnil, Qnil);
            teml = args[i];
            visargs[i] = Fkey_description (teml, Qnil);
            unbind_to (speccount1, Qnil);
@@ -630,9 +647,9 @@ invoke it.  If KEYS is omitted or nil, the return value of
              {
                Lisp_Object tem2;
 
-               teml = Fget (teml, intern ("event-symbol-elements"));
+               teml = Fget (teml, Qevent_symbol_elements);
                /* Ignore first element, which is the base key.  */
-               tem2 = Fmemq (intern ("down"), Fcdr (teml));
+               tem2 = Fmemq (Qdown, Fcdr (teml));
                if (! NILP (tem2))
                  up_event = Fread_event (Qnil, Qnil, Qnil);
              }
@@ -683,29 +700,10 @@ invoke it.  If KEYS is omitted or nil, the return value of
          if (!NILP (prefix_arg))
            goto have_prefix_arg;
        case 'n':               /* Read number from minibuffer.  */
-         {
-           bool first = 1;
-           do
-             {
-               Lisp_Object str;
-               if (! first)
-                 {
-                   message1 ("Please enter a number.");
-                   sit_for (make_number (1), 0, 0);
-                 }
-               first = 0;
-
-               str = Fread_from_minibuffer (callint_message,
-                                            Qnil, Qnil, Qnil, Qnil, Qnil,
-                                            Qnil);
-               if (! STRINGP (str) || SCHARS (str) == 0)
-                 args[i] = Qnil;
-               else
-                 args[i] = Fread (str);
-             }
-           while (! NUMBERP (args[i]));
-         }
-         visargs[i] = args[i];
+         args[i] = call1 (Qread_number, callint_message);
+         /* Passing args[i] directly stimulates compiler bug.  */
+         teml = args[i];
+         visargs[i] = Fnumber_to_string (teml);
          break;
 
        case 'P':               /* Prefix arg in raw form.  Does no I/O.  */
@@ -754,12 +752,12 @@ invoke it.  If KEYS is omitted or nil, the return value of
          break;
 
        case 'x':               /* Lisp expression read but not evaluated.  */
-         args[i] = Fread_minibuffer (callint_message, Qnil);
+         args[i] = call1 (intern ("read-minibuffer"), callint_message);
          visargs[i] = last_minibuf_string;
          break;
 
        case 'X':               /* Lisp expression read and evaluated.  */
-         args[i] = Feval_minibuffer (callint_message, Qnil);
+         args[i] = call1 (intern ("eval-minibuffer"), callint_message);
          visargs[i] = last_minibuf_string;
          break;
 
@@ -767,7 +765,7 @@ invoke it.  If KEYS is omitted or nil, the return value of
                                   argument if no prefix.  */
          if (NILP (prefix_arg))
            {
-             args[i] = Qnil;
+             /* args[i] = Qnil; */
              varies[i] = -1;
            }
          else
@@ -807,19 +805,22 @@ invoke it.  If KEYS is omitted or nil, the return value of
 
   QUIT;
 
-  args[0] = function;
+  args[0] = Qfuncall_interactively;
+  args[1] = function;
 
   if (arg_from_tty || !NILP (record_flag))
     {
-      visargs[0] = function;
-      for (i = 1; i < nargs; i++)
+      /* We don't need `visargs' any more, so let's recycle it since we need
+        an array of just the same size.  */
+      visargs[1] = function;
+      for (i = 2; i < nargs; i++)
        {
          if (varies[i] > 0)
-           visargs[i] = Fcons (intern (callint_argfuns[varies[i]]), Qnil);
+           visargs[i] = list1 (intern (callint_argfuns[varies[i]]));
          else
            visargs[i] = quotify_arg (args[i]);
        }
-      Vcommand_history = Fcons (Flist (nargs, visargs),
+      Vcommand_history = Fcons (Flist (nargs - 1, visargs + 1),
                                Vcommand_history);
       /* Don't keep command history around forever.  */
       if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0)
@@ -832,12 +833,12 @@ invoke it.  If KEYS is omitted or nil, the return value of
 
   /* If we used a marker to hold point, mark, or an end of the region,
      temporarily, convert it to an integer now.  */
-  for (i = 1; i < nargs; i++)
+  for (i = 2; i < nargs; i++)
     if (varies[i] >= 1 && varies[i] <= 4)
       XSETINT (args[i], marker_position (args[i]));
 
   if (record_then_fail)
-    Fbarf_if_buffer_read_only ();
+    Fbarf_if_buffer_read_only (Qnil);
 
   Vthis_command = save_this_command;
   Vthis_original_command = save_this_original_command;
@@ -845,13 +846,11 @@ invoke it.  If KEYS is omitted or nil, the return value of
   kset_last_command (current_kboard, save_last_command);
 
   {
-    Lisp_Object val;
-    specbind (Qcommand_debug_status, Qnil);
-
-    temporarily_switch_to_single_kboard (NULL);
-    val = Ffuncall (nargs, args);
+    Lisp_Object val = Ffuncall (nargs, args);
     UNGCPRO;
-    return unbind_to (speccount, val);
+    val = unbind_to (speccount, val);
+    SAFE_FREE ();
+    return val;
   }
 }
 
@@ -903,7 +902,8 @@ syms_of_callint (void)
   DEFSYM (Qminus, "-");
   DEFSYM (Qplus, "+");
   DEFSYM (Qhandle_shift_selection, "handle-shift-selection");
-  DEFSYM (Qcall_interactively, "call-interactively");
+  DEFSYM (Qread_number, "read-number");
+  DEFSYM (Qfuncall_interactively, "funcall-interactively");
   DEFSYM (Qcommand_debug_status, "command-debug-status");
   DEFSYM (Qenable_recursive_minibuffers, "enable-recursive-minibuffers");
   DEFSYM (Qmouse_leave_buffer_hook, "mouse-leave-buffer-hook");
@@ -961,5 +961,6 @@ a way to turn themselves off when a mouse command switches windows.  */);
 
   defsubr (&Sinteractive);
   defsubr (&Scall_interactively);
+  defsubr (&Sfuncall_interactively);
   defsubr (&Sprefix_numeric_value);
 }