/* Call a Lisp function interactively.
   Copyright (C) 1985, 1986, 1992, 1993, 1994 Free Software Foundation, Inc.

This file is part of XEmacs.

XEmacs is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

XEmacs is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with XEmacs; see the file COPYING.  If not, write to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* Synched up with: Mule 2.0.  Not synched with FSF. */

#include <config.h>
#include "lisp.h"
#include "buffer.h"
#include "bytecode.h"
#include "commands.h"
#include "window.h"
#include "emacsfns.h"
#include "insdel.h"

extern int num_input_chars;

Lisp_Object Vprefix_arg, Vcurrent_prefix_arg;
Lisp_Object Qcall_interactively;
Lisp_Object Vcommand_history;

Lisp_Object Vcommand_debug_status, Qcommand_debug_status;
Lisp_Object Qenable_recursive_minibuffers;

Lisp_Object Qcurrent_prefix_arg;

Lisp_Object Quser_variable_p;
Lisp_Object Qread_from_minibuffer;
Lisp_Object Qread_file_name;
Lisp_Object Qread_directory_name;
Lisp_Object Qcompleting_read;
Lisp_Object Qread_buffer;
Lisp_Object Qread_function;
Lisp_Object Qread_variable;
Lisp_Object Qread_expression;
Lisp_Object Qread_command;
Lisp_Object Qread_number;
Lisp_Object Qread_string;
Lisp_Object Qevents_to_keys;

#ifdef MULE
Lisp_Object Qread_coding_system;
Lisp_Object Qread_non_nil_coding_system;
#endif

/* ARGSUSED */
DEFUN ("interactive", Finteractive, Sinteractive, 0, UNEVALLED, 0,
 "Specify a way of parsing arguments for interactive use of a function.\n\
For example, write\n\
  (defun foo (arg) \"Doc string\" (interactive \"p\") ...use arg...)\n\
to make ARG be the prefix argument when `foo' is called as a command.\n\
The \"call\" to `interactive' is actually a declaration rather than a function;\n\
 it tells `call-interactively' how to read arguments\n\
 to pass to the function.\n\
When actually called, `interactive' just returns nil.\n\
\n\
The argument of `interactive' is usually a string containing a code letter\n\
 followed by a prompt.  (Some code letters do not use I/O to get\n\
 the argument and do not need prompts.)  To prompt for multiple arguments,\n\
 give a code letter, its prompt, a newline, and another code letter, etc.\n\
 Prompts are passed to format, and may use % escapes to print the\n\
 arguments that have already been read.\n\
If the argument is not a string, it is evaluated to get a list of\n\
 arguments to pass to the function.\n\
Just `(interactive)' means pass no args when calling interactively.\n\
\nCode letters available are:\n\
a -- Function name: symbol with a function definition.\n\
b -- Name of existing buffer.\n\
B -- Name of buffer, possibly nonexistent.\n\
c -- Character.\n\
C -- Command name: symbol with interactive function definition.\n\
d -- Value of point as number.  Does not do I/O.\n\
D -- Directory name.\n\
e -- Last mouse event.  Does not do I/O.\n\
f -- Existing file name.\n\
F -- Possibly nonexistent file name.\n\
i -- Always nil.  Does not do I/O.\n\
k -- Key sequence (a vector of events).\n\
m -- Value of mark as number.  Does not do I/O.\n\
n -- Number read using minibuffer.\n\
N -- Prefix arg converted to number, or if none, do like code `n'.\n\
p -- Prefix arg converted to number.  Does not do I/O.\n\
P -- Prefix arg in raw form.  Does not do I/O.\n\
r -- Region: point and mark as 2 numeric args, smallest first.  Does no I/O.\n\
s -- Any string.\n\
S -- Any symbol.\n\
v -- Variable name: symbol that is user-variable-p.\n\
x -- Lisp expression read but not evaluated.\n\
X -- Lisp expression read and evaluated.\n\
z -- Coding system.\n\
Z -- Coding system, nil if no prefix arg.\n\
In addition, if the string begins with `*'\n\
 then an error is signaled if the buffer is read-only.\n\
 This happens before reading any arguments.\n\
If the string begins with `@', then the window the mouse is over is selected\n\
 before anything else is done.\n\
If the string begins with `_', then this command will not cause the region\n\
 to be deactivated when it completes; that is, `zmacs-region-stays' will be\n\
 set to t when the command exits successfully.\n\
You may use any of `@', `*' and `_' at the beginning of the string;\n\
 they are processed in the order that they appear.")
  (args)
     Lisp_Object args;
{
  return Qnil;
}

/* Quotify EXP: if EXP is constant, return it.
   If EXP is not constant, return (quote EXP).  */
static Lisp_Object
quotify_arg (Lisp_Object exp)
{
  if (!INTP (exp) && !STRINGP (exp)
      && !NILP (exp) && !EQ (exp, Qt))
    return Fcons (Qquote, Fcons (exp, Qnil));

  return exp;
}

/* Modify EXP by quotifying each element (except the first).  */
static Lisp_Object
quotify_args (Lisp_Object exp)
{
  REGISTER Lisp_Object tail;
  REGISTER struct Lisp_Cons *ptr;
  for (tail = exp; CONSP (tail); tail = ptr->cdr)
    {
      ptr = XCONS (tail);
      ptr->car = quotify_arg (ptr->car);
    }
  return exp;
}

static Bufpos
check_mark (void)
{
  Lisp_Object tem;

  if (zmacs_regions && !zmacs_region_active_p)
    error ("The region is not active now");

  tem = Fmarker_buffer (current_buffer->mark);
  if (NILP (tem) || (XBUFFER (tem) != current_buffer))
    error ("The mark is not set now");

  return (marker_position (current_buffer->mark));
}

Lisp_Object Vcurrent_mouse_event;

static Lisp_Object
callint_prompt (CONST Bufbyte *prompt_start, Bytecount prompt_length,
                CONST Lisp_Object *args, int nargs)
{
  Lisp_Object s = make_string (prompt_start, prompt_length);
  struct gcpro gcpro1;

  /* Fformat no longer smashes its arg vector, so no need to copy it. */
  
  if (!strchr ((char *) string_data (XSTRING (s)), '%'))
    return (s);
  GCPRO1 (s);
  RETURN_UNGCPRO (emacs_doprnt_string_lisp (0, s, 0, nargs, args));
}

DEFUN ("call-interactively", Fcall_interactively, Scall_interactively, 1, 2, 0,
  "Call FUNCTION, reading args according to its interactive calling specs.\n\
The function contains a specification of how to do the argument reading.\n\
In the case of user-defined functions, this is specified by placing a call\n\
to the function `interactive' at the top level of the function body.\n\
See `interactive'.\n\
\n\
If optional second arg RECORD-FLAG is the symbol `lambda', the interactive\n\
calling arguments for FUNCTION are read and returned as a list,\n\
but the function is not called on them.\n\
\n\
If RECORD-FLAG is `t' then unconditionally put this command in the\n\
command-history.  Otherwise, this is done only if an arg is read using\n\
the minibuffer.")
  (function, record_flag)
     Lisp_Object function, record_flag;
{
  /* This function can GC */
  int speccount = specpdl_depth ();
  /* Save this now, since use of minibuffer will clobber it. */
  Lisp_Object prefix = Vcurrent_prefix_arg;

  Lisp_Object fun;
  Lisp_Object specs = Qnil;
  /* If SPECS is a string, we reset prompt_data to string_data (XSTRING (specs))
   *  every time a GC might have occurred */
  CONST char *prompt_data = 0;
  int prompt_index = 0;
  int argcount;
  int set_zmacs_region_stays = 0;

 retry:

  fun = indirect_function (function, 1);

  /* Decode the kind of function.  Either handle it and return,
     or go to `lose' if not interactive, or go to `retry'
     to specify a different function, or set either PROMPT_DATA or SPECS. */

  if (SUBRP (fun))
    {
      prompt_data = XSUBR (fun)->prompt;
      if (!prompt_data)
	{
	lose:
	  function = wrong_type_argument (Qcommandp, function);
	  goto retry;
	}
    }
  else if (BYTECODEP (fun))
    {
      struct Lisp_Bytecode *b = XBYTECODE (fun);
      if (!(b->flags.interactivep))
        goto lose;
      specs = bytecode_interactive (b);
    }
  else if (!CONSP (fun))
    goto lose;
  else
    {
      Lisp_Object funcar = Fcar (fun);

      if (EQ (funcar, Qautoload))
	{
	  struct gcpro gcpro1, gcpro2;
	  GCPRO2 (function, prefix);
	  do_autoload (fun, function);
	  UNGCPRO;
	  goto retry;
	}
      else if (EQ (funcar, Qlambda))
	{
	  specs = Fassq (Qinteractive, Fcdr (Fcdr (fun)));
	  if (NILP (specs))
	    goto lose;
	  specs = Fcar (Fcdr (specs));
	}
#ifdef MOCKLISP_SUPPORT
      else if (EQ (funcar, Qmocklisp))
	return ml_apply (fun, Qinteractive);
#endif
      else
	goto lose;
    }

  /* If either specs or prompt_data is set to a string, use it.  */
  if (!STRINGP (specs) && prompt_data == 0)
    {
      struct gcpro gcpro1, gcpro2;
      int i = num_input_chars;
      GCPRO2 (function, specs);
      specs = Feval (specs);
      if (EQ (record_flag, Qlambda))
	{
	  UNGCPRO;
	  return (specs);
	}
      if (!NILP (record_flag) || i != num_input_chars)
	{
	  /* #### There's no way for an interactive spec to put something
	   *  other than its literal arguments on the command-history.
	   *  For example, it should be possible to put (region-beginning)
	   *  on instead of some random point position like 259.
	   */
	  Vcommand_history
	    = Fcons (Fcons (function, quotify_args (Fcopy_sequence (specs))),
		     Vcommand_history);
	}
      RETURN_UNGCPRO (apply1 (fun, specs));
    }

  /* Here if function specifies a string to control parsing the defaults */

#ifdef I18N3
  /* Translate interactive prompt. */
  if (STRINGP (specs))
    {
      Lisp_Object domain = Qnil;
      if (BYTECODEP (fun))
	domain = Fcompiled_function_domain (fun);
      if (NILP (domain))
	specs = Fgettext (specs);
      else
	specs = Fdgettext (domain, specs);
    }
  else if (prompt_data)
    /* We do not have to worry about domains in this case because
       prompt_data is non-nil only for built-in functions, which
       always use the default domain. */
    prompt_data = gettext (prompt_data);
#endif

  /* Handle special starting chars `*' and `@' and `_'.  */
  prompt_index = 0;
  {
    struct gcpro gcpro1, gcpro2;
    GCPRO2 (function, specs);

    for (;;)
      {
	if (STRINGP (specs)) prompt_data = (CONST char *) string_data (XSTRING (specs));
    
	if (prompt_data[prompt_index] == '*')
	  {
	    prompt_index++;
	    if (!NILP (current_buffer->read_only))
	      barf_if_buffer_read_only (current_buffer, -1, -1);
	  }
	else if (prompt_data[prompt_index] == '@')
	  {
	    prompt_index++;
	    /* For non-window systems we just silently ignore @. */
#ifdef HAVE_WINDOW_SYSTEM
	    if (! NILP (Vcurrent_mouse_event)) 
	      {
		Lisp_Object window = Fevent_window (Vcurrent_mouse_event);
		if (!NILP (window))
		  Fselect_window (window);
	      }
#endif /* HAVE_WINDOW_SYSTEM */
	  }
	else if (prompt_data[prompt_index] == '_')
	  {
	    prompt_index++;
	    set_zmacs_region_stays = 1;
	  }
	else
	  {
	    UNGCPRO;
	    break;
	  }
      }
  }

  /* Count the number of arguments the interactive spec would have
     us give to the function.  */
  argcount = 0;
  {
    CONST char *tem;
    for (tem = prompt_data + prompt_index; *tem; )
      {
	/* 'r' specifications ("point and mark as 2 numeric args")
	   produce *two* arguments.  */
	if (*tem == 'r')
	  argcount += 2;
	else
	  argcount += 1;
	tem = (CONST char *) strchr (tem + 1, '\n');
	if (!tem)
	  break;
	tem++;
      }
  }

  if (argcount == 0)
    {
      /* Interactive function or no arguments; just call it */
      if (EQ (record_flag, Qlambda))
	return (Qnil);
      if (!NILP (record_flag))
	{
	  Vcommand_history = Fcons (list1 (function), Vcommand_history);
	}
      specbind (Qcommand_debug_status, Qnil);
      fun = call0 (fun);
      if (set_zmacs_region_stays)
	zmacs_region_stays = 1;
      return (unbind_to (speccount, fun));
    }

  /* Read interactive arguments */
  {
    /* args[-1] is the function to call */
    /* args[n] is the n'th argument to the function */
    int alloca_size = (1	/* function to call */
                       + argcount /* actual arguments */
                       + argcount /* visargs */
                       + argcount /* varies */
                       );
    Lisp_Object *args
      = (((Lisp_Object *) alloca (sizeof (Lisp_Object) * alloca_size))
         + 1);
    /* visargs is an array of either Qnil or user-friendlier versions (often
     *  strings) of previous arguments, to use in prompts for succesive
     *  arguments.  ("Often strings" because emacs didn't used to have
     *  format %S and prin1-to-string.) */
    Lisp_Object *visargs = args + argcount;
    /* If varies[i] is non-null, the i'th argument shouldn't just have
       its value in this call quoted in the command history.  It should be
       recorded as a call to the function named varies[i]]. */
    Lisp_Object *varies = visargs + argcount;
    int arg_from_tty = 0;
    REGISTER int argnum;
    struct gcpro gcpro1, gcpro2;

    args[-1] = function;
    for (argnum = 0; argnum < alloca_size - 1; argnum++)
      args[argnum] = Qnil;

    /* Must GC-protect args[-1] (ie function) because Ffuncall doesn't */
    /* `function' itself isn't GC-protected -- use args[-1] from here
       (actually, doesn't matter since Emacs GC doesn't relocate, sigh) */
    GCPRO2 (prefix, args[-1]);
    gcpro2.nvars = alloca_size;

    /* Marginal kludge.  Use an evaluated interactive spec instead of this!
     * if (SYMBOLP (args[-1])
     *     && !NILP (Fget (args[-1], Qenable_recursive_minibuffers, Qnil)))
     *   specbind (Qenable_recursive_minibuffers, Qt);
     */

    for (argnum = 0; ; argnum++)
      {
	CONST char *prompt_start = prompt_data + prompt_index + 1;
	CONST char *prompt_limit = (CONST char *) strchr (prompt_start, '\n');
	int prompt_length;
	prompt_length = ((prompt_limit) 
			 ? (prompt_limit - prompt_start)
			 : strlen (prompt_start));
	if (prompt_limit && prompt_limit[1] == 0)
	  {
	    prompt_limit = 0;	/* "sfoo:\n" -- strip tailing return */
	    prompt_length -= 1;
	  }
	/* This uses `visargs' instead of `args' so that global-set-key
	   prompts with "Set key C-x C-f to command: "instead of printing
	   event objects in there.
	 */
#define PROMPT() callint_prompt ((Bufbyte *) prompt_start, prompt_length, visargs, argnum)
	switch (prompt_data[prompt_index])
	  {
	  case 'a':		/* Symbol defined as a function */
	    {
	      Lisp_Object tem = call1 (Qread_function, PROMPT ());
	      args[argnum] = tem;
	      arg_from_tty = 1;
	      break;
	    }
	  case 'b':   		/* Name of existing buffer */
	    {
	      Lisp_Object def = Fcurrent_buffer ();
	      if (EQ (Fselected_window (Qnil), minibuf_window))
		def = Fother_buffer (def, Qnil, Qnil);
              /* read-buffer returns a buffer name, not a buffer! */
	      args[argnum] = call3 (Qread_buffer, PROMPT (), def,
				    Qt);
	      arg_from_tty = 1;
	      break;
	    }
	  case 'B':		/* Name of buffer, possibly nonexistent */
	    {
              /* read-buffer returns a buffer name, not a buffer! */
	      args[argnum] = call2 (Qread_buffer, PROMPT (),
				    Fother_buffer (Fcurrent_buffer (), Qnil,
						   Qnil));
	      arg_from_tty = 1;
	      break;
	    }
	  case 'c':		/* Character */
	    {
              Lisp_Object tem;
	      int speccount = specpdl_depth ();

	      specbind (Qcursor_in_echo_area, Qt);
	      message ("%s", string_data (XSTRING (PROMPT ())));
	      tem = (call0 (Qread_char));
              args[argnum] = tem;
              /* visargs[argnum] = Fsingle_key_description (tem); */

	      unbind_to (speccount, Qnil);

	      /* #### `C-x / a' should not leave the prompt in the minibuffer.
		 This isn't the right fix, because (message ...) (read-char)
		 shouldn't leave the message there either... */
	      message (0);

	      arg_from_tty = 1;
	      break;
	    }
	  case 'C':		/* Command: symbol with interactive function */
	    {
	      Lisp_Object tem = call1 (Qread_command, PROMPT ());
	      args[argnum] = tem;
	      arg_from_tty = 1;
	      break;
	    }
	  case 'd':		/* Value of point.  Does not do I/O.  */
	    {
	      args[argnum] = make_number (BUF_PT (current_buffer));
	      varies[argnum] = Qpoint;
	      break;
	    }
	  case 'e':
	    {
	      args[argnum] = Vcurrent_mouse_event;
	      break;
	    }
	  case 'D':		/* Directory name. */
	    {
	      args[argnum] = call4 (Qread_directory_name, PROMPT (),
				    Qnil, /* dir */
				    current_buffer->directory, /* default */
				    Qt /* must-match */
				    );
	      arg_from_tty = 1;
	      break;
	    }
	  case 'f':		/* Existing file name. */
	    {
	      Lisp_Object tem = call4 (Qread_file_name, PROMPT (),
				       Qnil, /* dir */
				       Qnil, /* default */
				       make_number (0) /* must-match */
				       );
              args[argnum] = tem;
	      arg_from_tty = 1;
	      break;
	    }
	  case 'F':		/* Possibly nonexistent file name. */
	    {
	      args[argnum] = call4 (Qread_file_name, PROMPT (),
				    Qnil, /* dir */
				    Qnil, /* default */
				    Qnil /* must-match */
				    );
	      arg_from_tty = 1;
	      break;
	    }
	  case 'i':		/* Ignore an argument -- Does not do I/O */
	    {
	      break;
	    }
	  case 'k':		/* Key sequence (vector of events) */
	    {
	      Lisp_Object tem = Fread_key_sequence (PROMPT ());
	      visargs[argnum] = Fkey_description (tem);
	      /* The following makes `describe-key' not work with
		 extent-local keymaps and such; and anyway, it's
		 contrary to the documentation. */
	      /* args[argnum] = call1 (Qevents_to_keys, tem); */
	      args[argnum] = tem;
	      arg_from_tty = 1;
	      break;
	    }

	  case 'm':		/* Value of mark.  Does not do I/O.  */
	    {
	      args[argnum] = make_number (check_mark ());
	      varies[argnum] = Qmark;
	      break;
	    }
	  case 'n':		/* Read number from minibuffer.  */
	    {
	    read_number:
	      args[argnum] = call2 (Qread_number, PROMPT (), Qt);
	      /* numbers are too boring to go on command history */
	      /* arg_from_tty = 1; */
              break;
            }
	  case 'N':		/* Prefix arg, else number from minibuffer */
	    {
	      if (NILP (prefix))
		goto read_number;
              else
                goto prefix_value;
	    }
	  case 'P':		/* Prefix arg in raw form.  Does no I/O.  */
	    {
	      args[argnum] = prefix;
	      break;
	    }
	  case 'p':		/* Prefix arg converted to number.  No I/O. */
            {
            prefix_value:
              {
                Lisp_Object tem = Fprefix_numeric_value (prefix);
                args[argnum] = tem;
              }
              break;
            }
	  case 'r':		/* Region, point and mark as 2 args. */
	    {
	      Bufpos tem = check_mark ();
	      args[argnum] = make_number (((BUF_PT (current_buffer) < tem) ? BUF_PT (current_buffer) : tem));
	      varies[argnum] = Qregion_beginning;
	      args[++argnum] = make_number (((BUF_PT (current_buffer) > tem) ? BUF_PT (current_buffer) : tem));
	      varies[argnum] = Qregion_end;
	      break;
	    }
	  case 's':		/* String read via minibuffer.  */
	    {
	      args[argnum] = call1 (Qread_string, PROMPT ());
	      arg_from_tty = 1;
	      break;
	    }
	  case 'S':		/* Any symbol.  */
	    {
#if 0				/* Historical crock */
	      Lisp_Object tem = intern ("minibuffer-local-ns-map");
	      tem = find_symbol_value (tem);
	      if (EQ (tem, Qunbound)) tem = Qnil;
	      tem = call3 (Qread_from_minibuffer, PROMPT (), Qnil,
			   tem);
	      args[argnum] = Fintern (tem, Qnil);
#else /* 1 */
	      visargs[argnum] = Qnil;
	      for (;;)
		{
		  Lisp_Object tem = call5 (Qcompleting_read,
					   PROMPT (),
					   Vobarray,
					   Qnil,
					   Qnil,
					   /* nil, or prev attempt */
					   visargs[argnum]);
		  visargs[argnum] = tem;
		  /* I could use condition-case with this loser, but why bother?
		   * tem = Fread (tem); check-symbol-p;
		   */
		  tem = Fintern (tem, Qnil);
		  args[argnum] = tem;
		  if (string_length (XSYMBOL (tem)->name) > 0)
		    /* Don't accept the empty-named symbol.  If the loser
		       really wants this s/he can call completing-read 
                       directly */
		    break;
		}
#endif /* 1 */
	      arg_from_tty = 1;
	      break;
	    }
	  case 'v':		/* Variable name: user-variable-p symbol */
	    {
	      Lisp_Object tem = call1 (Qread_variable, PROMPT ());
	      args[argnum] = tem;
	      arg_from_tty = 1;
	      break;
	    }
	  case 'x':		/* Lisp expression read but not evaluated */
	    {
	      args[argnum] = call1 (Qread_expression, PROMPT ());
              /* visargs[argnum] = Fprin1_to_string (args[argnum], Qnil); */
	      arg_from_tty = 1;
	      break;
	    }
	  case 'X':		/* Lisp expression read and evaluated */
	    {
	      Lisp_Object tem = call1 (Qread_expression, PROMPT ());
	      /* visargs[argnum] = Fprin1_to_string (tem, Qnil); */
	      args[argnum] = Feval (tem);
	      arg_from_tty = 1;
	      break;
	    }
#ifdef MULE
	  case 'Z':		/* Coding-system symbol or nil if no prefix */
	    {
	      if (NILP (prefix_arg))
		{
		  args[argnum] = Qnil;
		  varies[argnum] = -1;
		}
	      else 
		{
		  args[argnum] =
		    call1 (Qread_non_nil_coding_system, PROMPT ());
		  arg_from_tty = 1;
		}
	      break;
	    }
	  case 'z':		/* Coding-system symbol */
	    {
	      args[argnum] = call1 (Qread_coding_system, PROMPT ());
	      arg_from_tty = 1;
	      break;
	    }
#endif
	  default:
	    {
	      error ("Invalid `interactive' control letter \"%c\" (#o%03o).",
		     prompt_data[prompt_index],
		     prompt_data[prompt_index]);
	    }
	  }
#undef PROMPT
	if (NILP (visargs[argnum]))
	  visargs[argnum] = args[argnum];

	if (!prompt_limit)
	  break;
	if (STRINGP (specs)) prompt_data = (CONST char *) string_data (XSTRING (specs));
	prompt_index += prompt_length + 1 + 1; /* +1 to skip spec, +1 for \n */
      }
    unbind_to (speccount, Qnil);

    QUIT;

    if (EQ (record_flag, Qlambda))
      {
	RETURN_UNGCPRO (Flist (argcount, args));
      }
      
    if (arg_from_tty || !NILP (record_flag))
      {
        /* Reuse visargs as a temporary for constructing the command history */
	for (argnum = 0; argnum < argcount; argnum++)
	  {
	    if (!NILP (varies[argnum]))
	      visargs[argnum] = list1 (varies[argnum]);
	    else
	      visargs[argnum] = quotify_arg (args[argnum]);
	  }
	Vcommand_history = Fcons (Fcons (args[-1], Flist (argcount, visargs)),
				  Vcommand_history);
      }

    specbind (Qcommand_debug_status, Qnil);
    fun = Ffuncall (argcount + 1, args - 1);
    UNGCPRO;
    if (set_zmacs_region_stays)
      zmacs_region_stays = 1;
    return (unbind_to (speccount, fun));
  }
}

DEFUN ("prefix-numeric-value", Fprefix_numeric_value, Sprefix_numeric_value,
  1, 1, 0,
  "Return numeric meaning of raw prefix argument ARG.\n\
A raw prefix argument is what you get from `(interactive \"P\")'.\n\
Its numeric meaning is what you would get from `(interactive \"p\")'.")
  (raw)
     Lisp_Object raw;
{
  int val;

  if (NILP (raw))
    val = 1;
  else if (EQ (raw, Qminus))
    val = -1;
  else if (INTP (raw))
    val = XINT (raw);
  else if (CONSP (raw) && INTP (XCAR (raw)))
    val = XINT (XCAR (raw));
  else
    val = 1;

  return (make_number (val));

}

void
syms_of_callint (void)
{
  defsymbol (&Qcall_interactively, "call-interactively");
  defsymbol (&Qread_from_minibuffer, "read-from-minibuffer");
  defsymbol (&Qcompleting_read, "completing-read");
  defsymbol (&Qread_file_name, "read-file-name");
  defsymbol (&Qread_directory_name, "read-directory-name");
  defsymbol (&Qread_string, "read-string");
  defsymbol (&Qread_buffer, "read-buffer");
  defsymbol (&Qread_variable, "read-variable");
  defsymbol (&Qread_function, "read-function");
  defsymbol (&Qread_command, "read-command");
  defsymbol (&Qread_number, "read-number");
  defsymbol (&Qread_expression, "read-expression");
#ifdef MULE
  defsymbol (&Qread_coding_system, "read-coding-system");
  defsymbol (&Qread_non_nil_coding_system, "read-non-nil-coding-system");
#endif
  defsymbol (&Qevents_to_keys, "events-to-keys");
  defsymbol (&Qcommand_debug_status, "command-debug-status");
  defsymbol (&Qenable_recursive_minibuffers, "enable-recursive-minibuffers");
  defsymbol (&Qcommand_debug_status, "command-debug-status");
  defsymbol (&Quser_variable_p, "user-variable-p");
  defsymbol (&Qcurrent_prefix_arg, "current-prefix-arg");

  defsubr (&Sinteractive);
  defsubr (&Scall_interactively);
  defsubr (&Sprefix_numeric_value);
}

