diff options
Diffstat (limited to 'src/keyboard.c')
-rw-r--r-- | src/keyboard.c | 2288 |
1 files changed, 2288 insertions, 0 deletions
diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 00000000000..a27354d0454 --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,2288 @@ +/* Keyboard input; editor command loop. + Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs 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 1, or (at your option) +any later version. + +GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/*** For version 19, can simplify this by making interrupt_input 1 on VMS. */ + +/* This must precede sys/signal.h on certain machines. */ +#include <sys/types.h> +/* Allow config.h to undefine symbols found here. */ +#include <signal.h> + +#include "config.h" +#include <stdio.h> +#undef NULL +#include "termchar.h" +#include "termopts.h" +#include "termhooks.h" +#include "lisp.h" +#include "macros.h" +#include "window.h" +#include "commands.h" +#include "buffer.h" +#include <setjmp.h> +#include <errno.h> + +extern int errno; + +/* Get FIONREAD, if it is available. */ +#ifdef USG +#include <termio.h> +#include <fcntl.h> +#else /* not USG */ +#ifndef VMS +#include <sys/ioctl.h> +#endif /* not VMS */ +#endif /* not USG */ + +#include "emacssignal.h" + +/* Allow m- file to inhibit use of FIONREAD. */ +#ifdef BROKEN_FIONREAD +#undef FIONREAD +#endif + +/* Make all keyboard buffers much bigger when using X windows. */ +#ifdef HAVE_X_WINDOWS +#define BUFFER_SIZE_FACTOR 16 +#else +#define BUFFER_SIZE_FACTOR 1 +#endif + +/* Following definition copied from eval.c */ + +struct backtrace + { + struct backtrace *next; + Lisp_Object *function; + Lisp_Object *args; /* Points to vector of args. */ + int nargs; /* length of vector */ + /* if nargs is UNEVALLED, args points to slot holding list of unevalled args */ + char evalargs; + }; + +/* Non-nil disable property on a command means + do not execute it; call disabled-command-hook's value instead. */ +Lisp_Object Qdisabled, Vdisabled_command_hook; + +int recent_keys_index; /* Index for storing next element into recent_keys */ +int total_keys; /* Total number of elements stored into recent_keys */ +char recent_keys[100]; /* Holds last 100 keystrokes */ + +/* Buffer holding the key that invoked the current command. */ +unsigned char *this_command_keys; +int this_command_key_count; /* Size in use. */ +int this_command_keys_size; /* Size allocated. */ + +extern struct backtrace *backtrace_list; + +static jmp_buf getcjmp; /* for longjmp to where kbd input is being done. */ + +int waiting_for_input; /* True while doing kbd input */ + +/* True while displaying for echoing. Delays C-g throwing. */ +static int echoing; + +int immediate_quit; /* Nonzero means C-G should cause immediate error-signal. */ + +int help_char; /* Character to recognize as the help char. */ + +Lisp_Object Vhelp_form; /* Form to execute when help char is typed. */ + +/* Character that causes a quit. Normally C-g. */ + +int quit_char; + +extern Lisp_Object global_map; + +/* Current depth in recursive edits. */ + +int command_loop_level; + +/* Last input character read as a command. */ + +int last_command_char; + +/* Last input character read for any purpose. */ + +int last_input_char; + +/* If not -1, a character to be read as the next command input */ + +int unread_command_char; + +/* Char to use as prefix when a meta character is typed in. + This is bound on entry to minibuffer in case Esc is changed there. */ + +int meta_prefix_char; + +/* Total number of times read_command_char has returned. */ + +int num_input_chars; + +/* Auto-save automatically when this many characters have been typed + since the last time. */ + +static int auto_save_interval; + +/* Value of num_input_chars as of last auto save. */ + +int last_auto_save; + +/* Last command executed by the editor command loop, not counting + commands that set the prefix argument. */ + +Lisp_Object last_command; + +/* The command being executed by the command loop. + Commands may set this, and the value set will be copied into last_command + instead of the actual command. */ +Lisp_Object this_command; + +Lisp_Object Qself_insert_command; +Lisp_Object Qforward_char; +Lisp_Object Qbackward_char; + +/* read_key_sequence stores here the command definition of the + key sequence that it reads. */ +Lisp_Object read_key_sequence_cmd; + +/* Form to evaluate (if non-nil) when Emacs is started */ +Lisp_Object Vtop_level; + +/* User-supplied string to translate input characters through */ +Lisp_Object Vkeyboard_translate_table; + +FILE *dribble; /* File in which we write all commands we read */ + +/* Nonzero if input is available */ +int input_pending; + +/* Nonzero if should obey 0200 bit in input chars as "Meta" */ +int meta_key; + +extern char *pending_malloc_warning; + +/* Buffer for pre-read keyboard input */ +unsigned char kbd_buffer [256 * BUFFER_SIZE_FACTOR]; + +/* Number of characters available in kbd_buffer. */ +int kbd_count; + +/* Pointer to next available character in kbd_buffer. */ +unsigned char *kbd_ptr; + +/* Address (if not 0) of word to zero out + if a SIGIO interrupt happens */ +long *input_available_clear_word; + +/* Nonzero means use SIGIO interrupts; zero means use CBREAK mode. + Default is 1 if INTERRUPT_INPUT is defined. */ + +int interrupt_input; + +/* Nonzero while interrupts are temporarily deferred during redisplay. */ + +int interrupts_deferred; + +/* nonzero means use ^S/^Q for flow control. */ + +int flow_control; + +#ifndef BSD4_1 +#define sigfree() sigsetmask (SIGEMPTYMASK) +#define sigholdx(sig) sigsetmask (sigmask (sig)) +#define sigblockx(sig) sigblock (sigmask (sig)) +#define sigunblockx(sig) sigblock (SIGEMPTYMASK) +#define sigpausex(sig) sigpause (0) +#endif /* not BSD4_1 */ + +#ifdef BSD4_1 +#define SIGIO SIGTINT +/* sigfree and sigholdx are in sysdep.c */ +#define sigblockx(sig) sighold (sig) +#define sigunblockx(sig) sigrelse (sig) +#define sigpausex(sig) sigpause (sig) +#endif /* BSD4_1 */ + +/* We are unable to use interrupts if FIONREAD is not available, + so flush SIGIO so we won't try. */ +#ifndef FIONREAD +#ifdef SIGIO +#undef SIGIO +#endif +#endif + +/* If we support X Windows, and won't get an interrupt when input + arrives from the server, poll periodically so we can detect C-g. */ +#ifdef HAVE_X_WINDOWS +#ifndef SIGIO +#define POLL_FOR_INPUT +#endif +#endif + +/* Function for init_keyboard to call with no args (if nonzero). */ +void (*keyboard_init_hook) (); + +static void read_avail_input (); +static void get_input_pending (); + +/* Non-zero tells input_available_signal to call read_socket_hook + even if FIONREAD returns zero. */ +static int force_input; + +static int echo_keystrokes; /* > 0 if we are to echo keystrokes */ + +/* Nonzero means echo each character as typed. */ +static int immediate_echo; + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + +static char echobuf[100]; +static char *echoptr; + +/* Install the string STR as the beginning of the string of echoing, + so that it serves as a prompt for the next character. + Also start echoing. */ + +echo_prompt (str) + char *str; +{ + int len = strlen (str); + if (len > sizeof echobuf - 4) + len = sizeof echobuf - 4; + bcopy (str, echobuf, len + 1); + echoptr = echobuf + len; + + echo (); +} + +/* Add the character C to the echo string, + if echoing is going on. */ + +echo_char (c) + int c; +{ + extern char *push_key_description (); + + if (immediate_echo) + { + char *ptr = echoptr; + + if (ptr - echobuf > sizeof echobuf - 6) + return; + + if (echoptr != echobuf) + *ptr++ = ' '; + + ptr = push_key_description (c, ptr); + if (echoptr == echobuf && c == help_char) + { + strcpy (ptr, " (Type ? for further options)"); + ptr += strlen (ptr); + } + + *ptr = 0; + echoptr = ptr; + + echo (); + } +} + +/* Temporarily add a dash to the end of the echo string, + so that it serves as a mini-prompt for the very next character. */ + +echo_dash () +{ + if (!immediate_echo && echoptr == echobuf) + return; + + /* Put a dash at the end of the buffer temporarily, + but make it go away when the next character is added. */ + echoptr[0] = '-'; + echoptr[1] = 0; + + echo (); +} + +/* Display the current echo string, and begin echoing if not already + doing so. */ + +echo () +{ + if (!immediate_echo) + { + int i; + immediate_echo = 1; + + for (i = 0; i < this_command_key_count; i++) + echo_char (this_command_keys[i]); + echo_dash (); + } + + echoing = 1; + message1 (echobuf); + echoing = 0; + + if (waiting_for_input && !NULL (Vquit_flag)) + quit_throw_to_read_command_char (); +} + +/* Turn off echoing, for the start of a new command. */ + +cancel_echoing () +{ + immediate_echo = 0; + echoptr = echobuf; +} + +/* When an auto-save happens, record the "time", and don't do again soon. */ +record_auto_save () +{ + last_auto_save = num_input_chars; +} + +Lisp_Object recursive_edit_unwind (), command_loop (); + +DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "", + "Invoke the editor command loop recursively.\n\ +Do (throw 'exit nil) within the command loop to make this function return,\n\ +or (throw 'exit t) to make this function signal an error.\n\ +This function is called by the editor initialization\n\ +to begin editing.") + () +{ + int count = specpdl_ptr - specpdl; + + command_loop_level++; + update_mode_lines = 1; + + record_unwind_protect (recursive_edit_unwind, + (current_buffer != XBUFFER (XWINDOW (selected_window)->buffer) + ? Fcurrent_buffer () + : Qnil)); + + recursive_edit_1 (); + + unbind_to (count); + return Qnil; +} + +Lisp_Object +recursive_edit_1 () +{ + int count = specpdl_ptr - specpdl; + Lisp_Object val; + + if (command_loop_level > 0) + { + specbind (Qstandard_output, Qt); + specbind (Qstandard_input, Qt); + } + + val = command_loop (); + if (EQ (val, Qt)) + Fsignal (Qquit, Qnil); + + unbind_to (count); + return Qnil; +} + +Lisp_Object +recursive_edit_unwind (buffer) + Lisp_Object buffer; +{ + if (!NULL (buffer)) + Fset_buffer (buffer); + command_loop_level--; + update_mode_lines = 1; + return Qnil; +} + +Lisp_Object +cmd_error (data) + Lisp_Object data; +{ + Lisp_Object errmsg, tail, errname, file_error; + struct gcpro gcpro1; + int i; + + Vquit_flag = Qnil; + Vinhibit_quit = Qt; + Vstandard_output = Qt; + Vstandard_input = Qt; + Vexecuting_macro = Qnil; + echo_area_contents = 0; + + Fdiscard_input (); + bell (); + + errname = Fcar (data); + + if (EQ (errname, Qerror)) + { + data = Fcdr (data); + if (!CONSP (data)) data = Qnil; + errmsg = Fcar (data); + file_error = Qnil; + } + else + { + errmsg = Fget (errname, Qerror_message); + file_error = Fmemq (Qfile_error, + Fget (errname, Qerror_conditions)); + } + + /* Print an error message including the data items. + This is done by printing it into a scratch buffer + and then making a copy of the text in the buffer. */ + + if (!CONSP (data)) data = Qnil; + tail = Fcdr (data); + GCPRO1 (tail); + + /* For file-error, make error message by concatenating + all the data items. They are all strings. */ + if (!NULL (file_error)) + errmsg = XCONS (tail)->car, tail = XCONS (tail)->cdr; + + if (XTYPE (errmsg) == Lisp_String) + Fprinc (errmsg, Qt); + else + write_string_1 ("peculiar error", -1, Qt); + + for (i = 0; CONSP (tail); tail = Fcdr (tail), i++) + { + write_string_1 (i ? ", " : ": ", 2, Qt); + if (!NULL (file_error)) + Fprinc (Fcar (tail), Qt); + else + Fprin1 (Fcar (tail), Qt); + } + UNGCPRO; + + /* In -batch mode, force out the error message and newlines after it + and then die. */ + if (noninteractive) + { + message (""); + Fkill_emacs (make_number (-1)); + } + + Vquit_flag = Qnil; + + Vinhibit_quit = Qnil; + return make_number (0); +} + +Lisp_Object command_loop_1 (); +Lisp_Object command_loop_2 (); +Lisp_Object cmd_error (); +Lisp_Object top_level_1 (); + +/* Entry to editor-command-loop. + This level has the catches for exiting/returning to editor command loop. + It returns nil to exit recursive edit, t to abort it. */ + +Lisp_Object +command_loop () +{ + if (command_loop_level > 0 || minibuf_level > 0) + { + return internal_catch (Qexit, command_loop_2, Qnil); + } + else + while (1) + { + internal_catch (Qtop_level, top_level_1, Qnil); + internal_catch (Qtop_level, command_loop_2, Qnil); + /* End of file in -batch run causes exit here. */ + if (noninteractive) + Fkill_emacs (Qt); + } +} + +/* Here we catch errors in execution of commands within the + editing loop, and reenter the editing loop. + When there is an error, cmd_error runs and returns a non-nil + value to us. A value of nil means that cmd_loop_1 itself + returned due to end of file (or end of kbd macro). */ + +Lisp_Object +command_loop_2 () +{ + register Lisp_Object val; + do + val = internal_condition_case (command_loop_1, Qerror, cmd_error); + while (!NULL (val)); + return Qnil; +} + +Lisp_Object +top_level_2 () +{ + return Feval (Vtop_level); +} + +Lisp_Object +top_level_1 () +{ + /* On entry to the outer level, run the startup file */ + if (!NULL (Vtop_level)) + internal_condition_case (top_level_2, Qerror, cmd_error); + else if (!NULL (Vpurify_flag)) + message ("Bare impure Emacs (standard Lisp code not loaded)"); + else + message ("Bare Emacs (standard Lisp code not loaded)"); + return Qnil; +} + +DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "", + "Exit all recursive editing levels.") + () +{ + Fthrow (Qtop_level, Qnil); +} + +DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "", + "Exit from the innermost recursive edit or minibuffer.") + () +{ + if (command_loop_level > 0 || minibuf_level > 0) + Fthrow (Qexit, Qnil); + error ("No recursive edit is in progress"); +} + +DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "", + "Abort the command that requested this recursive edit or minibuffer input.") + () +{ + if (command_loop_level > 0 || minibuf_level > 0) + Fthrow (Qexit, Qt); + error ("No recursive edit is in progress"); +} + +/* This is the actual command reading loop, + sans error-handling encapsulation */ + +Lisp_Object Fcommand_execute (); + +Lisp_Object +command_loop_1 () +{ + Lisp_Object cmd; + int lose; + int nonundocount; + char keybuf[30]; + int i; + int no_redisplay; + int no_direct; + + Vprefix_arg = Qnil; + waiting_for_input = 0; + cancel_echoing (); + + /* Don't clear out last_command at the beginning of a macro. */ + if (NULL (Vexecuting_macro) + || XTYPE (Vexecuting_macro) != Lisp_String) + last_command = Qt; + nonundocount = 0; + no_redisplay = 0; + this_command_key_count = 0; + + while (1) + { + /* Install chars successfully executed in kbd macro */ + if (defining_kbd_macro && NULL (Vprefix_arg)) + finalize_kbd_macro_chars (); + + /* Make sure current window's buffer is selected. */ + + if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer) + set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer)); + + /* Display any malloc warning that just came out. + Use while because displaying one warning can cause another. */ + while (pending_malloc_warning) + display_malloc_warning (); + + no_direct = 0; + + /* If minibuffer on and echo area in use, + wait 2 sec and redraw minibufer. */ + + if (minibuf_level && echo_area_contents) + { + int count = specpdl_ptr - specpdl; + specbind (Qinhibit_quit, Qt); + Fsit_for (make_number (2), Qnil); + unbind_to (count); + + echo_area_contents = 0; + no_direct = 1; + if (!NULL (Vquit_flag)) + { + Vquit_flag = Qnil; + unread_command_char = quit_char; + } + } + + i = 0; +#if 0 + /* If prev. command was directly displayed, we don't need + redisplay. Try shortcut for reading single-char key sequence. */ + if (no_redisplay) + i = fast_read_one_key (keybuf); +#endif /* 0 */ + /* Shortcut not applicable or found a prefix key. + Take full precautions and read key sequence the hard way. */ + if (i == 0) + { +#ifdef C_ALLOCA + alloca (0); /* Cause a garbage collection now */ + /* Since we can free the most stuff here. */ +#endif /* C_ALLOCA */ + + /* Read next key sequence; i gets its length. */ + + i = read_key_sequence (keybuf, sizeof keybuf, 0, + no_redisplay && buffer_shared <= 1); + } + + /* Now we have read a key sequence of length I, + or else I is 0 and we found end of file. */ + + if (i == 0) /* End of file -- happens only in */ + return Qnil; /* a kbd macro, at the end */ + + last_command_char = keybuf[i - 1]; + + cmd = read_key_sequence_cmd; + if (!NULL (Vexecuting_macro)) + { + if (!NULL (Vquit_flag)) + { + Vexecuting_macro = Qt; + QUIT; /* Make some noise. */ + /* Will return since macro now empty. */ + } + } + + /* Do redisplay processing after this command except in special + cases identified below that set no_redisplay to 1. */ + no_redisplay = 0; + + /* Execute the command. */ + + if (NULL (cmd)) + { + /* nil means key is undefined. */ + bell (); + defining_kbd_macro = 0; + update_mode_lines++; + Vprefix_arg = Qnil; + } + else + { + this_command = cmd; + if (NULL (Vprefix_arg) && ! no_direct) + { + if (EQ (cmd, Qforward_char) && point < ZV) + { + lose = FETCH_CHAR (point); + SET_PT (point + 1); + if (lose >= ' ' && lose < 0177 + && (XFASTINT (XWINDOW (selected_window)->last_modified) + >= MODIFF) + && (XFASTINT (XWINDOW (selected_window)->last_point) + == point) + && !windows_or_buffers_changed + && EQ (current_buffer->selective_display, Qnil) + && !detect_input_pending () + && NULL (Vexecuting_macro)) + no_redisplay = direct_output_forward_char (1); + goto directly_done; + } + else if (EQ (cmd, Qbackward_char) && point > BEGV) + { + SET_PT (point - 1); + lose = FETCH_CHAR (point); + if (lose >= ' ' && lose < 0177 + && (XFASTINT (XWINDOW (selected_window)->last_modified) + >= MODIFF) + && (XFASTINT (XWINDOW (selected_window)->last_point) + == point) + && !windows_or_buffers_changed + && EQ (current_buffer->selective_display, Qnil) + && !detect_input_pending () + && NULL (Vexecuting_macro)) + no_redisplay = direct_output_forward_char (-1); + goto directly_done; + } + else if (EQ (cmd, Qself_insert_command)) + { + if (NULL (Vexecuting_macro) && + !EQ (minibuf_window, selected_window)) + { + if (!nonundocount || nonundocount >= 20) + { + Fundo_boundary (); + nonundocount = 0; + } + nonundocount++; + } + lose = (XFASTINT (XWINDOW (selected_window)->last_modified) + < MODIFF) + || (XFASTINT (XWINDOW (selected_window)->last_point) + != point) + || MODIFF <= current_buffer->save_modified + || windows_or_buffers_changed + || !EQ (current_buffer->selective_display, Qnil) + || detect_input_pending () + || !NULL (Vexecuting_macro); + if (self_insert_internal (last_command_char, 0)) + { + lose = 1; + nonundocount = 0; + } + if (!lose + && (point == ZV || FETCH_CHAR (point) == '\n') + && last_command_char >= ' ' + && last_command_char < 0177) + no_redisplay + = direct_output_for_insert (last_command_char); + goto directly_done; + } + } + + /* Here for a command that isn't executed directly */ + + nonundocount = 0; + if (NULL (Vprefix_arg)) + Fundo_boundary (); + Fcommand_execute (cmd, Qnil); + } + /* This label logically belongs inside the above group, + but moving it is said to avoid a compiler bug on SCO V.3.2v2. */ + directly_done: ; + + if (NULL (Vprefix_arg)) + { + last_command = this_command; + this_command_key_count = 0; + cancel_echoing (); + } + } +} + +/* Input of single characters from keyboard */ + +Lisp_Object print_help (); + +int echo_flag; +int echo_now; + +/* Alarm interrupt calls this and requests echoing at earliest safe time. */ +request_echo () +{ + int old_errno = errno; + + /* Note: no need to reestablish handler on USG systems + because it is established, if approriate, each time an alarm is requested. */ +#ifdef subprocesses +#ifdef BSD4_1 + extern int select_alarmed; + if (select_alarmed == 0) + { + select_alarmed = 1; + sigrelse (SIGALRM); + return; + } +#endif +#endif + +#ifdef BSD4_1 + sigisheld (SIGALRM); +#endif + + if (echo_now) + echo (); + else + echo_flag = 1; + +#ifdef BSD4_1 + sigunhold (SIGALRM); +#endif + + errno = old_errno; +} + +/* Nonzero means polling for input is temporarily suppresed. */ +int poll_suppress_count; + +/* Number of seconds between polling for input. */ +int polling_period; + +#ifdef POLL_FOR_INPUT +int polling_for_input; + +/* Handle an alarm once each second and read pending input + so as to handle a C-g if it comces in. */ + +input_poll_signal () +{ + int junk; + + if (!waiting_for_input) + read_avail_input (&junk); + signal (SIGALRM, input_poll_signal); + alarm (polling_period); +} + +#endif + +/* Begin signals to poll for input, if they are appropriate. + This function is called unconditionally from various places. */ + +start_polling () +{ +#ifdef POLL_FOR_INPUT + if (read_socket_hook) + { + poll_suppress_count--; + if (poll_suppress_count == 0) + { + signal (SIGALRM, input_poll_signal); + polling_for_input = 1; + alarm (polling_period); + } + } +#endif +} + +/* Turn off polling. */ + +stop_polling () +{ +#ifdef POLL_FOR_INPUT + if (read_socket_hook) + { + if (poll_suppress_count == 0) + { + polling_for_input = 0; + alarm (0); + } + poll_suppress_count++; + } +#endif +} + +/* read a character from the keyboard; call the redisplay if needed */ +/* commandflag 0 means do not do auto-saving, but do do redisplay. + -1 means do not do redisplay, but do do autosaving. + 1 means do both. */ + +read_command_char (commandflag) + int commandflag; +{ + register int c; + int alarmtime; + int count; + Lisp_Object tem; + jmp_buf save_jump; + extern request_echo (); + + if (unread_command_char >= 0) + { + c = unread_command_char; + unread_command_char = -1; + if (this_command_key_count == 0) + goto reread_first; + goto reread; + } + + if (!NULL (Vexecuting_macro)) + { + if (XTYPE (Vexecuting_macro) != Lisp_String + || XSTRING (Vexecuting_macro)->size <= executing_macro_index) + return -1; + QUIT; + c = XSTRING (Vexecuting_macro)->data[executing_macro_index++]; + goto from_macro; + } + + /* Save outer setjmp data, in case called recursively. */ + bcopy (getcjmp, save_jump, sizeof getcjmp); + + stop_polling (); + + if (commandflag >= 0 && !detect_input_pending ()) + redisplay (); + + if (commandflag != 0 + && auto_save_interval > 0 + && num_input_chars - last_auto_save > max (auto_save_interval, 20) + && !detect_input_pending ()) + Fdo_auto_save (Qnil); + + if (_setjmp (getcjmp)) + { + c = quit_char; + waiting_for_input = 0; + input_available_clear_word = 0; + + goto non_reread; + } + + /* Message turns off echoing unless more keystrokes turn it on again. */ + if (echo_area_contents && *echo_area_contents && echo_area_contents != echobuf) + cancel_echoing (); + else + /* If already echoing, continue, and prompt. */ + echo_dash (); + + /* If in middle of key sequence and minibuffer not active, + start echoing if enough time elapses. */ + if (minibuf_level == 0 && !immediate_echo && this_command_key_count > 0 + && echo_keystrokes > 0 + && (echo_area_contents == 0 || *echo_area_contents == 0)) + { + /* Else start echoing if user waits more than `alarmtime' seconds. */ + /* This interrupt either calls echo right away + or sets echo_flag, which causes echo to be called + by set_waiting_for_input's next invocation. */ + signal (SIGALRM, request_echo); + echo_flag = 0; + echo_now = 0; + alarmtime = echo_keystrokes; + alarm ((unsigned) alarmtime); + } + + c = kbd_buffer_read_command_char (); + + /* Terminate Emacs in batch mode if at eof. */ + if (noninteractive && c < 0) + Fkill_emacs (make_number (1)); + + non_reread: + + bcopy (save_jump, getcjmp, sizeof getcjmp); + + /* Cancel alarm if it was set and has not already gone off. */ + if (alarmtime > 0) alarm (0); + + echo_area_contents = 0; + + if (c < 0) return -1; + + c &= meta_key ? 0377 : 0177; + + if (XTYPE (Vkeyboard_translate_table) == Lisp_String + && XSTRING (Vkeyboard_translate_table)->size > c) + c = XSTRING (Vkeyboard_translate_table)->data[c]; + + total_keys++; + recent_keys[recent_keys_index] = c; + recent_keys_index = (recent_keys_index + 1) % sizeof recent_keys; + + if (dribble) + { + putc (c, dribble); + fflush (dribble); + } + + store_kbd_macro_char (c); + + start_polling (); + + from_macro: + reread_first: /* Rereading a char and it is the first in a command. */ + + echo_char (c); + + /* Record this character as part of the current key. */ + if (this_command_key_count == this_command_keys_size) + { + this_command_keys_size *= 2; + this_command_keys + = (unsigned char *) xrealloc (this_command_keys, + this_command_keys_size); + } + this_command_keys[this_command_key_count++] = c; + + /* Rereading in the middle of a command. */ + reread: + + last_input_char = c; + + num_input_chars++; + + /* Process the help character specially if enabled */ + if (c == help_char && !NULL (Vhelp_form)) + { + count = specpdl_ptr - specpdl; + + record_unwind_protect (Fset_window_configuration, + Fcurrent_window_configuration ()); + + tem = Feval (Vhelp_form); + if (XTYPE (tem) == Lisp_String) + internal_with_output_to_temp_buffer ("*Help*", print_help, tem); + + cancel_echoing (); + c = read_command_char (0); + /* Remove the help from the screen */ + unbind_to (count); + redisplay (); + if (c == 040) + { + cancel_echoing (); + c = read_command_char (0); + } + } + + return c; +} + +Lisp_Object +print_help (object) + Lisp_Object object; +{ + Fprinc (object, Qnil); + return Qnil; +} + +/* Low level keyboard input. + Read characters into kbd_buffer + from which they are obtained by kbd_buffer_read_command_char. */ + +/* Set this for debugging, to have a way to get out */ +int stop_character; + +/* Store a character obtained at interrupt level into kbd_buffer, fifo */ +kbd_buffer_store_char (c) + register int c; +{ + c &= 0377; + + if (c == quit_char + || ((c == (0200 | quit_char)) && !meta_key)) + { + interrupt_signal (); + return; + } + + if (c && c == stop_character) + { + sys_suspend (); + return; + } + + if (kbd_ptr != kbd_buffer) + { + bcopy (kbd_ptr, kbd_buffer, kbd_count); + kbd_ptr = kbd_buffer; + } + + if (kbd_count < sizeof kbd_buffer) + { + kbd_buffer[kbd_count++] = c; + } +} + +kbd_buffer_read_command_char () +{ + register int c; + + if (noninteractive) + { + c = getchar (); + return c; + } + + /* Either ordinary input buffer or C-g buffered means we can return. */ + while (!kbd_count) + { + if (!NULL (Vquit_flag)) + quit_throw_to_read_command_char (); + + /* One way or another, wait until input is available; then, if + interrupt handlers have not read it, read it now. */ + +#ifdef VMS + wait_for_kbd_input (); +#else +/* Note SIGIO has been undef'd if FIONREAD is missing. */ +#ifdef SIGIO + gobble_input (); +#endif /* SIGIO */ + if (!kbd_count) + { +#ifdef subprocesses + wait_reading_process_input (0, -1, 1); +#else +/* Note SIGIO has been undef'd if FIONREAD is missing. */ +#ifdef SIGIO + if (interrupt_input) + { + sigblockx (SIGIO); + set_waiting_for_input (0); + while (!kbd_count) + sigpausex (SIGIO); + clear_waiting_for_input (); + sigunblockx (SIGIO); + } +#else + interrupt_input = 0; +#endif /* not SIGIO */ +#endif /* subprocesses */ + + if (!interrupt_input && !kbd_count) + { + read_avail_input (0); + } + } +#endif /* not VMS */ + } + + input_pending = --kbd_count > 0; + c = *kbd_ptr; /* *kbd_ptr++ would have a timing error. */ + kbd_ptr++; /* See kbd_buffer_store_char. */ + return (c & (meta_key ? 0377 : 0177)); /* Clean up if sign was extended. */ +} + +/* Force an attempt to read input regardless of what FIONREAD says. */ + +force_input_read () +{ + force_input = 1; + detect_input_pending (); + force_input = 0; +} + +/* Store into *addr the number of terminal input chars available. + Equivalent to ioctl (0, FIONREAD, addr) but works + even if FIONREAD does not exist. */ + +static void +get_input_pending (addr) + int *addr; +{ +#ifdef VMS + /* On VMS, we always have something in the buffer + if any input is available. */ + /*** It might be simpler to make interrupt_input 1 on VMS ***/ + *addr = kbd_count | !NULL (Vquit_flag); +#else + /* First of all, have we already counted some input? */ + *addr = kbd_count | !NULL (Vquit_flag); + /* If input is being read as it arrives, and we have none, there is none. */ + if (*addr > 0 || (interrupt_input && ! interrupts_deferred && ! force_input)) + return; +#ifdef FIONREAD + if (! force_input) + { + /* If we can count the input without reading it, do so. */ + if (ioctl (0, FIONREAD, addr) < 0) + *addr = 0; + if (*addr == 0 || read_socket_hook == 0) + return; + /* If the input consists of window-events, not all of them + are necessarily kbd chars. So process all the input + and see how many kbd chars we got. */ + } +#endif +#ifdef SIGIO + { + /* It seems there is a timing error such that a SIGIO can be handled here + and cause kbd_count to become nonzero even though raising of SIGIO + has already been turned off. */ + SIGMASKTYPE mask = sigblock (sigmask (SIGIO)); + if (kbd_count == 0) + read_avail_input (*addr); + sigsetmask (mask); + } +#else + /* If we can't count the input, read it (if any) and see what we got. */ + read_avail_input (*addr); +#endif + *addr = kbd_count | !NULL (Vquit_flag); +#endif +} + +/* Read pending any input out of the system and into Emacs. */ + +/* This function is temporary in Emacs 18. It is used only + with X windows. X windows always turns on interrupt input + if possible, so this function has nothing to do except + on systems that don't have SIGIO. And they also don't have FIONREAD. */ +void +consume_available_input () +{ +#ifdef SIGIO + if (!interrupt_input || interrupts_deferred) +#endif + read_avail_input (0); +} + +/* Read any terminal input already buffered up by the system + into the kbd_buffer, assuming the buffer is currently empty. + Never waits. + + If NREAD is nonzero, assume it contains # chars of raw data waiting. + If it is zero, we determine that datum. + + Input gets into the kbd_buffer either through this function + (at main program level) or at interrupt level if input + is interrupt-driven. */ + +static void +read_avail_input (nread) + int nread; +{ + /* This function is not used on VMS. */ +#ifndef VMS + char buf[256 * BUFFER_SIZE_FACTOR]; + register int i; + +#ifdef FIONREAD + if (! force_input) + { + if (nread == 0) + get_input_pending (&nread); + if (nread == 0) + return; + } + if (nread > sizeof buf) + nread = sizeof buf; + + /* Read what is waiting. */ + if (read_socket_hook) + nread = (*read_socket_hook) (0, buf, nread); + else + nread = read (0, buf, nread); + +#else /* no FIONREAD */ +#ifdef USG +#ifdef SYSV_STREAMS + /* When talking to Xwindows using streams, something gets screwed up + if Emacs alters this flag in the descriptor. */ + if (!read_socket_hook) +#endif + fcntl (fileno (stdin), F_SETFL, O_NDELAY); + if (read_socket_hook) + { + nread = (*read_socket_hook) (0, buf, sizeof buf); + } + else + { + nread = read (fileno (stdin), buf, sizeof buf); + } +#ifdef AIX + /* The kernel sometimes fails to deliver SIGHUP for ptys. + This looks incorrect, but it isn't, because _BSD causes + O_NDELAY to be defined in fcntl.h as O_NONBLOCK, + and that causes a value other than 0 when there is no input. */ + if (nread == 0) + kill (SIGHUP, 0); +#endif +#ifdef EBADSLT + if (nread == -1 && (errno == EAGAIN || errno == EBADSLT)) +#else + if (nread == -1 && errno == EAGAIN) +#endif + nread = 0; +#ifdef SYSV_STREAMS + if (!read_socket_hook) +#endif + fcntl (fileno (stdin), F_SETFL, 0); +#else /* not USG */ + you lose +#endif /* not USG */ +#endif /* no FIONREAD */ + + /* Scan the chars for C-g and store them in kbd_buffer. */ + if (kbd_count == 0) + kbd_ptr = kbd_buffer; + + for (i = 0; i < nread; i++) + { + kbd_buffer_store_char (buf[i]); + /* Don't look at input that follows a C-g too closely. + This reduces lossage due to autorepeat on C-g. */ + if (buf[i] == quit_char) + break; + } +#endif /* not VMS */ +} + +#ifdef SIGIO /* for entire page */ +/* Note SIGIO has been undef'd if FIONREAD is missing. */ + +/* If using interrupt input and some input chars snuck into the + buffer before we enabled interrupts, fake an interrupt for them. */ + +gobble_input () +{ + int nread; + if (interrupt_input) + { + if (ioctl (0, FIONREAD, &nread) < 0) + nread = 0; + if (nread) + { + sigholdx (SIGIO); + input_available_signal (SIGIO); + sigfree (); + } + } +} + +input_available_signal (signo) + int signo; +{ + unsigned char buf[256 * BUFFER_SIZE_FACTOR]; + int nread; + register int i; + /* Must preserve main program's value of errno. */ + int old_errno = errno; +#ifdef BSD4_1 + extern int select_alarmed; +#endif + +#ifdef USG + /* USG systems forget handlers when they are used; + must reestablish each time */ + signal (signo, input_available_signal); +#endif /* USG */ + +#ifdef BSD4_1 + sigisheld (SIGIO); +#endif + + if (input_available_clear_word) + *input_available_clear_word = 0; + + while (1) + { + if (ioctl (0, FIONREAD, &nread) < 0) + /* Formerly simply exited the loop, but that sometimes led to + a failure of Emacs to terminate. + SIGHUP seems appropriate if we can't reach the terminal. */ + kill (getpid (), SIGHUP); + if (nread <= 0) + break; +#ifdef BSD4_1 + select_alarmed = 1; /* Force the select emulator back to life */ +#endif + if (read_socket_hook) + { + nread = (*read_socket_hook) (0, buf, sizeof buf); + if (!nread) + continue; + } + else + { + if (nread > sizeof buf) + nread = sizeof buf; + nread = read (0, buf, nread); + } + + for (i = 0; i < nread; i++) + { + kbd_buffer_store_char (buf[i]); + /* Don't look at input that follows a C-g too closely. + This reduces lossage due to autorepeat on C-g. */ + if (buf[i] == quit_char) + break; + } + } +#ifdef BSD4_1 + sigfree (); +#endif + errno = old_errno; +} +#endif /* SIGIO */ + +#if 0 +/* This is turned off because it didn't produce much speedup. */ + +/* Read a single-char key sequence. Do not redisplay. + Return 1 if successful, or 0 if what follows is not + a single-char key. (In that case, a char has been unread.) + This is used instead of read_key_sequence as an optimization + just after a direct-updating command is done, since at such + times we know that no redisplay is required. */ + +int +fast_read_one_key (keybuf) + char *keybuf; +{ + register Lisp_Object map; + register int c; + register Lisp_Object tem; + + keys_prompt = 0; + /* Read a character, and do not redisplay. */ + c = read_command_char (-1); + Vquit_flag = Qnil; + + /* Assume until further notice that we are unlucky + and will return zero, so this char will be + reread by read_key_sequence. */ + + unread_command_char = c; + + if (c < 0 || c >= 0200) + return 0; + + map = current_buffer->keymap; + if (!EQ (map, Qnil)) + { + tem = get_keyelt (access_keymap (map, c)); + if (!EQ (tem, Qnil)) + return 0; + } + + XSET (map, Lisp_Vector, global_map); + tem = !NULL (map) + ? get_keyelt (access_keymap (map, c)) + : Qnil; + + read_key_sequence_cmd = tem; + + /* trace symbols to their function definitions */ + + while (XTYPE (tem) == Lisp_Symbol && !NULL (tem) + && !EQ (tem, Qunbound)) + tem = XSYMBOL (tem)->function; + + /* Is the definition a prefix character? */ + + if (XTYPE (tem) == Lisp_Vector || + (CONSP (tem) && EQ (XCONS (tem)->car, Qkeymap))) + return 0; + + unread_command_char = -1; + keybuf[0] = c; + return 1; +} + +#endif /* 0 */ + +/* Read a sequence of keys that ends with a non prefix character, + and store them in KEYBUF, a buffer of size BUFSIZE. + Prompt with PROMPT. Echo starting immediately unless `prompt' is 0. + Return the length of the key sequence stored. + NODISPLAY nonzero means don't do redisplay before the first character + (just for speedup). */ + +int +read_key_sequence (keybuf, bufsize, prompt, nodisplay) + char *keybuf; + int bufsize; + unsigned char *prompt; + int nodisplay; +{ + register int i; + Lisp_Object nextlocal, nextglobal; + register int c, nextc; + Lisp_Object local, global; + + if (FROM_KBD) + { + if (prompt) + echo_prompt (prompt); + else if (cursor_in_echo_area) + echo_dash (); + } + + nextc = read_command_char (nodisplay ? -1 : !prompt); + nextlocal = current_buffer->keymap; + XSET (nextglobal, Lisp_Vector, global_map); + + i = 0; + while (!NULL (nextlocal) || !NULL (nextglobal)) + { + if (i == bufsize) + error ("key sequence too long"); + + if (nextc >= 0) + { + c = nextc; + nextc = -1; + } + else + c = read_command_char (!prompt); + Vquit_flag = Qnil; + nodisplay = 0; + + if (c < 0) + return 0; + if (c >= 0200) + { + nextc = c & 0177; + c = meta_prefix_char; + } + + keybuf[i] = c; + + global = !NULL (nextglobal) + ? get_keyelt (access_keymap (nextglobal, c)) + : Qnil; + + local = !NULL (nextlocal) + ? get_keyelt (access_keymap (nextlocal, c)) + : Qnil; + + /* If C is not defined in either keymap + and it is an uppercase letter, try corresponding lowercase. */ + + if (NULL (global) && NULL (local) && UPPERCASEP (c)) + { + global = !NULL (nextglobal) + ? get_keyelt (access_keymap (nextglobal, DOWNCASE (c))) + : Qnil; + + local = !NULL (nextlocal) + ? get_keyelt (access_keymap (nextlocal, DOWNCASE (c))) + : Qnil; + + /* If that has worked better that the original char, + downcase it permanently. */ + + if (!NULL (global) || !NULL (local)) + { + keybuf[i] = c = DOWNCASE (c); + } + } + + i++; + + nextlocal = Qnil; + nextglobal = Qnil; + + read_key_sequence_cmd = !NULL (local) ? local : global; + + /* trace symbols to their function definitions */ + + while (XTYPE (global) == Lisp_Symbol && !NULL (global) + && !EQ (global, Qunbound)) + global = XSYMBOL (global)->function; + while (XTYPE (local) == Lisp_Symbol && !NULL (local) + && !EQ (local, Qunbound)) + local = XSYMBOL (local)->function; + + /* Are the definitions prefix characters? */ + + if (XTYPE (local) == Lisp_Vector || + (CONSP (local) && EQ (XCONS (local)->car, Qkeymap)) + || + /* If nextc is set, we are processing a prefix char + that represents a meta-bit. + Let a global prefix definition override a local non-prefix. + This is for minibuffers that redefine Escape for completion. + A real Escape gets completion, but Meta bits get ESC-prefix. */ + ((NULL (local) || nextc >= 0) + && (XTYPE (global) == Lisp_Vector || + (CONSP (global) && EQ (XCONS (global)->car, Qkeymap))))) + { + if (XTYPE (local) == Lisp_Vector || + (CONSP (local) && EQ (XCONS (local)->car, Qkeymap))) + nextlocal = local; + else + nextlocal = Qnil; + + if (XTYPE (global) == Lisp_Vector || + (CONSP (global) && EQ (XCONS (global)->car, Qkeymap))) + nextglobal = global; + else + nextglobal = Qnil; + } + } + + return i; +} + +DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 1, 0, + "Read a sequence of keystrokes and return as a string.\n\ +The sequence is sufficient to specify a non-prefix command\n\ +starting from the current local and global keymaps.\n\ +A C-g typed while in this function is treated like\n\ +any other character, and quit-flag is not set.\n\ +One arg, PROMPT, a prompt string or nil, meaning do not prompt specially.") + (prompt) + Lisp_Object prompt; +{ + char keybuf[30]; + register int i; + + if (!NULL (prompt)) + CHECK_STRING (prompt, 0); + QUIT; + + this_command_key_count = 0; + i = read_key_sequence (keybuf, sizeof keybuf, + (NULL (prompt)) ? 0 : XSTRING (prompt)->data, + 0); + return make_string (keybuf, i); +} + +DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 2, 0, + "Execute CMD as an editor command.\n\ +CMD must be a symbol that satisfies the `commandp' predicate.\n\ +Optional second arg RECORD-FLAG non-nil\n\ +means unconditionally put this command in the command-history.\n\ +Otherwise, this is done only if an arg is read using the minibuffer.") + (cmd, record) + Lisp_Object cmd, record; +{ + register Lisp_Object final; + register Lisp_Object tem; + Lisp_Object prefixarg; + struct backtrace backtrace; + extern int debug_on_next_call; + + prefixarg = Vprefix_arg, Vprefix_arg = Qnil; + Vcurrent_prefix_arg = prefixarg; + debug_on_next_call = 0; + + if (XTYPE (cmd) == Lisp_Symbol) + { + tem = Fget (cmd, Qdisabled); + if (!NULL (tem)) + return call0 (Vdisabled_command_hook); + } + + while (1) + { + final = cmd; + while (XTYPE (final) == Lisp_Symbol) + { + if (EQ (Qunbound, XSYMBOL (final)->function)) + Fsymbol_function (final); /* Get an error! */ + final = XSYMBOL (final)->function; + } + + if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload))) + do_autoload (final, cmd); + else + break; + } + + if (CONSP (final) || XTYPE (final) == Lisp_Subr) + { + backtrace.next = backtrace_list; + backtrace_list = &backtrace; + backtrace.function = &Qcall_interactively; + backtrace.args = &cmd; + backtrace.nargs = 1; + backtrace.evalargs = 0; + + tem = Fcall_interactively (cmd, record); + + backtrace_list = backtrace.next; + return tem; + } + if (XTYPE (final) == Lisp_String) + { + return Fexecute_kbd_macro (final, prefixarg); + } + return Qnil; +} + +DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command, + 1, 1, "P", + "Read function name, then read its arguments and call it.") + (prefixarg) + Lisp_Object prefixarg; +{ + Lisp_Object function; + char buf[40]; + Lisp_Object saved_keys; + struct gcpro gcpro1; + + saved_keys = Fthis_command_keys (); + GCPRO1 (saved_keys); + + buf[0] = 0; + + if (EQ (prefixarg, Qminus)) + strcpy (buf, "- "); + else if (CONSP (prefixarg) && XINT (XCONS (prefixarg)->car) == 4) + strcpy (buf, "C-u "); + else if (CONSP (prefixarg) && XTYPE (XCONS (prefixarg)->car) == Lisp_Int) + sprintf (buf, "%d ", XINT (XCONS (prefixarg)->car)); + else if (XTYPE (prefixarg) == Lisp_Int) + sprintf (buf, "%d ", XINT (prefixarg)); + + /* This isn't strictly correct if execute-extended-command + is bound to anything else */ + strcat (buf, "M-x "); + + function = Fcompleting_read (build_string (buf), Vobarray, Qcommandp, Qt, Qnil); + + saved_keys = concat2 (saved_keys, function); + if (this_command_keys_size < XSTRING (saved_keys)->size) + { + /* This makes the buffer bigger than necessary, but that's okay. */ + this_command_keys_size += XSTRING (saved_keys)->size; + this_command_keys = (unsigned char *) xrealloc (this_command_keys, + this_command_keys_size); + } + bcopy (XSTRING (saved_keys)->data, this_command_keys, + XSTRING (saved_keys)->size + 1); + this_command_key_count = XSTRING (saved_keys)->size; + + UNGCPRO; + + function = Fintern (function, Vobarray); + Vprefix_arg = prefixarg; + this_command = function; + + return Fcommand_execute (function, Qt); +} + +detect_input_pending () +{ + if (!input_pending) + get_input_pending (&input_pending); + + return input_pending; +} + +/* This is called in some cases before a possible quit. + It cases the next call to detect_input_pending to recompute input_pending. + So calling this function unnecessarily can't do any harm. */ +clear_input_pending () +{ + input_pending = 0; +} + +DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0, + "T if command input is currently available with no waiting.\n\ +Actually, the value is NIL only if we can be sure that no input is available.") + () +{ + if (unread_command_char >= 0) return Qt; + + return detect_input_pending () ? Qt : Qnil; +} + +DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0, + "Return string of last 100 chars read from terminal.") + () +{ + Lisp_Object val; + if (total_keys < sizeof recent_keys) + return make_string (recent_keys, total_keys); + + val = make_string (recent_keys, sizeof recent_keys); + bcopy (recent_keys + recent_keys_index, + XSTRING (val)->data, + sizeof recent_keys - recent_keys_index); + bcopy (recent_keys, + XSTRING (val)->data + sizeof recent_keys - recent_keys_index, + recent_keys_index); + return val; +} + +DEFUN ("this-command-keys", Fthis_command_keys, Sthis_command_keys, 0, 0, 0, + "Return string of the keystrokes that invoked this command.") + () +{ + return make_string (this_command_keys, this_command_key_count); +} + +DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0, + "Return the current depth in recursive edits.") + () +{ + Lisp_Object temp; + XFASTINT (temp) = command_loop_level + minibuf_level; + return temp; +} + +DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1, + "FOpen dribble file: ", + "Start writing all keyboard characters to FILE.\n\ +Use nil as an argument to close the dribble file.") + (file) + Lisp_Object file; +{ + if (dribble != 0) + fclose (dribble); + dribble = 0; + if (!NULL (file)) + { + file = Fexpand_file_name (file, Qnil); + dribble = fopen (XSTRING (file)->data, "w"); + } + return Qnil; +} + +DEFUN ("discard-input", Fdiscard_input, Sdiscard_input, 0, 0, 0, + "Discard the contents of the terminal input buffer.\n\ +Also flush any kbd macro definition in progress.") + () +{ + defining_kbd_macro = 0; + update_mode_lines++; + + unread_command_char = -1; + Vquit_flag = Qnil; + discard_tty_input (); + + kbd_count = 0; + input_pending = 0; + + return Qnil; +} + +DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "", + "Stop Emacs and return to superior process. You can resume.\n\ +If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\ +to be read as terminal input by Emacs's superior shell.\n\ +Before suspending, if `suspend-hook' is bound and value is non-nil\n\ +call the value as a function of no args. Don't suspend if it returns non-nil.\n\ +Otherwise, suspend normally and after resumption call\n\ +`suspend-resume-hook' if that is bound and non-nil.") + (stuffstring) + Lisp_Object stuffstring; +{ + register Lisp_Object tem; + int count = specpdl_ptr - specpdl; + int old_height, old_width; + int width, height; + struct gcpro gcpro1; + extern init_sys_modes (); + + if (!NULL (stuffstring)) + CHECK_STRING (stuffstring, 0); + GCPRO1 (stuffstring); + + /* Call value of suspend-hook + if it is bound and value is non-nil. */ + tem = intern ("suspend-hook"); + tem = XSYMBOL (tem)->value; + if (! EQ (tem, Qunbound) && ! EQ (tem, Qnil)) + { + tem = call0 (tem); + if (!EQ (tem, Qnil)) return Qnil; + } + + get_screen_size (&old_width, &old_height); + reset_sys_modes (); + /* sys_suspend can get an error if it tries to fork a subshell + and the system resources aren't available for that. */ + record_unwind_protect (init_sys_modes, 0); + stuff_buffered_input (stuffstring); + sys_suspend (); + unbind_to (count); + + /* Check if terminal/window size has changed. + Note that this is not useful when we are running directly + with a window system; but suspend should be disabled in that case. */ + get_screen_size (&width, &height); + if (width != old_width || height != old_height) + change_screen_size (height, width, 0, 0, 0); + + /* Call value of suspend-resume-hook + if it is bound and value is non-nil. */ + tem = intern ("suspend-resume-hook"); + tem = XSYMBOL (tem)->value; + if (! EQ (tem, Qunbound) && ! EQ (tem, Qnil)) + call0 (tem); + UNGCPRO; + return Qnil; +} + +/* If STUFFSTRING is a string, stuff its contents as pending terminal input. + Then in any case stuff anthing Emacs has read ahead and not used. */ + +stuff_buffered_input (stuffstring) + Lisp_Object stuffstring; +{ + register unsigned char *p; + +/* stuff_char works only in BSD, versions 4.2 and up. */ +#ifdef BSD +#ifndef BSD4_1 + if (XTYPE (stuffstring) == Lisp_String) + { + register int count; + + p = XSTRING (stuffstring)->data; + count = XSTRING (stuffstring)->size; + while (count-- > 0) + stuff_char (*p++); + stuff_char ('\n'); + } + /* Anything we have read ahead, put back for the shell to read. */ + while (kbd_count) + { + stuff_char (*kbd_ptr++); + kbd_count--; + } + input_pending = 0; +#endif +#endif /* BSD and not BSD4_1 */ +} + +set_waiting_for_input (word_to_clear) + long *word_to_clear; +{ + input_available_clear_word = word_to_clear; + + /* Tell interrupt_signal to throw back to read_command_char, */ + waiting_for_input = 1; + + /* If interrupt_signal was called before and buffered a C-g, + make it run again now, to avoid timing error. */ + if (!NULL (Vquit_flag)) + quit_throw_to_read_command_char (); + + /* Tell alarm signal to echo right away */ + echo_now = 1; + + /* If alarm has gone off already, echo now. */ + if (echo_flag) + { + echo (); + echo_flag = 0; + } +} + +clear_waiting_for_input () +{ + /* Tell interrupt_signal not to throw back to read_command_char, */ + waiting_for_input = 0; + echo_now = 0; + input_available_clear_word = 0; +} + +/* This routine is called at interrupt level in response to C-G. + If interrupt_input, this is the handler for SIGINT. + Otherwise, it is called from kbd_buffer_store_char, + in handling SIGIO or SIGTINT. + + If `waiting_for_input' is non zero, then unless `echoing' is nonzero, + immediately throw back to read_command_char. + + Otherwise it sets the Lisp variable quit-flag not-nil. + This causes eval to throw, when it gets a chance. + If quit-flag is already non-nil, it stops the job right away. */ + +interrupt_signal () +{ + char c; + /* Must preserve main program's value of errno. */ + int old_errno = errno; + extern Lisp_Object Vwindow_system; + +#ifdef USG + /* USG systems forget handlers when they are used; + must reestablish each time */ + signal (SIGINT, interrupt_signal); + signal (SIGQUIT, interrupt_signal); +#endif /* USG */ + + cancel_echoing (); + + if (!NULL (Vquit_flag) && NULL (Vwindow_system)) + { + fflush (stdout); + reset_sys_modes (); + sigfree (); +#ifdef SIGTSTP /* Support possible in later USG versions */ +/* + * On systems which can suspend the current process and return to the original + * shell, this command causes the user to end up back at the shell. + * The "Auto-save" and "Abort" questions are not asked until + * the user elects to return to emacs, at which point he can save the current + * job and either dump core or continue. + */ + sys_suspend (); +#else +#ifdef VMS + if (sys_suspend () == -1) + { + printf ("Not running as a subprocess;\n"); + printf ("you can continue or abort.\n"); + } +#else /* not VMS */ + /* Perhaps should really fork an inferior shell? + But that would not provide any way to get back + to the original shell, ever. */ + printf ("No support for stopping a process on this operating system;\n"); + printf ("you can continue or abort.\n"); +#endif /* not VMS */ +#endif /* not SIGTSTP */ + printf ("Auto-save? (y or n) "); + fflush (stdout); + if (((c = getchar ()) & ~040) == 'Y') + Fdo_auto_save (Qnil); + while (c != '\n') c = getchar (); +#ifdef VMS + printf ("Abort (and enter debugger)? (y or n) "); +#else /* not VMS */ + printf ("Abort (and dump core)? (y or n) "); +#endif /* not VMS */ + fflush (stdout); + if (((c = getchar ()) & ~040) == 'Y') + abort (); + while (c != '\n') c = getchar (); + printf ("Continuing...\n"); + fflush (stdout); + init_sys_modes (); + } + else + { + /* If executing a function that wants to be interrupted out of + and the user has not deferred quitting by binding `inhibit-quit' + then quit right away. */ + if (immediate_quit && NULL (Vinhibit_quit)) + { + immediate_quit = 0; + sigfree (); + Fsignal (Qquit, Qnil); + } + else + /* Else request quit when it's safe */ + Vquit_flag = Qt; + } + + if (waiting_for_input && !echoing) + quit_throw_to_read_command_char (); + + errno = old_errno; +} + +/* Handle a C-g by making read_command_char return C-g. */ + +quit_throw_to_read_command_char () +{ + quit_error_check (); + sigfree (); + /* Prevent another signal from doing this before we finish. */ + waiting_for_input = 0; + input_pending = 0; + unread_command_char = -1; +#ifdef POLL_FOR_INPUT + if (poll_suppress_count != 1) + abort (); +#endif + _longjmp (getcjmp, 1); +} + +DEFUN ("set-input-mode", Fset_input_mode, Sset_input_mode, 2, 3, 0, + "Set mode of reading keyboard input.\n\ +First arg non-nil means use input interrupts; nil means use CBREAK mode.\n\ +Second arg non-nil means use ^S/^Q flow control for output to terminal\n\ + (no effect except in CBREAK mode).\n\ +Optional third arg non-nil specifies character to use for quitting.\n\n\ +Note that the arguments will change incompatibly in version 19.") + (interrupt, flow, quit) + Lisp_Object interrupt, flow, quit; +{ + reset_sys_modes (); +#ifdef SIGIO +/* Note SIGIO has been undef'd if FIONREAD is missing. */ +#ifdef NO_SOCK_SIGIO + if (read_socket_hook) + interrupt_input = 0; /* No interrupts if reading from a socket. */ + else +#endif /* NO_SOCK_SIGIO */ + interrupt_input = !NULL (interrupt); +#else /* not SIGIO */ + interrupt_input = 0; +#endif /* not SIGIO */ + flow_control = !NULL (flow); + if (!NULL (quit)) + { + CHECK_NUMBER (quit, 2); + quit_char = XINT (quit); + /* Don't let this value be out of range. */ + quit_char &= (meta_key ? 0377 : 0177); + } + init_sys_modes (); + return Qnil; +} + +init_keyboard () +{ + this_command_keys_size = 40; + this_command_keys = (unsigned char *) xmalloc (40); + + command_loop_level = -1; /* Correct, before outermost invocation. */ + quit_char = Ctl ('G'); + immediate_quit = 0; + unread_command_char = -1; + recent_keys_index = 0; + total_keys = 0; + kbd_count = 0; + kbd_ptr = kbd_buffer; + input_pending = 0; + force_input = 0; + if (!noninteractive) + { + signal (SIGINT, interrupt_signal); +#ifdef HAVE_TERMIO + /* On systems with TERMIO, C-g is set up for both SIGINT and SIGQUIT + and we can't tell which one it will give us. */ + signal (SIGQUIT, interrupt_signal); +#endif /* HAVE_TERMIO */ +/* Note SIGIO has been undef'd if FIONREAD is missing. */ +#ifdef SIGIO + signal (SIGIO, input_available_signal); +#endif /* SIGIO */ + } + +/* Use interrupt input by default, if it works and noninterrupt input + has deficiencies. */ + +#ifdef INTERRUPT_INPUT + interrupt_input = 1; +#else + interrupt_input = 0; +#endif + + sigfree (); + dribble = 0; + + if (keyboard_init_hook) + (*keyboard_init_hook) (); + + poll_suppress_count = 1; +#ifdef POLL_FOR_INPUT + start_polling (); +#endif +} + +syms_of_keyboard () +{ + Qself_insert_command = intern ("self-insert-command"); + staticpro (&Qself_insert_command); + + Qforward_char = intern ("forward-char"); + staticpro (&Qforward_char); + + Qbackward_char = intern ("backward-char"); + staticpro (&Qbackward_char); + + Qdisabled = intern ("disabled"); + staticpro (&Qdisabled); + + defsubr (&Sread_key_sequence); + defsubr (&Srecursive_edit); + defsubr (&Sinput_pending_p); + defsubr (&Scommand_execute); + defsubr (&Srecent_keys); + defsubr (&Sthis_command_keys); + defsubr (&Ssuspend_emacs); + defsubr (&Sabort_recursive_edit); + defsubr (&Sexit_recursive_edit); + defsubr (&Srecursion_depth); + defsubr (&Stop_level); + defsubr (&Sdiscard_input); + defsubr (&Sopen_dribble_file); + defsubr (&Sset_input_mode); + defsubr (&Sexecute_extended_command); + + DEFVAR_LISP ("disabled-command-hook", &Vdisabled_command_hook, + "Value is called instead of any command that is disabled\n\ +\(has a non-nil disabled property)."); + + DEFVAR_BOOL ("meta-flag", &meta_key, + "*Non-nil means treat 0200 bit in terminal input as Meta bit."); + + DEFVAR_INT ("last-command-char", &last_command_char, + "Last terminal input character that was part of a command, as an integer."); + + DEFVAR_INT ("last-input-char", &last_input_char, + "Last terminal input character, as an integer."); + + DEFVAR_INT ("unread-command-char", &unread_command_char, + "Character to be read as next input from command input stream, or -1 if none."); + + DEFVAR_INT ("meta-prefix-char", &meta_prefix_char, + "Meta-prefix character code. Meta-foo as command input\n\ +turns into this character followed by foo."); + meta_prefix_char = 033; + + DEFVAR_LISP ("last-command", &last_command, + "The last command executed. Normally a symbol with a function definition,\n\ +but can be whatever was found in the keymap, or whatever the variable\n\ +`this-command' was set to by that command."); + last_command = Qnil; + + DEFVAR_LISP ("this-command", &this_command, + "The command now being executed.\n\ +The command can set this variable; whatever is put here\n\ +will be in last-command during the following command."); + this_command = Qnil; + + DEFVAR_INT ("auto-save-interval", &auto_save_interval, + "*Number of keyboard input characters between auto-saves.\n\ +Zero means disable autosaving."); + auto_save_interval = 300; + + DEFVAR_INT ("echo-keystrokes", &echo_keystrokes, + "*Nonzero means echo unfinished commands after this many seconds of pause."); + echo_keystrokes = 1; + + DEFVAR_INT ("polling-period", &polling_period, + "*Interval between polling for input during Lisp execution.\n\ +The reason for polling is to make C-g work to stop a running program.\n\ +Polling is needed only when using X windows and SIGIO does not work.\n\ +Polling is automatically disabled in all other cases."); + polling_period = 2; + + DEFVAR_INT ("help-char", &help_char, + "Character to recognize as meaning Help.\n\ +When it is read, do (eval help-form), and display result if it's a string.\n\ +If help-form's value is nil, this char can be read normally."); + help_char = Ctl ('H'); + + DEFVAR_LISP ("help-form", &Vhelp_form, + "Form to execute when character help-char is read.\n\ +If the form returns a string, that string is displayed.\n\ +If help-form is nil, the help char is not recognized."); + Vhelp_form = Qnil; + + DEFVAR_LISP ("top-level", &Vtop_level, + "Form to evaluate when Emacs starts up.\n\ +Useful to set before you dump a modified Emacs."); + Vtop_level = Qnil; + + DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table, + "String used as translate table for keyboard input, or nil.\n\ +Each character is looked up in this string and the contents used instead.\n\ +If string is of length N, character codes N and up are untranslated."); + Vkeyboard_translate_table = Qnil; +} + +keys_of_keyboard () +{ + ndefkey (Vglobal_map, Ctl ('Z'), "suspend-emacs"); + ndefkey (Vctl_x_map, Ctl ('Z'), "suspend-emacs"); + ndefkey (Vesc_map, Ctl ('C'), "exit-recursive-edit"); + ndefkey (Vglobal_map, Ctl (']'), "abort-recursive-edit"); + ndefkey (Vesc_map, 'x', "execute-extended-command"); +} |