summaryrefslogtreecommitdiff
path: root/info/infomap.c
diff options
context:
space:
mode:
Diffstat (limited to 'info/infomap.c')
-rw-r--r--info/infomap.c1285
1 files changed, 1285 insertions, 0 deletions
diff --git a/info/infomap.c b/info/infomap.c
new file mode 100644
index 0000000..b964d01
--- /dev/null
+++ b/info/infomap.c
@@ -0,0 +1,1285 @@
+/* infomap.c -- keymaps for Info.
+ $Id: infomap.c,v 1.21 2008/06/11 09:55:42 gray Exp $
+
+ Copyright (C) 1993, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2007, 2008
+ Free Software Foundation, Inc.
+
+ This program 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 3 of the License, or
+ (at your option) any later version.
+
+ This program 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, see <http://www.gnu.org/licenses/>.
+
+ Written by Brian Fox (bfox@ai.mit.edu). */
+
+#include "info.h"
+#include "infomap.h"
+#include "funs.h"
+#include "terminal.h"
+
+#if defined(INFOKEY)
+#include "infokey.h"
+#include "variables.h"
+#endif /* INFOKEY */
+
+static int keymap_bind_keyseq (Keymap map, const char *keyseq,
+ KEYMAP_ENTRY *keyentry);
+
+/* Return a new keymap which has all the uppercase letters mapped to run
+ the function info_do_lowercase_version (). */
+Keymap
+keymap_make_keymap (void)
+{
+ int i;
+ Keymap keymap;
+
+ keymap = (Keymap)xmalloc (256 * sizeof (KEYMAP_ENTRY));
+
+ for (i = 0; i < 256; i++)
+ {
+ keymap[i].type = ISFUNC;
+ keymap[i].function = NULL;
+ }
+
+ for (i = 'A'; i < ('Z' + 1); i++)
+ {
+ keymap[i].type = ISFUNC;
+#if defined(INFOKEY)
+ keymap[Meta(i)].type = ISFUNC;
+ keymap[Meta(i)].function =
+#endif /* INFOKEY */
+ keymap[i].function = InfoCmd(info_do_lowercase_version);
+ }
+
+ return keymap;
+}
+
+#if defined(INFOKEY)
+static FUNCTION_KEYSEQ *
+find_function_keyseq (Keymap map, int c, Keymap rootmap)
+{
+ FUNCTION_KEYSEQ *k;
+
+ if (map[c].type != ISFUNC)
+ abort();
+ if (map[c].function == NULL)
+ return NULL;
+ for (k = map[c].function->keys; k; k = k->next)
+ {
+ const unsigned char *p;
+ Keymap m = rootmap;
+ if (k->map != rootmap)
+ continue;
+ for (p = (unsigned char *) k->keyseq; *p && m[*p].type == ISKMAP; p++)
+ m = (Keymap)m[*p].function;
+ if (*p != c || p[1])
+ continue;
+ if (m[*p].type != ISFUNC)
+ abort ();
+ break;
+ }
+ return k;
+}
+
+static void
+add_function_keyseq (InfoCommand *function,
+ const char *keyseq, Keymap rootmap)
+{
+ FUNCTION_KEYSEQ *ks;
+
+ if (function == NULL ||
+ function == InfoCmd(info_do_lowercase_version) ||
+ function == InfoCmd(ea_insert))
+ return;
+ ks = xmalloc (sizeof(FUNCTION_KEYSEQ));
+ ks->next = function->keys;
+ ks->map = rootmap;
+ ks->keyseq = xstrdup(keyseq);
+ function->keys = ks;
+}
+
+static void
+remove_function_keyseq (InfoCommand *function,
+ const char *keyseq, Keymap rootmap)
+{
+
+ FUNCTION_KEYSEQ *k, *kp;
+
+ if (function == NULL ||
+ function == InfoCmd(info_do_lowercase_version) ||
+ function == InfoCmd(ea_insert))
+ return;
+ for (kp = NULL, k = function->keys; k; kp = k, k = k->next)
+ if (k->map == rootmap && strcmp(k->keyseq, keyseq) == 0)
+ break;
+ if (!k)
+ abort ();
+ if (kp)
+ kp->next = k->next;
+ else
+ function->keys = k->next;
+}
+#endif /* INFOKEY */
+
+/* Return a new keymap which is a copy of MAP. */
+Keymap
+keymap_copy_keymap (Keymap map, Keymap rootmap, Keymap newroot)
+{
+ int i;
+ Keymap keymap;
+#if defined(INFOKEY)
+ FUNCTION_KEYSEQ *ks;
+#endif /* INFOKEY */
+
+ keymap = keymap_make_keymap ();
+ if (!newroot)
+ newroot = keymap;
+
+ for (i = 0; i < 256; i++)
+ {
+ keymap[i].type = map[i].type;
+ switch (map[i].type)
+ {
+ case ISFUNC:
+ keymap[i].function = map[i].function;
+#if defined(INFOKEY)
+ ks = find_function_keyseq (map, i, rootmap);
+ if (ks)
+ add_function_keyseq(map[i].function, ks->keyseq, newroot);
+#endif /* INFOKEY */
+ break;
+ case ISKMAP:
+ keymap[i].function = (InfoCommand *)keymap_copy_keymap
+ ((Keymap)map[i].function, rootmap, NULL);
+ break;
+ }
+ }
+ return keymap;
+}
+
+/* Free the keymap and its descendants. */
+void
+keymap_discard_keymap (Keymap map, Keymap rootmap)
+{
+ int i;
+
+ if (!map)
+ return;
+ if (!rootmap)
+ rootmap = map;
+
+ for (i = 0; i < 256; i++)
+ {
+#if defined(INFOKEY)
+ FUNCTION_KEYSEQ *ks;
+#endif /* INFOKEY */
+ switch (map[i].type)
+ {
+ case ISFUNC:
+#if defined(INFOKEY)
+ ks = find_function_keyseq(map, i, rootmap);
+ if (ks)
+ remove_function_keyseq (map[i].function, ks->keyseq, rootmap);
+#endif /* INFOKEY */
+ break;
+
+ case ISKMAP:
+ keymap_discard_keymap ((Keymap)map[i].function, rootmap);
+ break;
+
+ }
+ }
+ free(map);
+}
+
+/* Conditionally bind key sequence. */
+static int
+keymap_bind_keyseq (Keymap map,
+ const char *keyseq, KEYMAP_ENTRY *keyentry)
+{
+ Keymap m = map;
+ const unsigned char *s = (unsigned char *) keyseq;
+ int c;
+
+ if (s == NULL || *s == '\0') return 0;
+
+ while ((c = *s++) != '\0')
+ {
+#if defined(INFOKEY)
+ FUNCTION_KEYSEQ *ks;
+#endif /* INFOKEY */
+ switch (m[c].type)
+ {
+ case ISFUNC:
+#if defined(INFOKEY)
+ ks = find_function_keyseq(m, c, map);
+ if (ks)
+ remove_function_keyseq (m[c].function, ks->keyseq, map);
+#else /* !INFOKEY */
+ if (!(m[c].function == NULL || (
+ m != map &&
+ m[c].function == InfoCmd(info_do_lowercase_version))
+ ))
+ return 0;
+#endif /* !INFOKEY */
+
+ if (*s != '\0')
+ {
+ m[c].type = ISKMAP;
+ /* Here we are casting the Keymap pointer returned from
+ keymap_make_keymap to an InfoCommand pointer. Ugh.
+ This makes the `function' structure garbage
+ if it's actually interpreted as an InfoCommand.
+ Should really be using a union, and taking steps to
+ avoid the possible error. */
+ m[c].function = (InfoCommand *)keymap_make_keymap ();
+ }
+ break;
+
+ case ISKMAP:
+#if defined(INFOKEY)
+ if (*s == '\0')
+ keymap_discard_keymap ((Keymap)m[c].function, map);
+#else /* !INFOKEY */
+ if (*s == '\0')
+ return 0;
+#endif
+ break;
+ }
+ if (*s != '\0')
+ {
+ m = (Keymap)m[c].function;
+ }
+ else
+ {
+#if defined(INFOKEY)
+ add_function_keyseq (keyentry->function, keyseq, map);
+#endif /* INFOKEY */
+ m[c] = *keyentry;
+ }
+ }
+
+ return 1;
+}
+
+
+/* Initialize the standard info keymaps. */
+
+Keymap info_keymap = NULL;
+Keymap echo_area_keymap = NULL;
+
+/* Make sure that we don't have too many command codes defined. */
+
+#if A_NCOMMANDS > A_MAX_COMMAND + 1
+#error "too many commands defined"
+#endif
+
+/* Initialize the keymaps from the .info keymap file. */
+
+#define NUL '\0'
+
+static unsigned char default_emacs_like_info_keys[] =
+{
+ 0, /* suppress-default-keybindings flag */
+ TAB, NUL, A_info_move_to_next_xref,
+ LFD, NUL, A_info_select_reference_this_line,
+ RET, NUL, A_info_select_reference_this_line,
+ CONTROL('a'), NUL, A_info_beginning_of_line,
+ CONTROL('b'), NUL, A_info_backward_char,
+ CONTROL('e'), NUL, A_info_end_of_line,
+ CONTROL('f'), NUL, A_info_forward_char,
+ CONTROL('h'), NUL, A_info_get_help_window,
+ CONTROL('l'), NUL, A_info_redraw_display,
+ CONTROL('n'), NUL, A_info_next_line,
+ CONTROL('p'), NUL, A_info_prev_line,
+ CONTROL('r'), NUL, A_isearch_backward,
+ CONTROL('s'), NUL, A_isearch_forward,
+ CONTROL('u'), NUL, A_info_universal_argument,
+ CONTROL('v'), NUL, A_info_scroll_forward_page_only,
+ ',', NUL, A_info_next_index_match,
+ '/', NUL, A_info_search,
+ '0', NUL, A_info_last_menu_item,
+ '1', NUL, A_info_menu_digit,
+ '2', NUL, A_info_menu_digit,
+ '3', NUL, A_info_menu_digit,
+ '4', NUL, A_info_menu_digit,
+ '5', NUL, A_info_menu_digit,
+ '6', NUL, A_info_menu_digit,
+ '7', NUL, A_info_menu_digit,
+ '8', NUL, A_info_menu_digit,
+ '9', NUL, A_info_menu_digit,
+ '<', NUL, A_info_first_node,
+ '>', NUL, A_info_last_node,
+ '?', NUL, A_info_get_help_window,
+ '[', NUL, A_info_global_prev_node,
+ ']', NUL, A_info_global_next_node,
+ 'b', NUL, A_info_beginning_of_node,
+ 'd', NUL, A_info_dir_node,
+ 'e', NUL, A_info_end_of_node,
+ 'f', NUL, A_info_xref_item,
+ 'g', NUL, A_info_goto_node,
+ 'G', NUL, A_info_menu_sequence,
+ 'h', NUL, A_info_get_help_window,
+ 'H', NUL, A_info_get_info_help_node,
+ 'i', NUL, A_info_index_search,
+ 'l', NUL, A_info_history_node,
+ 'm', NUL, A_info_menu_item,
+ 'n', NUL, A_info_next_node,
+ 'O', NUL, A_info_goto_invocation_node,
+ 'p', NUL, A_info_prev_node,
+ 'r', NUL, A_info_xref_item,
+ 'R', NUL, A_info_toggle_regexp,
+ 's', NUL, A_info_search,
+ 'S', NUL, A_info_search_case_sensitively,
+ 't', NUL, A_info_top_node,
+ 'u', NUL, A_info_up_node,
+ ESC, '0', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '1', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '2', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '3', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '4', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '5', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '6', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '7', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '8', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '9', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '-', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, CONTROL('f'), NUL, A_info_show_footnotes,
+ ESC, CONTROL('g'), NUL, A_info_abort_key,
+ ESC, TAB, NUL, A_info_move_to_prev_xref,
+ ESC, CONTROL('v'), NUL, A_info_scroll_other_window,
+ ESC, '<', NUL, A_info_beginning_of_node,
+ ESC, '>', NUL, A_info_end_of_node,
+ ESC, 'b', NUL, A_info_backward_word,
+ ESC, 'f', NUL, A_info_forward_word,
+ ESC, 'r', NUL, A_info_move_to_window_line,
+ ESC, 'v', NUL, A_info_scroll_backward_page_only,
+ Meta('0'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('1'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('2'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('3'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('4'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('5'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('6'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('7'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('8'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('9'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('-'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta(CONTROL('f')), NUL, A_info_show_footnotes,
+ Meta(CONTROL('g')), NUL, A_info_abort_key,
+ Meta(TAB), NUL, A_info_move_to_prev_xref,
+ Meta(CONTROL('v')), NUL, A_info_scroll_other_window,
+ Meta('<'), NUL, A_info_beginning_of_node,
+ Meta('>'), NUL, A_info_end_of_node,
+ Meta('b'), NUL, A_info_backward_word,
+ Meta('f'), NUL, A_info_forward_word,
+ Meta('r'), NUL, A_info_move_to_window_line,
+ Meta('v'), NUL, A_info_scroll_backward_page_only,
+#if defined (NAMED_FUNCTIONS)
+ ESC, 'x', NUL, A_info_execute_command,
+ Meta('x'), NUL, A_info_execute_command,
+#endif /* NAMED_FUNCTIONS */
+
+ CONTROL('x'), CONTROL('b'), NUL, A_list_visited_nodes,
+ CONTROL('x'), CONTROL('c'), NUL, A_info_quit,
+ CONTROL('x'), CONTROL('f'), NUL, A_info_view_file,
+ CONTROL('x'), CONTROL('g'), NUL, A_info_abort_key,
+ CONTROL('x'), CONTROL('v'), NUL, A_info_view_file,
+ CONTROL('x'), '0', NUL, A_info_delete_window,
+ CONTROL('x'), '1', NUL, A_info_keep_one_window,
+ CONTROL('x'), '2', NUL, A_info_split_window,
+ CONTROL('x'), '^', NUL, A_info_grow_window,
+ CONTROL('x'), 'b', NUL, A_select_visited_node,
+ CONTROL('x'), 'k', NUL, A_info_kill_node,
+ CONTROL('x'), 'n', NUL, A_info_search_next,
+ CONTROL('x'), 'N', NUL, A_info_search_previous,
+ CONTROL('x'), 'o', NUL, A_info_next_window,
+ CONTROL('x'), 't', NUL, A_info_tile_windows,
+ CONTROL('x'), 'w', NUL, A_info_toggle_wrap,
+
+/* Arrow key bindings for info keymaps. It seems that some
+ terminals do not match their termcap entries, so it's best to just
+ define everything with both of the usual prefixes. */
+
+ SK_ESCAPE, SK_PAGE_UP, NUL, A_info_scroll_backward,
+ SK_ESCAPE, SK_PAGE_DOWN, NUL, A_info_scroll_forward,
+ '\033', 'O', 'A', NUL, A_info_prev_line,
+ '\033', '[', 'A', NUL, A_info_prev_line,
+ '\033', 'O', 'B', NUL, A_info_next_line,
+ '\033', '[', 'B', NUL, A_info_next_line,
+ SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_info_forward_char,
+ '\033', 'O', 'C', NUL, A_info_forward_char,
+ '\033', '[', 'C', NUL, A_info_forward_char,
+ SK_ESCAPE, SK_LEFT_ARROW, NUL, A_info_backward_char,
+ '\033', 'O', 'D', NUL, A_info_backward_char,
+ '\033', '[', 'D', NUL, A_info_backward_char,
+ SK_ESCAPE, SK_HOME, NUL, A_info_beginning_of_node,
+ SK_ESCAPE, SK_END, NUL, A_info_end_of_node,
+ SK_ESCAPE, SK_DELETE, NUL, A_info_scroll_backward,
+
+ ESC, SK_ESCAPE, SK_PAGE_UP, NUL, A_info_scroll_other_window_backward,
+ ESC, SK_ESCAPE, SK_PAGE_DOWN, NUL, A_info_scroll_other_window,
+ ESC, SK_ESCAPE, SK_UP_ARROW, NUL, A_info_prev_line,
+ ESC, '\033', 'O', 'A', NUL, A_info_prev_line,
+ ESC, '\033', '[', 'A', NUL, A_info_prev_line,
+ ESC, SK_ESCAPE, SK_DOWN_ARROW, NUL, A_info_next_line,
+ ESC, '\033', 'O', 'B', NUL, A_info_next_line,
+ ESC, '\033', '[', 'B', NUL, A_info_next_line,
+ ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_info_forward_word,
+ ESC, '\033', 'O', 'C', NUL, A_info_forward_word,
+ ESC, '\033', '[', 'C', NUL, A_info_forward_word,
+ ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL, A_info_backward_word,
+ ESC, '\033', 'O', 'D', NUL, A_info_backward_word,
+ ESC, '\033', '[', 'D', NUL, A_info_backward_word,
+
+ /* We want help to report q, not C-x C-c, etc. */
+ 'q', NUL, A_info_quit,
+ 'x', NUL, A_info_delete_window,
+ SPC, NUL, A_info_scroll_forward,
+ DEL, NUL, A_info_scroll_backward,
+ '{', NUL, A_info_search_previous,
+ '}', NUL, A_info_search_next,
+ CONTROL('g'), NUL, A_info_abort_key,
+ SK_ESCAPE, SK_UP_ARROW, NUL, A_info_prev_line,
+ SK_ESCAPE, SK_DOWN_ARROW, NUL, A_info_next_line,
+};
+
+
+static unsigned char default_emacs_like_ea_keys[] =
+{
+ 0, /* suppress-default-keybindings flag */
+ ESC, '0', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '1', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '2', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '3', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '4', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '5', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '6', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '7', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '8', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '9', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '-', NUL, A_info_add_digit_to_numeric_arg,
+ Meta('0'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('1'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('2'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('3'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('4'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('5'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('6'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('7'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('8'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('9'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('-'), NUL, A_info_add_digit_to_numeric_arg,
+ ESC, CONTROL('g'), NUL, A_ea_abort,
+ ESC, CONTROL('v'), NUL, A_ea_scroll_completions_window,
+ ESC, 'b', NUL, A_ea_backward_word,
+ ESC, 'd', NUL, A_ea_kill_word,
+ ESC, 'f', NUL, A_ea_forward_word,
+ ESC, 'y', NUL, A_ea_yank_pop,
+ ESC, '?', NUL, A_ea_possible_completions,
+ ESC, TAB, NUL, A_ea_tab_insert,
+ ESC, DEL, NUL, A_ea_backward_kill_word,
+ Meta(CONTROL('g')), NUL, A_ea_abort,
+ Meta(CONTROL('v')), NUL, A_ea_scroll_completions_window,
+ Meta('b'), NUL, A_ea_backward_word,
+ Meta('d'), NUL, A_ea_kill_word,
+ Meta('f'), NUL, A_ea_forward_word,
+ Meta('y'), NUL, A_ea_yank_pop,
+ Meta('?'), NUL, A_ea_possible_completions,
+ Meta(TAB), NUL, A_ea_tab_insert,
+ Meta(DEL), NUL, A_ea_backward_kill_word,
+ CONTROL('a'), NUL, A_ea_beg_of_line,
+ CONTROL('b'), NUL, A_ea_backward,
+ CONTROL('d'), NUL, A_ea_delete,
+ CONTROL('e'), NUL, A_ea_end_of_line,
+ CONTROL('f'), NUL, A_ea_forward,
+ CONTROL('g'), NUL, A_ea_abort,
+ CONTROL('h'), NUL, A_ea_rubout,
+/* CONTROL('k') */
+ SK_ESCAPE, SK_LITERAL, NUL, A_ea_kill_line,
+ CONTROL('l'), NUL, A_info_redraw_display,
+ CONTROL('q'), NUL, A_ea_quoted_insert,
+ CONTROL('t'), NUL, A_ea_transpose_chars,
+ CONTROL('u'), NUL, A_info_universal_argument,
+ CONTROL('y'), NUL, A_ea_yank,
+ LFD, NUL, A_ea_newline,
+ RET, NUL, A_ea_newline,
+ SPC, NUL, A_ea_complete,
+ TAB, NUL, A_ea_complete,
+ '?', NUL, A_ea_possible_completions,
+#ifdef __MSDOS__
+ /* PC users will lynch me if I don't give them their usual DEL
+ effect... */
+ DEL, NUL, A_ea_delete,
+#else
+ DEL, NUL, A_ea_rubout,
+#endif
+#if defined (NAMED_FUNCTIONS)
+ /* ESC, 'x', NUL, A_info_execute_command, */
+ /* Meta('x'), NUL, A_info_execute_command, */
+#endif /* NAMED_FUNCTIONS */
+ CONTROL('x'), 'o', NUL, A_info_next_window,
+ CONTROL('x'), DEL, NUL, A_ea_backward_kill_line,
+
+/* Arrow key bindings for echo area keymaps. It seems that some
+ terminals do not match their termcap entries, so it's best to just
+ define everything with both of the usual prefixes. */
+
+ SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_ea_forward,
+ '\033', 'O', 'C', NUL, A_ea_forward,
+ '\033', '[', 'C', NUL, A_ea_forward,
+ SK_ESCAPE, SK_LEFT_ARROW, NUL, A_ea_backward,
+ '\033', 'O', 'D', NUL, A_ea_backward,
+ '\033', '[', 'D', NUL, A_ea_backward,
+ ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_ea_forward_word,
+ ESC, '\033', 'O', 'C', NUL, A_ea_forward_word,
+ ESC, '\033', '[', 'C', NUL, A_ea_forward_word,
+ ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL, A_ea_backward_word,
+ ESC, '\033', 'O', 'D', NUL, A_ea_backward_word,
+ ESC, '\033', '[', 'D', NUL, A_ea_backward_word,
+#ifdef __MSDOS__
+ SK_ESCAPE, SK_DELETE, NUL, A_ea_delete,
+#else
+ SK_ESCAPE, SK_DELETE, NUL, A_ea_rubout,
+#endif
+ SK_ESCAPE, SK_HOME, NUL, A_ea_beg_of_line,
+ SK_ESCAPE, SK_END, NUL, A_ea_end_of_line,
+ ESC, SK_ESCAPE, SK_DELETE, NUL, A_ea_backward_kill_word,
+ CONTROL('x'), SK_ESCAPE, SK_DELETE, NUL,A_ea_backward_kill_line,
+};
+
+
+static unsigned char default_vi_like_info_keys[] =
+{
+ 0, /* suppress-default-keybindings flag */
+ '0', NUL, A_info_add_digit_to_numeric_arg,
+ '1', NUL, A_info_add_digit_to_numeric_arg,
+ '2', NUL, A_info_add_digit_to_numeric_arg,
+ '3', NUL, A_info_add_digit_to_numeric_arg,
+ '4', NUL, A_info_add_digit_to_numeric_arg,
+ '5', NUL, A_info_add_digit_to_numeric_arg,
+ '6', NUL, A_info_add_digit_to_numeric_arg,
+ '7', NUL, A_info_add_digit_to_numeric_arg,
+ '8', NUL, A_info_add_digit_to_numeric_arg,
+ '9', NUL, A_info_add_digit_to_numeric_arg,
+ '-', NUL, A_info_add_digit_to_numeric_arg,
+ TAB, NUL, A_info_move_to_next_xref,
+ LFD, NUL, A_info_down_line,
+ RET, NUL, A_info_down_line,
+ CONTROL('a'), NUL, A_info_beginning_of_line,
+ CONTROL('b'), NUL, A_info_scroll_backward_page_only,
+ CONTROL('d'), NUL, A_info_scroll_half_screen_down,
+ CONTROL('e'), NUL, A_info_down_line,
+ CONTROL('f'), NUL, A_info_scroll_forward_page_only,
+ CONTROL('k'), NUL, A_info_up_line,
+ CONTROL('l'), NUL, A_info_redraw_display,
+ CONTROL('n'), NUL, A_info_down_line,
+ CONTROL('p'), NUL, A_info_up_line,
+ CONTROL('r'), NUL, A_info_redraw_display,
+ CONTROL('s'), NUL, A_isearch_forward,
+ CONTROL('u'), NUL, A_info_scroll_half_screen_up,
+ CONTROL('v'), NUL, A_info_scroll_forward_page_only,
+ CONTROL('y'), NUL, A_info_up_line,
+ ',', NUL, A_info_next_index_match,
+ '/', NUL, A_info_search,
+ ESC, '0', NUL, A_info_last_menu_item,
+ ESC, '1', NUL, A_info_menu_digit,
+ ESC, '2', NUL, A_info_menu_digit,
+ ESC, '3', NUL, A_info_menu_digit,
+ ESC, '4', NUL, A_info_menu_digit,
+ ESC, '5', NUL, A_info_menu_digit,
+ ESC, '6', NUL, A_info_menu_digit,
+ ESC, '7', NUL, A_info_menu_digit,
+ ESC, '8', NUL, A_info_menu_digit,
+ ESC, '9', NUL, A_info_menu_digit,
+ Meta('0'), NUL, A_info_last_menu_item,
+ Meta('1'), NUL, A_info_menu_digit,
+ Meta('2'), NUL, A_info_menu_digit,
+ Meta('3'), NUL, A_info_menu_digit,
+ Meta('4'), NUL, A_info_menu_digit,
+ Meta('5'), NUL, A_info_menu_digit,
+ Meta('6'), NUL, A_info_menu_digit,
+ Meta('7'), NUL, A_info_menu_digit,
+ Meta('8'), NUL, A_info_menu_digit,
+ Meta('9'), NUL, A_info_menu_digit,
+ '<', NUL, A_info_first_node,
+ '>', NUL, A_info_last_node,
+ '?', NUL, A_info_search_backward,
+ '[', NUL, A_info_global_prev_node,
+ ']', NUL, A_info_global_next_node,
+ '\'', NUL, A_info_history_node,
+ 'b', NUL, A_info_scroll_backward,
+ 'd', NUL, A_info_scroll_half_screen_down,
+ 'e', NUL, A_info_down_line,
+ 'E', NUL, A_info_view_file,
+ ':', 'e', NUL, A_info_view_file,
+ 'f', NUL, A_info_scroll_forward_page_only,
+ 'F', NUL, A_info_scroll_forward_page_only,
+ 'g', NUL, A_info_first_node,
+ 'G', NUL, A_info_last_node,
+ 'h', NUL, A_info_get_help_window,
+ 'H', NUL, A_info_get_help_window,
+ 'i', NUL, A_info_index_search,
+ 'I', NUL, A_info_goto_invocation_node,
+ 'j', NUL, A_info_next_line,
+ 'k', NUL, A_info_prev_line,
+ 'l', NUL, A_info_history_node,
+ 'm', NUL, A_info_menu_item,
+ 'n', NUL, A_info_search_next,
+ 'N', NUL, A_info_search_previous,
+ 'O', NUL, A_info_goto_invocation_node,
+ 'p', NUL, A_info_prev_node,
+ 'Q', NUL, A_info_quit,
+ ':', 'q', NUL, A_info_quit,
+ ':', 'Q', NUL, A_info_quit,
+ 'Z', 'Z', NUL, A_info_quit,
+ 'r', NUL, A_info_redraw_display,
+ 'R', NUL, A_info_toggle_regexp,
+ 's', NUL, A_info_search,
+ 'S', NUL, A_info_search_case_sensitively,
+ 't', NUL, A_info_top_node,
+ 'u', NUL, A_info_scroll_half_screen_up,
+ 'w', NUL, A_info_scroll_backward_page_only_set_window,
+ 'y', NUL, A_info_up_line,
+ 'z', NUL, A_info_scroll_forward_page_only_set_window,
+ ESC, CONTROL('f'), NUL, A_info_show_footnotes,
+ ESC, CONTROL('g'), NUL, A_info_abort_key,
+ ESC, TAB, NUL, A_info_move_to_prev_xref,
+ ESC, SPC, NUL, A_info_scroll_forward_page_only,
+ ESC, CONTROL('v'), NUL, A_info_scroll_other_window,
+ ESC, '<', NUL, A_info_beginning_of_node,
+ ESC, '>', NUL, A_info_end_of_node,
+ ESC, '/', NUL, A_info_search,
+ ESC, '?', NUL, A_info_search_backward,
+ ESC, 'b', NUL, A_info_beginning_of_node,
+ ESC, 'd', NUL, A_info_dir_node,
+ ESC, 'e', NUL, A_info_end_of_node,
+ ESC, 'f', NUL, A_info_xref_item,
+ ESC, 'g', NUL, A_info_select_reference_this_line,
+ ESC, 'h', NUL, A_info_get_info_help_node,
+ ESC, 'm', NUL, A_info_menu_item,
+ ESC, 'n', NUL, A_info_search,
+ ESC, 'N', NUL, A_info_search_backward,
+ ESC, 'r', NUL, A_isearch_backward,
+ ESC, 's', NUL, A_isearch_forward,
+ ESC, 't', NUL, A_info_top_node,
+ ESC, 'v', NUL, A_info_scroll_backward_page_only,
+#if defined (NAMED_FUNCTIONS)
+ ESC, 'x', NUL, A_info_execute_command,
+ Meta('x'), NUL, A_info_execute_command,
+#endif /* NAMED_FUNCTIONS */
+ ESC, DEL, NUL, A_info_scroll_other_window_backward,
+ CONTROL('x'), CONTROL('b'), NUL, A_list_visited_nodes,
+ CONTROL('x'), CONTROL('c'), NUL, A_info_quit,
+ CONTROL('x'), CONTROL('f'), NUL, A_info_view_file,
+ CONTROL('x'), CONTROL('g'), NUL, A_info_abort_key,
+ CONTROL('x'), CONTROL('v'), NUL, A_info_view_file,
+ CONTROL('x'), LFD, NUL, A_info_select_reference_this_line,
+ CONTROL('x'), RET, NUL, A_info_select_reference_this_line,
+ CONTROL('x'), '0', NUL, A_info_delete_window,
+ CONTROL('x'), '1', NUL, A_info_keep_one_window,
+ CONTROL('x'), '2', NUL, A_info_split_window,
+ CONTROL('x'), '^', NUL, A_info_grow_window,
+ CONTROL('x'), 'b', NUL, A_select_visited_node,
+ CONTROL('x'), 'g', NUL, A_info_goto_node,
+ CONTROL('x'), 'i', NUL, A_info_index_search,
+ CONTROL('x'), 'I', NUL, A_info_goto_invocation_node,
+ CONTROL('x'), 'k', NUL, A_info_kill_node,
+ CONTROL('x'), 'n', NUL, A_info_next_node,
+ CONTROL('x'), 'o', NUL, A_info_next_window,
+ CONTROL('x'), 'O', NUL, A_info_goto_invocation_node,
+ CONTROL('x'), 'p', NUL, A_info_prev_node,
+ CONTROL('x'), 'r', NUL, A_info_xref_item,
+ CONTROL('x'), 't', NUL, A_info_tile_windows,
+ CONTROL('x'), 'u', NUL, A_info_up_node,
+ CONTROL('x'), 'w', NUL, A_info_toggle_wrap,
+ CONTROL('x'), ',', NUL, A_info_next_index_match,
+
+/* Arrow key bindings for info keymaps. It seems that some
+ terminals do not match their termcap entries, so it's best to just
+ define everything with both of the usual prefixes. */
+
+ SK_ESCAPE, SK_PAGE_UP, NUL, A_info_scroll_backward,
+ SK_ESCAPE, SK_PAGE_DOWN, NUL, A_info_scroll_forward,
+ '\033', 'O', 'A', NUL, A_info_up_line,
+ '\033', '[', 'A', NUL, A_info_up_line,
+ '\033', 'O', 'B', NUL, A_info_down_line,
+ '\033', '[', 'B', NUL, A_info_down_line,
+ SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_info_scroll_forward_page_only,
+ '\033', 'O', 'C', NUL, A_info_scroll_forward_page_only,
+ '\033', '[', 'C', NUL, A_info_scroll_forward_page_only,
+ SK_ESCAPE, SK_LEFT_ARROW, NUL, A_info_scroll_backward_page_only,
+ '\033', 'O', 'D', NUL, A_info_scroll_backward_page_only,
+ '\033', '[', 'D', NUL, A_info_scroll_backward_page_only,
+ SK_ESCAPE, SK_HOME, NUL, A_info_beginning_of_node,
+ SK_ESCAPE, SK_END, NUL, A_info_end_of_node,
+ ESC, SK_ESCAPE, SK_PAGE_DOWN, NUL, A_info_scroll_other_window,
+ ESC, SK_ESCAPE, SK_PAGE_UP, NUL, A_info_scroll_other_window_backward,
+ ESC, SK_ESCAPE, SK_DELETE, NUL, A_info_scroll_other_window_backward,
+ ESC, SK_ESCAPE, SK_UP_ARROW, NUL, A_info_prev_node,
+ ESC, '\033', 'O', 'A', NUL, A_info_prev_node,
+ ESC, '\033', '[', 'A', NUL, A_info_prev_node,
+ ESC, SK_ESCAPE, SK_DOWN_ARROW, NUL, A_info_next_node,
+ ESC, '\033', 'O', 'B', NUL, A_info_next_node,
+ ESC, '\033', '[', 'B', NUL, A_info_next_node,
+ ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_info_xref_item,
+ ESC, '\033', 'O', 'C', NUL, A_info_xref_item,
+ ESC, '\033', '[', 'C', NUL, A_info_xref_item,
+ ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL, A_info_beginning_of_node,
+ ESC, '\033', 'O', 'D', NUL, A_info_beginning_of_node,
+ ESC, '\033', '[', 'D', NUL, A_info_beginning_of_node,
+ CONTROL('x'), SK_ESCAPE, SK_DELETE, NUL,A_ea_backward_kill_line,
+
+ /* We want help to report q, not C-x C-c, etc. */
+ 'q', NUL, A_info_quit,
+ 'x', NUL, A_info_delete_window,
+ SPC, NUL, A_info_scroll_forward,
+ DEL, NUL, A_info_scroll_backward,
+ '{', NUL, A_info_search_previous,
+ '}', NUL, A_info_search_next,
+ CONTROL('g'), NUL, A_info_abort_key,
+ SK_ESCAPE, SK_UP_ARROW, NUL, A_info_up_line,
+ SK_ESCAPE, SK_DOWN_ARROW, NUL, A_info_down_line,
+};
+
+
+static unsigned char default_vi_like_ea_keys[] =
+{
+ 0, /* suppress-default-keybindings flag */
+ ESC, '1', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '2', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '3', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '4', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '5', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '6', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '7', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '8', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '9', NUL, A_info_add_digit_to_numeric_arg,
+ ESC, '-', NUL, A_info_add_digit_to_numeric_arg,
+ Meta('1'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('2'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('3'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('4'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('5'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('6'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('7'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('8'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('9'), NUL, A_info_add_digit_to_numeric_arg,
+ Meta('-'), NUL, A_info_add_digit_to_numeric_arg,
+ ESC, CONTROL('g'), NUL, A_ea_abort,
+ ESC, CONTROL('h'), NUL, A_ea_backward_kill_word,
+ ESC, CONTROL('v'), NUL, A_ea_scroll_completions_window,
+ ESC, '0', NUL, A_ea_beg_of_line,
+ ESC, '$', NUL, A_ea_end_of_line,
+ ESC, 'b', NUL, A_ea_backward_word,
+ ESC, 'd', NUL, A_ea_kill_word,
+ ESC, 'f', NUL, A_ea_forward_word,
+ ESC, 'h', NUL, A_ea_forward,
+ ESC, 'l', NUL, A_ea_backward,
+ ESC, 'w', NUL, A_ea_forward_word,
+ ESC, 'x', NUL, A_ea_delete,
+ ESC, 'X', NUL, A_ea_kill_word,
+ ESC, 'y', NUL, A_ea_yank_pop,
+ ESC, '?', NUL, A_ea_possible_completions,
+ ESC, TAB, NUL, A_ea_tab_insert,
+ ESC, DEL, NUL, A_ea_kill_word,
+ Meta(CONTROL('g')), NUL, A_ea_abort,
+ Meta(CONTROL('h')), NUL, A_ea_backward_kill_word,
+ Meta(CONTROL('v')), NUL, A_ea_scroll_completions_window,
+ Meta('0'), NUL, A_ea_beg_of_line,
+ Meta('$'), NUL, A_ea_end_of_line,
+ Meta('b'), NUL, A_ea_backward_word,
+ Meta('d'), NUL, A_ea_kill_word,
+ Meta('f'), NUL, A_ea_forward_word,
+ Meta('h'), NUL, A_ea_forward,
+ Meta('l'), NUL, A_ea_backward,
+ Meta('w'), NUL, A_ea_forward_word,
+ Meta('x'), NUL, A_ea_delete,
+ Meta('X'), NUL, A_ea_kill_word,
+ Meta('y'), NUL, A_ea_yank_pop,
+ Meta('?'), NUL, A_ea_possible_completions,
+ Meta(TAB), NUL, A_ea_tab_insert,
+ Meta(DEL), NUL, A_ea_kill_word,
+ CONTROL('a'), NUL, A_ea_beg_of_line,
+ CONTROL('b'), NUL, A_ea_backward,
+ CONTROL('d'), NUL, A_ea_delete,
+ CONTROL('e'), NUL, A_ea_end_of_line,
+ CONTROL('f'), NUL, A_ea_forward,
+ CONTROL('g'), NUL, A_ea_abort,
+ CONTROL('h'), NUL, A_ea_rubout,
+/* CONTROL('k') */
+ SK_ESCAPE, SK_LITERAL, NUL, A_ea_kill_line,
+ CONTROL('l'), NUL, A_info_redraw_display,
+ CONTROL('q'), NUL, A_ea_quoted_insert,
+ CONTROL('t'), NUL, A_ea_transpose_chars,
+ CONTROL('u'), NUL, A_ea_abort,
+ CONTROL('v'), NUL, A_ea_quoted_insert,
+ CONTROL('y'), NUL, A_ea_yank,
+ LFD, NUL, A_ea_newline,
+ RET, NUL, A_ea_newline,
+ SPC, NUL, A_ea_complete,
+ TAB, NUL, A_ea_complete,
+ '?', NUL, A_ea_possible_completions,
+#ifdef __MSDOS__
+ /* PC users will lynch me if I don't give them their usual DEL
+ effect... */
+ DEL, NUL, A_ea_delete,
+#else
+ DEL, NUL, A_ea_rubout,
+#endif
+ CONTROL('x'), 'o', NUL, A_info_next_window,
+ CONTROL('x'), DEL, NUL, A_ea_backward_kill_line,
+
+ /* Arrow key bindings for echo area keymaps. It seems that some
+ terminals do not match their termcap entries, so it's best to just
+ define everything with both of the usual prefixes. */
+
+ SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_ea_forward,
+ '\033', 'O', 'C', NUL, A_ea_forward,
+ '\033', '[', 'C', NUL, A_ea_forward,
+ SK_ESCAPE, SK_LEFT_ARROW, NUL, A_ea_backward,
+ '\033', 'O', 'D', NUL, A_ea_backward,
+ '\033', '[', 'D', NUL, A_ea_backward,
+ SK_ESCAPE, SK_HOME, NUL, A_ea_beg_of_line,
+ SK_ESCAPE, SK_END, NUL, A_ea_end_of_line,
+#ifdef __MSDOS__
+ SK_ESCAPE, SK_DELETE, NUL, A_ea_delete,
+#else
+ SK_DELETE, SK_DELETE, NUL, A_ea_rubout,
+#endif
+ ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL, A_ea_forward_word,
+ ESC, '\033', 'O', 'C', NUL, A_ea_forward_word,
+ ESC, '\033', '[', 'C', NUL, A_ea_forward_word,
+ ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL, A_ea_backward_word,
+ ESC, '\033', 'O', 'D', NUL, A_ea_backward_word,
+ ESC, '\033', '[', 'D', NUL, A_ea_backward_word,
+ ESC, SK_ESCAPE, SK_DELETE, NUL, A_ea_kill_word,
+ CONTROL('x'), SK_ESCAPE, SK_DELETE, NUL,A_ea_backward_kill_line,
+};
+
+
+static unsigned char *user_info_keys;
+static unsigned int user_info_keys_len;
+static unsigned char *user_ea_keys;
+static unsigned int user_ea_keys_len;
+static unsigned char *user_vars;
+static unsigned int user_vars_len;
+
+/*
+ * Return the size of a file, or 0 if the size can't be determined.
+ */
+static unsigned long
+filesize (int f)
+{
+ long pos = lseek(f, 0L, SEEK_CUR);
+ long sz = -1L;
+ if (pos != -1L)
+ {
+ sz = lseek(f, 0L, SEEK_END);
+ lseek(f, pos, SEEK_SET);
+ }
+ return sz == -1L ? 0L : sz;
+}
+
+/* Get an integer from a infokey file.
+ Integers are stored as two bytes, low order first, in radix INFOKEY_RADIX.
+ */
+static int
+getint (unsigned char **sp)
+{
+ int n;
+
+ if ( !((*sp)[0] < INFOKEY_RADIX && (*sp)[1] < INFOKEY_RADIX) )
+ return -1;
+ n = (*sp)[0] + (*sp)[1] * INFOKEY_RADIX;
+ *sp += 2;
+ return n;
+}
+
+
+/* Fetch the contents of the standard infokey file "$HOME/.info". Return
+ true if ok, false if not. */
+static int
+fetch_user_maps (void)
+{
+ char *filename = NULL;
+ char *homedir;
+ int f;
+ unsigned char *buf;
+ unsigned long len;
+ long nread;
+ unsigned char *p;
+ int n;
+
+ /* Find and open file. */
+ if ((filename = getenv("INFOKEY")) != NULL)
+ filename = xstrdup(filename);
+ else if ((homedir = getenv("HOME")) != NULL)
+ {
+ filename = xmalloc(strlen(homedir) + 2 + strlen(INFOKEY_FILE));
+ strcpy(filename, homedir);
+ strcat(filename, "/");
+ strcat(filename, INFOKEY_FILE);
+ }
+#ifdef __MSDOS__
+ /* Poor baby, she doesn't have a HOME... */
+ else
+ filename = xstrdup(INFOKEY_FILE); /* try current directory */
+#endif
+ if (filename == NULL || (f = open(filename, O_RDONLY)) == (-1))
+ {
+ if (filename && errno != ENOENT)
+ {
+ info_error(filesys_error_string(filename, errno),
+ NULL, NULL);
+ free(filename);
+ }
+ return 0;
+ }
+ SET_BINARY (f);
+
+ /* Ensure that the file is a reasonable size. */
+ len = filesize(f);
+ if (len < INFOKEY_NMAGIC + 2 || len > 100 * 1024)
+ {
+ /* Bad file (a valid file must have at least 9 chars, and
+ more than 100 KB is a problem). */
+ if (len < INFOKEY_NMAGIC + 2)
+ info_error(_("Ignoring invalid infokey file `%s' - too small"),
+ filename, NULL);
+ else
+ info_error(_("Ignoring invalid infokey file `%s' - too big"),
+ filename, NULL);
+ close(f);
+ free(filename);
+ return 0;
+ }
+
+ /* Read the file into a buffer. */
+ buf = xmalloc((int)len);
+ nread = read(f, buf, (unsigned int) len);
+ close(f);
+ if ((unsigned int) nread != len)
+ {
+ info_error(_("Error reading infokey file `%s' - short read"),
+ filename, NULL);
+ free(buf);
+ free(filename);
+ return 0;
+ }
+
+ /* Check the header, trailer, and version of the file to increase
+ our confidence that the contents are valid. */
+ if ( buf[0] != INFOKEY_MAGIC_S0
+ || buf[1] != INFOKEY_MAGIC_S1
+ || buf[2] != INFOKEY_MAGIC_S2
+ || buf[3] != INFOKEY_MAGIC_S3
+ || buf[len - 4] != INFOKEY_MAGIC_E0
+ || buf[len - 3] != INFOKEY_MAGIC_E1
+ || buf[len - 2] != INFOKEY_MAGIC_E2
+ || buf[len - 1] != INFOKEY_MAGIC_E3
+ )
+ {
+ info_error(_("Invalid infokey file `%s' (bad magic numbers) -- run infokey to update it"),
+ filename, NULL);
+ free(filename);
+ return 0;
+ }
+ if (len < INFOKEY_NMAGIC + strlen(VERSION) + 1
+ || strcmp(VERSION, (char *) (buf + 4)) != 0)
+ {
+ info_error
+ (_("Your infokey file `%s' is out of date -- run infokey to update it"),
+ filename, NULL);
+ free(filename);
+ return 0;
+ }
+
+ /* Extract the pieces. */
+ for (p = buf + 4 + strlen(VERSION) + 1;
+ (unsigned int) (p - buf) < len - 4;
+ p += n)
+ {
+ int s = *p++;
+
+ n = getint(&p);
+ if (n < 0 || (unsigned int) n > len - 4 - (p - buf))
+ {
+ info_error(_("Invalid infokey file `%s' (bad section length) -- run infokey to update it"),
+ filename, NULL);
+ free(filename);
+ return 0;
+ }
+
+ switch (s)
+ {
+ case INFOKEY_SECTION_INFO:
+ user_info_keys = p;
+ user_info_keys_len = n;
+ break;
+ case INFOKEY_SECTION_EA:
+ user_ea_keys = p;
+ user_ea_keys_len = n;
+ break;
+ case INFOKEY_SECTION_VAR:
+ user_vars = p;
+ user_vars_len = n;
+ break;
+ default:
+ info_error(_("Invalid infokey file `%s' (bad section code) -- run infokey to update it"),
+ filename, NULL);
+ free(filename);
+ return 0;
+ }
+ }
+
+ free(filename);
+ return 1;
+}
+
+/* Decode special key sequences from the infokey file. Return zero
+ if the key sequence includes special keys which the terminal
+ doesn't define.
+ */
+static int
+decode_keys(unsigned char *src, unsigned int slen,
+ unsigned char *dst, unsigned int dlen)
+{
+ unsigned char *s = src;
+ unsigned char *d = dst;
+
+#define To_dst(c) do { \
+ if ((unsigned int) (d - dst) < dlen) *d++ = (c); \
+} while (0)
+
+ while ((unsigned int) (s - src) < slen)
+ {
+ unsigned char c = ISMETA(*s) ? UNMETA(*s) : *s;
+
+ if (c == SK_ESCAPE)
+ {
+ char *t;
+ static char lit[] = { SK_ESCAPE, NUL };
+
+ switch ((unsigned int) (s + 1 - src) < slen ? s[1] : '\0')
+ {
+ case SK_RIGHT_ARROW: t = term_kr; break;
+ case SK_LEFT_ARROW: t = term_kl; break;
+ case SK_UP_ARROW: t = term_ku; break;
+ case SK_DOWN_ARROW: t = term_kd; break;
+ case SK_PAGE_UP: t = term_kP; break;
+ case SK_PAGE_DOWN: t = term_kN; break;
+ case SK_HOME: t = term_kh; break;
+ case SK_END: t = term_ke; break;
+ case SK_DELETE: t = term_kx; break;
+ case SK_INSERT: t = term_ki; break;
+ case SK_LITERAL:
+ default: t = lit; break;
+ }
+ if (t == NULL)
+ return 0;
+ while (*t)
+ To_dst(ISMETA(*s) ? Meta(*t++) : *t++);
+ s += 2;
+ }
+ else
+ {
+ if (ISMETA(*s))
+ To_dst(Meta(*s++));
+ else
+ To_dst(*s++);
+ }
+ }
+
+ To_dst('\0');
+
+ return 1;
+
+#undef To_dst
+
+}
+
+/* Convert an infokey file section to keymap bindings. Return false if
+ the default bindings are to be suppressed. */
+static int
+section_to_keymaps(Keymap map, unsigned char *table, unsigned int len)
+{
+ int stop;
+ unsigned char *p;
+ unsigned char *seq = NULL;
+ unsigned int seqlen = 0;
+ enum { getseq, gotseq, getaction } state = getseq;
+
+ stop = len > 0 ? table[0] : 0;
+
+ for (p = table + 1; (unsigned int) (p - table) < len; p++)
+ {
+ switch (state)
+ {
+ case getseq:
+ if (*p)
+ {
+ seq = p;
+ state = gotseq;
+ }
+ break;
+
+ case gotseq:
+ if (!*p)
+ {
+ seqlen = p - seq;
+ state = getaction;
+ }
+ break;
+
+ case getaction:
+ {
+ unsigned int action = *p;
+ unsigned char keyseq[256];
+ KEYMAP_ENTRY ke;
+
+ state = getseq;
+ /* If decode_keys returns zero, it
+ means that seq includes keys which
+ the terminal doesn't support, like
+ PageDown. In that case, don't bind
+ the key sequence. */
+ if (decode_keys(seq, seqlen, keyseq,
+ sizeof keyseq))
+ {
+ keyseq[sizeof keyseq - 1] = '\0';
+ ke.type = ISFUNC;
+ ke.function =
+ action < A_NCOMMANDS
+ ? &function_doc_array[action]
+ : NULL;
+ keymap_bind_keyseq(map,
+ (const char *) keyseq, &ke);
+ }
+ }
+ break;
+ }
+ }
+ if (state != getseq)
+ info_error(_("Bad data in infokey file -- some key bindings ignored"),
+ NULL, NULL);
+ return !stop;
+}
+
+/* Convert an infokey file section to variable settings.
+ */
+static void
+section_to_vars(unsigned char *table, unsigned int len)
+{
+ enum { getvar, gotvar, getval, gotval } state = getvar;
+ unsigned char *var = NULL;
+ unsigned char *val = NULL;
+ unsigned char *p;
+
+ for (p = table; (unsigned int) (p - table) < len; p++)
+ {
+ switch (state)
+ {
+ case getvar:
+ if (*p)
+ {
+ var = p;
+ state = gotvar;
+ }
+ break;
+
+ case gotvar:
+ if (!*p)
+ state = getval;
+ break;
+
+ case getval:
+ if (*p)
+ {
+ val = p;
+ state = gotval;
+ }
+ break;
+
+ case gotval:
+ if (!*p)
+ {
+ set_variable_to_value((char *) var, (char *) val);
+ state = getvar;
+ }
+ break;
+ }
+ }
+ if (state != getvar)
+ info_error(_("Bad data in infokey file -- some var settings ignored"),
+ NULL, NULL);
+}
+
+void
+initialize_info_keymaps (void)
+{
+ int i;
+ int suppress_info_default_bindings = 0;
+ int suppress_ea_default_bindings = 0;
+
+ if (!info_keymap)
+ {
+ info_keymap = keymap_make_keymap ();
+ echo_area_keymap = keymap_make_keymap ();
+ }
+
+ /* Bind the echo area insert routines. */
+ for (i = 0; i < 256; i++)
+ if (isprint (i))
+ echo_area_keymap[i].function = InfoCmd(ea_insert);
+
+ /* Get user-defined keys and variables. */
+ if (fetch_user_maps())
+ {
+ if (user_info_keys_len && user_info_keys[0])
+ suppress_info_default_bindings = 1;
+ if (user_ea_keys_len && user_ea_keys[0])
+ suppress_ea_default_bindings = 1;
+ }
+
+ /* Apply the default bindings, unless the user says to suppress
+ them. */
+ if (vi_keys_p)
+ {
+ if (!suppress_info_default_bindings)
+ section_to_keymaps(info_keymap, default_vi_like_info_keys,
+ sizeof(default_vi_like_info_keys));
+ if (!suppress_ea_default_bindings)
+ section_to_keymaps(echo_area_keymap, default_vi_like_ea_keys,
+ sizeof(default_vi_like_ea_keys));
+ }
+ else
+ {
+ if (!suppress_info_default_bindings)
+ section_to_keymaps(info_keymap, default_emacs_like_info_keys,
+ sizeof(default_emacs_like_info_keys));
+ if (!suppress_ea_default_bindings)
+ section_to_keymaps(echo_area_keymap, default_emacs_like_ea_keys,
+ sizeof(default_emacs_like_ea_keys));
+ }
+
+ /* If the user specified custom bindings, apply them on top of the
+ default ones. */
+ if (user_info_keys_len)
+ section_to_keymaps(info_keymap, user_info_keys, user_info_keys_len);
+
+ if (user_ea_keys_len)
+ section_to_keymaps(echo_area_keymap, user_ea_keys, user_ea_keys_len);
+
+ if (user_vars_len)
+ section_to_vars(user_vars, user_vars_len);
+}
+
+/* vim: set sw=2 cino={1s>2sn-s^-se-s: */