void
vars_of_callint (void)
{
  DEFVAR_LISP ("prefix-arg", &Vprefix_arg,
    "The value of the prefix argument for the next editing command.\n\
It may be a number, or the symbol `-' for just a minus sign as arg,\n\
or a list whose car is a number for just one or more C-U's\n\
or nil if no argument has been specified.\n\
\n\
You cannot examine this variable to find the argument for this command\n\
since it has been set to nil by the time you can look.\n\
Instead, you should use the variable `current-prefix-arg', although\n\
normally commands can get this prefix argument with (interactive \"P\").");
  Vprefix_arg = Qnil;

  DEFVAR_LISP ("current-prefix-arg", &Vcurrent_prefix_arg,
    "The value of the prefix argument for this editing command.\n\
It may be a number, or the symbol `-' for just a minus sign as arg,\n\
or a list whose car is a number for just one or more C-U's\n\
or nil if no argument has been specified.\n\
This is what `(interactive \"P\")' returns.");
  Vcurrent_prefix_arg = Qnil;

  DEFVAR_LISP ("current-mouse-event", &Vcurrent_mouse_event,
    "The mouse-button event which invoked this command, or nil.\n\
This is what `(interactive \"e\")' returns.");
  Vcurrent_mouse_event = Qnil;

  DEFVAR_LISP ("command-history", &Vcommand_history,
    "List of recent commands that read arguments from terminal.\n\
Each command is represented as a form to evaluate.");
  Vcommand_history = Qnil;

  DEFVAR_LISP ("command-debug-status", &Vcommand_debug_status,
    "Debugging status of current interactive command.\n\
Bound each time `call-interactively' is called;\n\
may be set by the debugger as a reminder for itself.");
  Vcommand_debug_status = Qnil;
}
