📄 bind.c
字号:
/* bind.c -- key binding and startup file support for the readline library. *//* 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 (__TANDEM)# include <floss.h>#endif#if defined (HAVE_CONFIG_H)# include <config.h>#endif#include <stdio.h>#include <sys/types.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 */#include <errno.h>#if !defined (errno)extern int errno;#endif /* !errno */#include "posixstat.h"/* System-specific feature definitions and include files. */#include "rldefs.h"/* Some standard library routines. */#include "readline.h"#include "history.h"#include "rlprivate.h"#include "rlshell.h"#include "xmalloc.h"#if !defined (strchr) && !defined (__STDC__)extern char *strchr (), *strrchr ();#endif /* !strchr && !__STDC__ *//* Variables exported by this file. */Keymap rl_binding_keymap;static char *_rl_read_file PARAMS((char *, size_t *));static void _rl_init_file_error PARAMS((const char *));static int _rl_read_init_file PARAMS((const char *, int));static int glean_key_from_name PARAMS((char *));static int substring_member_of_array PARAMS((char *, const char **));static int currently_reading_init_file;/* used only in this file */static int _rl_prefer_visible_bell = 1;/* **************************************************************** *//* *//* Binding keys *//* *//* **************************************************************** *//* rl_add_defun (char *name, rl_command_func_t *function, int key) Add NAME to the list of named functions. Make FUNCTION be the function that gets called. If KEY is not -1, then bind it. */intrl_add_defun (name, function, key) const char *name; rl_command_func_t *function; int key;{ if (key != -1) rl_bind_key (key, function); rl_add_funmap_entry (name, function); return 0;}/* Bind KEY to FUNCTION. Returns non-zero if KEY is out of range. */intrl_bind_key (key, function) int key; rl_command_func_t *function;{ if (key < 0) return (key); if (META_CHAR (key) && _rl_convert_meta_chars_to_ascii) { if (_rl_keymap[ESC].type == ISKMAP) { Keymap escmap; escmap = FUNCTION_TO_KEYMAP (_rl_keymap, ESC); key = UNMETA (key); escmap[key].type = ISFUNC; escmap[key].function = function; return (0); } return (key); } _rl_keymap[key].type = ISFUNC; _rl_keymap[key].function = function; rl_binding_keymap = _rl_keymap; return (0);}/* Bind KEY to FUNCTION in MAP. Returns non-zero in case of invalid KEY. */intrl_bind_key_in_map (key, function, map) int key; rl_command_func_t *function; Keymap map;{ int result; Keymap oldmap; oldmap = _rl_keymap; _rl_keymap = map; result = rl_bind_key (key, function); _rl_keymap = oldmap; return (result);}/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right now, this is always used to attempt to bind the arrow keys, hence the check for rl_vi_movement_mode. */intrl_bind_key_if_unbound_in_map (key, default_func, kmap) int key; rl_command_func_t *default_func; Keymap kmap;{ char keyseq[2]; keyseq[0] = (unsigned char)key; keyseq[1] = '\0'; return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap));}intrl_bind_key_if_unbound (key, default_func) int key; rl_command_func_t *default_func;{ char keyseq[2]; keyseq[0] = (unsigned char)key; keyseq[1] = '\0'; return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap));}/* Make KEY do nothing in the currently selected keymap. Returns non-zero in case of error. */intrl_unbind_key (key) int key;{ return (rl_bind_key (key, (rl_command_func_t *)NULL));}/* Make KEY do nothing in MAP. Returns non-zero in case of error. */intrl_unbind_key_in_map (key, map) int key; Keymap map;{ return (rl_bind_key_in_map (key, (rl_command_func_t *)NULL, map));}/* Unbind all keys bound to FUNCTION in MAP. */intrl_unbind_function_in_map (func, map) rl_command_func_t *func; Keymap map;{ register int i, rval; for (i = rval = 0; i < KEYMAP_SIZE; i++) { if (map[i].type == ISFUNC && map[i].function == func) { map[i].function = (rl_command_func_t *)NULL; rval = 1; } } return rval;}intrl_unbind_command_in_map (command, map) const char *command; Keymap map;{ rl_command_func_t *func; func = rl_named_function (command); if (func == 0) return 0; return (rl_unbind_function_in_map (func, map));}/* Bind the key sequence represented by the string KEYSEQ to FUNCTION, starting in the current keymap. This makes new keymaps as necessary. */intrl_bind_keyseq (keyseq, function) const char *keyseq; rl_command_func_t *function;{ return (rl_generic_bind (ISFUNC, keyseq, (char *)function, _rl_keymap));}/* Bind the key sequence represented by the string KEYSEQ to FUNCTION. This makes new keymaps as necessary. The initial place to do bindings is in MAP. */intrl_bind_keyseq_in_map (keyseq, function, map) const char *keyseq; rl_command_func_t *function; Keymap map;{ return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map));}/* Backwards compatibility; equivalent to rl_bind_keyseq_in_map() */intrl_set_key (keyseq, function, map) const char *keyseq; rl_command_func_t *function; Keymap map;{ return (rl_generic_bind (ISFUNC, keyseq, (char *)function, map));}/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right now, this is always used to attempt to bind the arrow keys, hence the check for rl_vi_movement_mode. */intrl_bind_keyseq_if_unbound_in_map (keyseq, default_func, kmap) const char *keyseq; rl_command_func_t *default_func; Keymap kmap;{ rl_command_func_t *func; if (keyseq) { func = rl_function_of_keyseq (keyseq, kmap, (int *)NULL);#if defined (VI_MODE) if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode)#else if (!func || func == rl_do_lowercase_version)#endif return (rl_bind_keyseq_in_map (keyseq, default_func, kmap)); else return 1; } return 0;}intrl_bind_keyseq_if_unbound (keyseq, default_func) const char *keyseq; rl_command_func_t *default_func;{ return (rl_bind_keyseq_if_unbound_in_map (keyseq, default_func, _rl_keymap));}/* Bind the key sequence represented by the string KEYSEQ to the string of characters MACRO. This makes new keymaps as necessary. The initial place to do bindings is in MAP. */intrl_macro_bind (keyseq, macro, map) const char *keyseq, *macro; Keymap map;{ char *macro_keys; int macro_keys_len; macro_keys = (char *)xmalloc ((2 * strlen (macro)) + 1); if (rl_translate_keyseq (macro, macro_keys, ¯o_keys_len)) { free (macro_keys); return -1; } rl_generic_bind (ISMACR, keyseq, macro_keys, map); return 0;}/* Bind the key sequence represented by the string KEYSEQ to the arbitrary pointer DATA. TYPE says what kind of data is pointed to by DATA, right now this can be a function (ISFUNC), a macro (ISMACR), or a keymap (ISKMAP). This makes new keymaps as necessary. The initial place to do bindings is in MAP. */intrl_generic_bind (type, keyseq, data, map) int type; const char *keyseq; char *data; Keymap map;{ char *keys; int keys_len; register int i; KEYMAP_ENTRY k; k.function = 0; /* If no keys to bind to, exit right away. */ if (!keyseq || !*keyseq) { if (type == ISMACR) free (data); return -1; } keys = (char *)xmalloc (1 + (2 * strlen (keyseq))); /* Translate the ASCII representation of KEYSEQ into an array of characters. Stuff the characters into KEYS, and the length of KEYS into KEYS_LEN. */ if (rl_translate_keyseq (keyseq, keys, &keys_len)) { free (keys); return -1; } /* Bind keys, making new keymaps as necessary. */ for (i = 0; i < keys_len; i++) { unsigned char uc = keys[i]; int ic; ic = uc; if (ic < 0 || ic >= KEYMAP_SIZE) return -1; if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic)) { ic = UNMETA (ic); if (map[ESC].type == ISKMAP) map = FUNCTION_TO_KEYMAP (map, ESC); } if ((i + 1) < keys_len) { if (map[ic].type != ISKMAP) { /* We allow subsequences of keys. If a keymap is being created that will `shadow' an existing function or macro key binding, we save that keybinding into the ANYOTHERKEY index in the new map. The dispatch code will look there to find the function to execute if the subsequence is not matched. ANYOTHERKEY was chosen to be greater than UCHAR_MAX. */ k = map[ic]; map[ic].type = ISKMAP; map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap()); } map = FUNCTION_TO_KEYMAP (map, ic); /* The dispatch code will return this function if no matching key sequence is found in the keymap. This (with a little help from the dispatch code in readline.c) allows `a' to be mapped to something, `abc' to be mapped to something else, and the function bound to `a' to be executed when the user types `abx', leaving `bx' in the input queue. */ if (k.function && ((k.type == ISFUNC && k.function != rl_do_lowercase_version) || k.type == ISMACR)) { map[ANYOTHERKEY] = k; k.function = 0; } } else { if (map[ic].type == ISMACR) free ((char *)map[ic].function); else if (map[ic].type == ISKMAP) { map = FUNCTION_TO_KEYMAP (map, ic); ic = ANYOTHERKEY; } map[ic].function = KEYMAP_TO_FUNCTION (data); map[ic].type = type; } rl_binding_keymap = map; } free (keys); return 0;}/* Translate the ASCII representation of SEQ, stuffing the values into ARRAY, an array of characters. LEN gets the final length of ARRAY. Return non-zero if there was an error parsing SEQ. */intrl_translate_keyseq (seq, array, len) const char *seq; char *array; int *len;{ register int i, c, l, temp; for (i = l = 0; c = seq[i]; i++) { if (c == '\\') { c = seq[++i]; if (c == 0) break; /* Handle \C- and \M- prefixes. */ if ((c == 'C' || c == 'M') && seq[i + 1] == '-') { /* Handle special case of backwards define. */ if (strncmp (&seq[i], "C-\\M-", 5) == 0) { array[l++] = ESC; /* ESC is meta-prefix */ i += 5; array[l++] = CTRL (_rl_to_upper (seq[i])); if (seq[i] == '\0') i--; } else if (c == 'M') { i++; array[l++] = ESC; /* ESC is meta-prefix */ } else if (c == 'C') { i += 2; /* Special hack for C-?... */ array[l++] = (seq[i] == '?') ? RUBOUT : CTRL (_rl_to_upper (seq[i])); } continue; } /* Translate other backslash-escaped characters. These are the same escape sequences that bash's `echo' and `printf' builtins handle, with the addition of \d -> RUBOUT. A backslash preceding a character that is not special is stripped. */ switch (c) { case 'a': array[l++] = '\007'; break; case 'b': array[l++] = '\b'; break; case 'd': array[l++] = RUBOUT; /* readline-specific */ break; case 'e': array[l++] = ESC; break; case 'f': array[l++] = '\f'; break; case 'n': array[l++] = NEWLINE; break; case 'r': array[l++] = RETURN; break; case 't': array[l++] = TAB; break; case 'v': array[l++] = 0x0B; break; case '\\': array[l++] = '\\'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': i++; for (temp = 2, c -= '0'; ISOCTAL (seq[i]) && temp--; i++) c = (c * 8) + OCTVALUE (seq[i]); i--; /* auto-increment in for loop */ array[l++] = c & largest_char; break; case 'x': i++; for (temp = 2, c = 0; ISXDIGIT ((unsigned char)seq[i]) && temp--; i++) c = (c * 16) + HEXVALUE (seq[i]); if (temp == 2) c = 'x'; i--; /* auto-increment in for loop */ array[l++] = c & largest_char; break; default: /* backslashes before non-special chars just add the char */ array[l++] = c; break; /* the backslash is stripped */ } continue; } array[l++] = c; } *len = l; array[l] = '\0'; return (0);}char *rl_untranslate_keyseq (seq) int seq;{ static char kseq[16]; int i, c; i = 0; c = seq; if (META_CHAR (c)) { kseq[i++] = '\\'; kseq[i++] = 'M'; kseq[i++] = '-'; c = UNMETA (c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -