/* Call a Lisp function interactively.
- Copyright (C) 1985-1986, 1993-1995, 1997, 2000-2014 Free Software
+ Copyright (C) 1985-1986, 1993-1995, 1997, 2000-2015 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
#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;
-static Lisp_Object Qread_number;
-
-Lisp_Object Qmouse_leave_buffer_hook;
-
-static Lisp_Object Qlist, Qlet, Qletx, Qsave_excursion, Qif;
-Lisp_Object Qwhen, Qprogn;
static Lisp_Object preserved_fns;
/* Marker used within call-interactively to refer to point. */
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;
}
}
+/* 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;
+ Lisp_Object args[7];
+
+ GCPRO1 (default_filename);
+ args[0] = intern ("read-file-name");
+ args[1] = callint_message;
+ args[2] = Qnil;
+ args[3] = default_filename;
+ args[4] = mustmatch;
+ args[5] = initial;
+ args[6] = predicate;
+ RETURN_UNGCPRO (Ffuncall (7, args));
+}
+
+/* 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.
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
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 = xlispstrdupa (specs);
- else
+ /* If SPECS is not a string, invent one. */
+ if (! STRINGP (specs))
{
Lisp_Object input;
Lisp_Object funval = Findirect_function (function, Qt);
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 args[3];
+ args[0] = Qfuncall_interactively;
+ args[1] = function;
+ args[2] = specs;
+ Lisp_Object result = unbind_to (speccount, Fapply (3, args));
+ 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. */
{
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. */
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);
}
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. */
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++)
{
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)
{
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. */
QUIT;
- args[0] = function;
+ args[0] = Qfuncall_interactively;
+ args[1] = function;
if (arg_from_tty || !NILP (record_flag))
{
/* We don't need `visargs' any more, so let's recycle it since we need
an array of just the same size. */
- visargs[0] = function;
- for (i = 1; i < nargs; i++)
+ visargs[1] = function;
+ for (i = 2; i < nargs; i++)
{
if (varies[i] > 0)
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)
/* 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;
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;
}
}
DEFSYM (Qplus, "+");
DEFSYM (Qhandle_shift_selection, "handle-shift-selection");
DEFSYM (Qread_number, "read-number");
- DEFSYM (Qcall_interactively, "call-interactively");
+ 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");
defsubr (&Sinteractive);
defsubr (&Scall_interactively);
+ defsubr (&Sfuncall_interactively);
defsubr (&Sprefix_numeric_value);
}