📄 readline.c
字号:
/* readline.c -- a general facility for reading lines of input with emacs style editing and completion. *//* Copyright 1987, 1989, 1991, 1992 Free Software Foundation, Inc. This file contains the Readline Library (the Library), a set of routines for providing Emacs style line input to programs that ask for it. The 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 of the License, or (at your option) any later version. The 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Remove these declarations when we have a complete libgnu.a. *//* #define STATIC_MALLOC */#if !defined (STATIC_MALLOC)extern char *xmalloc (), *xrealloc ();#elsestatic char *xmalloc (), *xrealloc ();#endif /* STATIC_MALLOC */#include "sysdep.h"#include <sys/types.h>#include <stdio.h>#include <fcntl.h>#ifndef NO_SYS_FILE#include <sys/file.h>#endif#include <signal.h>#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#define NEW_TTY_DRIVER#define HAVE_BSD_SIGNALS/* #define USE_XON_XOFF */#ifdef __MSDOS__#undef NEW_TTY_DRIVER#undef HAVE_BSD_SIGNALS#endif/* Some USG machines have BSD signal handling (sigblock, sigsetmask, etc.) */#if defined (USG) && !defined (hpux)#undef HAVE_BSD_SIGNALS#endif/* System V machines use termio. */#if !defined (_POSIX_VERSION)# if defined (USG) || defined (hpux) || defined (Xenix) || defined (sgi) || defined (DGUX)# undef NEW_TTY_DRIVER# define TERMIO_TTY_DRIVER# include <termio.h># if !defined (TCOON)# define TCOON 1# endif# endif /* USG || hpux || Xenix || sgi || DUGX */#endif /* !_POSIX_VERSION *//* Posix systems use termios and the Posix signal functions. */#if defined (_POSIX_VERSION)# if !defined (TERMIOS_MISSING)# undef NEW_TTY_DRIVER# define TERMIOS_TTY_DRIVER# include <termios.h># endif /* !TERMIOS_MISSING */# define HAVE_POSIX_SIGNALS# if !defined (O_NDELAY)# define O_NDELAY O_NONBLOCK /* Posix-style non-blocking i/o */# endif /* O_NDELAY */#endif /* _POSIX_VERSION *//* Other (BSD) machines use sgtty. */#if defined (NEW_TTY_DRIVER)#include <sgtty.h>#endif/* Define _POSIX_VDISABLE if we are not using the `new' tty driver and it is not already defined. It is used both to determine if a special character is disabled and to disable certain special characters. Posix systems should set to 0, USG systems to -1. */#if !defined (NEW_TTY_DRIVER) && !defined (_POSIX_VDISABLE)# if defined (_POSIX_VERSION)# define _POSIX_VDISABLE 0# else /* !_POSIX_VERSION */# define _POSIX_VDISABLE -1# endif /* !_POSIX_VERSION */#endif /* !NEW_TTY_DRIVER && !_POSIX_VDISABLE *//* Define some macros for dealing with assorted signalling disciplines. These macros provide a way to use signal blocking and disabling without smothering your code in a pile of #ifdef's. SIGNALS_UNBLOCK; Stop blocking all signals. { SIGNALS_DECLARE_SAVED (name); Declare a variable to save the signal blocking state. ... SIGNALS_BLOCK (SIGSTOP, name); Block a signal, and save the previous state for restoration later. ... SIGNALS_RESTORE (name); Restore previous signals. }*/#ifdef HAVE_POSIX_SIGNALS /* POSIX signals */#define SIGNALS_UNBLOCK \ do { sigset_t set; \ sigemptyset (&set); \ sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL); \ } while (0)#define SIGNALS_DECLARE_SAVED(name) sigset_t name#define SIGNALS_BLOCK(SIG, saved) \ do { sigset_t set; \ sigemptyset (&set); \ sigaddset (&set, SIG); \ sigprocmask (SIG_BLOCK, &set, &saved); \ } while (0)#define SIGNALS_RESTORE(saved) \ sigprocmask (SIG_SETMASK, &saved, (sigset_t *)NULL)#else /* HAVE_POSIX_SIGNALS */#ifdef HAVE_BSD_SIGNALS /* BSD signals */#define SIGNALS_UNBLOCK sigsetmask (0)#define SIGNALS_DECLARE_SAVED(name) int name#define SIGNALS_BLOCK(SIG, saved) saved = sigblock (sigmask (SIG))#define SIGNALS_RESTORE(saved) sigsetmask (saved)#else /* HAVE_BSD_SIGNALS */ /* None of the Above */#define SIGNALS_UNBLOCK /* nothing */#define SIGNALS_DECLARE_SAVED(name) /* nothing */#define SIGNALS_BLOCK(SIG, saved) /* nothing */#define SIGNALS_RESTORE(saved) /* nothing */#endif /* HAVE_BSD_SIGNALS */#endif /* HAVE_POSIX_SIGNALS *//* End of signal handling definitions. */#include <errno.h>extern int errno;#include <setjmp.h>#include <sys/stat.h>/* Posix macro to check file in statbuf for directory-ness. */#if defined (S_IFDIR) && !defined (S_ISDIR)#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)#endif#ifndef __MSDOS__/* These next are for filename completion. Perhaps this belongs in a different place. */#include <pwd.h>#endif /* __MSDOS__ */#if defined (USG) && !defined (isc386) && !defined (sgi)struct passwd *getpwuid (), *getpwent ();#endif/* #define HACK_TERMCAP_MOTION *//* Some standard library routines. */#include "readline.h"#include "history.h"#ifndef digit#define digit(c) ((c) >= '0' && (c) <= '9')#endif#ifndef isletter#define isletter(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))#endif#ifndef digit_value#define digit_value(c) ((c) - '0')#endif#ifndef member#define member(c, s) ((c) ? index ((s), (c)) : 0)#endif#ifndef isident#define isident(c) ((isletter(c) || digit(c) || c == '_'))#endif#ifndef exchange#define exchange(x, y) {int temp = x; x = y; y = temp;}#endif#if !defined (rindex)extern char *rindex ();#endif /* rindex */#if !defined (index)extern char *index ();#endif /* index */extern char *getenv ();extern char *tilde_expand ();static update_line ();static void output_character_function ();static delete_chars ();static void insert_some_chars ();#if defined (VOID_SIGHANDLER)# define sighandler void#else# define sighandler int#endif /* VOID_SIGHANDLER *//* This typedef is equivalant to the one for Function; it allows us to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */typedef sighandler SigHandler ();/* If on, then readline handles signals in a way that doesn't screw. */#define HANDLE_SIGNALS#ifdef __GO32__#include <sys/pc.h>#undef HANDLE_SIGNALS#endif/* **************************************************************** *//* *//* Line editing input utility *//* *//* **************************************************************** *//* A pointer to the keymap that is currently in use. By default, it is the standard emacs keymap. */Keymap keymap = emacs_standard_keymap;#define no_mode -1#define vi_mode 0#define emacs_mode 1/* The current style of editing. */int rl_editing_mode = emacs_mode;/* Non-zero if the previous command was a kill command. */static int 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 = 0;/* If non-zero, this program is running in an EMACS buffer. */static char *running_in_emacs = (char *)NULL;/* 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 (). */static jmp_buf readline_top_level;/* The streams we interact with. */static FILE *in_stream, *out_stream;/* The names of the streams that we do input and output to. */FILE *rl_instream, *rl_outstream;/* Non-zero means echo characters as they are read. */int readline_echoing_p = 1;/* Current prompt. */char *rl_prompt;/* 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 () prints the first prompt. */Function *rl_startup_hook = (Function *)NULL;/* If non-zero, then this is the address of a function to call when completing on a directory name. The function is called with the address of a string (the current directory name) as an arg. */Function *rl_symbolic_link_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. */static int 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;/* Line buffer and maintenence. */char *rl_line_buffer = (char *)NULL;int rl_line_buffer_len = 0;#define DEFAULT_BUFFER_SIZE 256/* **************************************************************** *//* *//* `Forward' declarations *//* *//* **************************************************************** *//* Non-zero means do not parse any lines other than comments and parser directives. */static unsigned char parsing_conditionalized_out = 0;/* Caseless strcmp (). */static int stricmp (), strnicmp ();static char *strpbrk ();/* Non-zero means to save keys that we dispatch on in a kbd macro. */static int defining_kbd_macro = 0;/* **************************************************************** *//* *//* Top Level Functions *//* *//* **************************************************************** */static void rl_prep_terminal (), rl_deprep_terminal ();static void clear_to_eol (), rl_generic_bind ();/* Read a line of input. Prompt with PROMPT. A NULL PROMPT means none. A return value of NULL means that EOF was encountered. */char *readline (prompt) char *prompt;{ char *readline_internal (); 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_initialize (); rl_prep_terminal ();#if defined (HANDLE_SIGNALS) rl_set_signals ();#endif value = readline_internal (); rl_deprep_terminal ();#if defined (HANDLE_SIGNALS) rl_clear_signals ();#endif return (value);}/* 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. */char *readline_internal (){ int lastc, c, eof_found; in_stream = rl_instream; out_stream = rl_outstream; lastc = -1; eof_found = 0; if (rl_startup_hook) (*rl_startup_hook) (); if (!readline_echoing_p) { if (rl_prompt) { fprintf (out_stream, "%s", rl_prompt); fflush (out_stream); } } else { rl_on_new_line (); rl_redisplay ();#if defined (VI_MODE) if (rl_editing_mode == vi_mode) rl_vi_insertion_mode ();#endif /* VI_MODE */ } while (!rl_done) { int lk = last_command_was_kill; int code = setjmp (readline_top_level); if (code) rl_redisplay (); if (!rl_pending_input) { /* 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 eof_char typed to blank line, and not as the previous character is interpreted as EOF. */ if (((c == eof_char && lastc != c) || c == EOF) && !rl_end) { eof_found = 1; break; } lastc = c; rl_dispatch (c, keymap); /* If there was no change in 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) { if (lk == last_command_was_kill) 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 && keymap == vi_movement_keymap) rl_vi_check ();#endif /* VI_MODE */ if (!rl_done) rl_redisplay (); } /* Restore the original of this history line, iff the line that we are editing was originally in the history, AND the line has changed. */ { HIST_ENTRY *entry = current_history (); if (entry && rl_undo_list) { char *temp = savestring (the_line); rl_revert_line (); entry = replace_history_entry (where_history (), the_line, (HIST_ENTRY *)NULL); 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 (); if (eof_found) return (char *)NULL; else return (savestring (the_line));}/* **************************************************************** *//* *//* Signal Handling *//* *//* **************************************************************** */#if defined (SIGWINCH)static SigHandler *old_sigwinch = (SigHandler *)NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -