📄 readline.c
字号:
/* readline.c -- a general facility for reading lines of input
with emacs style editing and completion. */
/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
The GNU Readline Library 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.
The GNU Readline Library 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.
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <sys/types.h>
#include "posixstat.h"
#include <fcntl.h>
#if defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif /* HAVE_SYS_FILE_H */
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */
#if defined (HAVE_LOCALE_H)
# include <locale.h>
#endif
#include <stdio.h>
#include "posixjmp.h"
/* System-specific feature definitions and include files. */
#include "rldefs.h"
#if defined (__EMX__)
# define INCL_DOSPROCESS
# include <os2.h>
#endif /* __EMX__ */
/* Some standard library routines. */
#include "readline.h"
#include "history.h"
#include "rlprivate.h"
#include "rlshell.h"
#include "xmalloc.h"
#ifndef RL_LIBRARY_VERSION
# define RL_LIBRARY_VERSION "4.1"
#endif
/* Evaluates its arguments multiple times. */
#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
/* Forward declarations used in this file. */
void _rl_free_history_entry __P((HIST_ENTRY *));
static char *readline_internal __P((void));
static void readline_initialize_everything __P((void));
static void start_using_history __P((void));
static void bind_arrow_keys __P((void));
static int rl_change_case __P((int, int));
static void readline_default_bindings __P((void));
/* **************************************************************** */
/* */
/* Line editing input utility */
/* */
/* **************************************************************** */
char *rl_library_version = RL_LIBRARY_VERSION;
int rl_gnu_readline_p = 1;
/* A pointer to the keymap that is currently in use.
By default, it is the standard emacs keymap. */
Keymap _rl_keymap = emacs_standard_keymap;
/* The current style of editing. */
int rl_editing_mode = emacs_mode;
/* Non-zero if we called this function from _rl_dispatch(). It's present
so functions can find out whether they were called from a key binding
or directly from an application. */
int rl_dispatching;
/* Non-zero if the previous command was a kill command. */
int _rl_last_command_was_kill = 0;
/* The current value of the numeric argument specified by the user. */
int rl_numeric_arg = 1;
/* Non-zero if an argument was typed. */
int rl_explicit_arg = 0;
/* Temporary value used while generating the argument. */
int rl_arg_sign = 1;
/* Non-zero means we have been called at least once before. */
static int rl_initialized;
/* If non-zero, this program is running in an EMACS buffer. */
static int running_in_emacs;
/* The current offset in the current input line. */
int rl_point;
/* Mark in the current input line. */
int rl_mark;
/* Length of the current input line. */
int rl_end;
/* Make this non-zero to return the current input_line. */
int rl_done;
/* The last function executed by readline. */
Function *rl_last_func = (Function *)NULL;
/* Top level environment for readline_internal (). */
procenv_t readline_top_level;
/* The streams we interact with. */
FILE *_rl_in_stream, *_rl_out_stream;
/* The names of the streams that we do input and output to. */
FILE *rl_instream = (FILE *)NULL;
FILE *rl_outstream = (FILE *)NULL;
/* Non-zero means echo characters as they are read. */
int readline_echoing_p = 1;
/* Current prompt. */
char *rl_prompt;
int rl_visible_prompt_length = 0;
/* Set to non-zero by calling application if it has already printed rl_prompt
and does not want readline to do it the first time. */
int rl_already_prompted = 0;
/* The number of characters read in order to type this complete command. */
int rl_key_sequence_length = 0;
/* If non-zero, then this is the address of a function to call just
before readline_internal_setup () prints the first prompt. */
Function *rl_startup_hook = (Function *)NULL;
/* If non-zero, this is the address of a function to call just before
readline_internal_setup () returns and readline_internal starts
reading input characters. */
Function *rl_pre_input_hook = (Function *)NULL;
/* What we use internally. You should always refer to RL_LINE_BUFFER. */
static char *the_line;
/* The character that can generate an EOF. Really read from
the terminal driver... just defaulted here. */
int _rl_eof_char = CTRL ('D');
/* Non-zero makes this the next keystroke to read. */
int rl_pending_input = 0;
/* Pointer to a useful terminal name. */
char *rl_terminal_name = (char *)NULL;
/* Non-zero means to always use horizontal scrolling in line display. */
int _rl_horizontal_scroll_mode = 0;
/* Non-zero means to display an asterisk at the starts of history lines
which have been modified. */
int _rl_mark_modified_lines = 0;
/* The style of `bell' notification preferred. This can be set to NO_BELL,
AUDIBLE_BELL, or VISIBLE_BELL. */
int _rl_bell_preference = AUDIBLE_BELL;
/* String inserted into the line by rl_insert_comment (). */
char *_rl_comment_begin;
/* Keymap holding the function currently being executed. */
Keymap rl_executing_keymap;
/* Non-zero means to erase entire line, including prompt, on empty input lines. */
int rl_erase_empty_line = 0;
/* Non-zero means to read only this many characters rather than up to a
character bound to accept-line. */
int rl_num_chars_to_read;
/* Line buffer and maintenence. */
char *rl_line_buffer = (char *)NULL;
int rl_line_buffer_len = 0;
/* Forward declarations used by the display and termcap code. */
/* **************************************************************** */
/* */
/* `Forward' declarations */
/* */
/* **************************************************************** */
/* Non-zero means do not parse any lines other than comments and
parser directives. */
unsigned char _rl_parsing_conditionalized_out = 0;
/* Non-zero means to convert characters with the meta bit set to
escape-prefixed characters so we can indirect through
emacs_meta_keymap or vi_escape_keymap. */
int _rl_convert_meta_chars_to_ascii = 1;
/* Non-zero means to output characters with the meta bit set directly
rather than as a meta-prefixed escape sequence. */
int _rl_output_meta_chars = 0;
/* **************************************************************** */
/* */
/* Top Level Functions */
/* */
/* **************************************************************** */
/* Non-zero means treat 0200 bit in terminal input as Meta bit. */
int _rl_meta_flag = 0; /* Forward declaration */
/* Read a line of input. Prompt with PROMPT. An empty PROMPT means
none. A return value of NULL means that EOF was encountered. */
char *
readline (prompt)
char *prompt;
{
char *value;
rl_prompt = prompt;
/* If we are at EOF return a NULL string. */
if (rl_pending_input == EOF)
{
rl_pending_input = 0;
return ((char *)NULL);
}
rl_visible_prompt_length = rl_expand_prompt (rl_prompt);
rl_initialize ();
(*rl_prep_term_function) (_rl_meta_flag);
#if defined (HANDLE_SIGNALS)
rl_set_signals ();
#endif
value = readline_internal ();
(*rl_deprep_term_function) ();
#if defined (HANDLE_SIGNALS)
rl_clear_signals ();
#endif
return (value);
}
#if defined (READLINE_CALLBACKS)
# define STATIC_CALLBACK
#else
# define STATIC_CALLBACK static
#endif
STATIC_CALLBACK void
readline_internal_setup ()
{
char *nprompt;
_rl_in_stream = rl_instream;
_rl_out_stream = rl_outstream;
if (rl_startup_hook)
(*rl_startup_hook) ();
if (readline_echoing_p == 0)
{
if (rl_prompt && rl_already_prompted == 0)
{
nprompt = _rl_strip_prompt (rl_prompt);
fprintf (_rl_out_stream, "%s", nprompt);
fflush (_rl_out_stream);
free (nprompt);
}
}
else
{
if (rl_prompt && rl_already_prompted)
rl_on_new_line_with_prompt ();
else
rl_on_new_line ();
(*rl_redisplay_function) ();
#if defined (VI_MODE)
if (rl_editing_mode == vi_mode)
rl_vi_insertion_mode (1, 0);
#endif /* VI_MODE */
}
if (rl_pre_input_hook)
(*rl_pre_input_hook) ();
}
STATIC_CALLBACK char *
readline_internal_teardown (eof)
int eof;
{
char *temp;
HIST_ENTRY *entry;
/* Restore the original of this history line, iff the line that we
are editing was originally in the history, AND the line has changed. */
entry = current_history ();
if (entry && rl_undo_list)
{
temp = savestring (the_line);
rl_revert_line (1, 0);
entry = replace_history_entry (where_history (), the_line, (histdata_t)NULL);
_rl_free_history_entry (entry);
strcpy (the_line, temp);
free (temp);
}
/* At any rate, it is highly likely that this line has an undo list. Get
rid of it now. */
if (rl_undo_list)
free_undo_list ();
return (eof ? (char *)NULL : savestring (the_line));
}
STATIC_CALLBACK int
#if defined (READLINE_CALLBACKS)
readline_internal_char ()
#else
readline_internal_charloop ()
#endif
{
static int lastc, eof_found;
int c, code, lk;
lastc = -1;
eof_found = 0;
#if !defined (READLINE_CALLBACKS)
while (rl_done == 0)
{
#endif
lk = _rl_last_command_was_kill;
code = setjmp (readline_top_level);
if (code)
(*rl_redisplay_function) ();
if (rl_pending_input == 0)
{
/* Then initialize the argument and number of keys read. */
_rl_init_argument ();
rl_key_sequence_length = 0;
}
c = rl_read_key ();
/* EOF typed to a non-blank line is a <NL>. */
if (c == EOF && rl_end)
c = NEWLINE;
/* The character _rl_eof_char typed to blank line, and not as the
previous character is interpreted as EOF. */
if (((c == _rl_eof_char && lastc != c) || c == EOF) && !rl_end)
{
#if defined (READLINE_CALLBACKS)
return (rl_done = 1);
#else
eof_found = 1;
break;
#endif
}
lastc = c;
_rl_dispatch ((unsigned char)c, _rl_keymap);
/* If there was no change in _rl_last_command_was_kill, then no kill
has taken place. Note that if input is pending we are reading
a prefix command, so nothing has changed yet. */
if (rl_pending_input == 0 && lk == _rl_last_command_was_kill)
_rl_last_command_was_kill = 0;
#if defined (VI_MODE)
/* In vi mode, when you exit insert mode, the cursor moves back
over the previous character. We explicitly check for that here. */
if (rl_editing_mode == vi_mode && _rl_keymap == vi_movement_keymap)
rl_vi_check ();
#endif /* VI_MODE */
if (rl_num_chars_to_read && rl_end >= rl_num_chars_to_read)
{
(*rl_redisplay_function) ();
rl_newline (1, '\n');
}
if (rl_done == 0)
(*rl_redisplay_function) ();
/* If the application writer has told us to erase the entire line if
the only character typed was something bound to rl_newline, do so. */
if (rl_erase_empty_line && rl_done && rl_last_func == rl_newline &&
rl_point == 0 && rl_end == 0)
_rl_erase_entire_line ();
#if defined (READLINE_CALLBACKS)
return 0;
#else
}
return (eof_found);
#endif
}
#if defined (READLINE_CALLBACKS)
static int
readline_internal_charloop ()
{
int eof = 1;
while (rl_done == 0)
eof = readline_internal_char ();
return (eof);
}
#endif /* READLINE_CALLBACKS */
/* Read a line of input from the global rl_instream, doing output on
the global rl_outstream.
If rl_prompt is non-null, then that is our prompt. */
static char *
readline_internal ()
{
int eof;
readline_internal_setup ();
eof = readline_internal_charloop ();
return (readline_internal_teardown (eof));
}
void
_rl_init_line_state ()
{
rl_point = rl_end = 0;
the_line = rl_line_buffer;
the_line[0] = 0;
}
void
_rl_set_the_line ()
{
the_line = rl_line_buffer;
}
/* Do the command associated with KEY in MAP.
If the associated command is really a keymap, then read
another key, and dispatch into that map. */
int
_rl_dispatch (key, map)
register int key;
Keymap map;
{
int r, newkey;
char *macro;
Function *func;
if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii)
{
if (map[ESC].type == ISKMAP)
{
if (_rl_defining_kbd_macro)
_rl_add_macro_char (ESC);
map = FUNCTION_TO_KEYMAP (map, ESC);
key = UNMETA (key);
rl_key_sequence_length += 2;
return (_rl_dispatch (key, map));
}
else
ding ();
return 0;
}
if (_rl_defining_kbd_macro)
_rl_add_macro_char (key);
r = 0;
switch (map[key].type)
{
case ISFUNC:
func = map[key].function;
if (func != (Function *)NULL)
{
/* Special case rl_do_lowercase_version (). */
if (func == rl_do_lowercase_version)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -