xref: /openbsd/gnu/usr.bin/texinfo/info/infomap.c (revision 898184e3)
1 /* infomap.c -- keymaps for Info.
2    $Id: infomap.c,v 1.5 2006/07/17 16:12:36 espie Exp $
3 
4    Copyright (C) 1993, 1997, 1998, 1999, 2001, 2002, 2003, 2004 Free Software
5    Foundation, Inc.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 
21    Written by Brian Fox (bfox@ai.mit.edu). */
22 
23 #include "info.h"
24 #include "infomap.h"
25 #include "funs.h"
26 #include "terminal.h"
27 
28 #if defined(INFOKEY)
29 #include "infokey.h"
30 #include "variables.h"
31 #endif /* INFOKEY */
32 
33 static int keymap_bind_keyseq (Keymap map, const char *keyseq,
34     KEYMAP_ENTRY *keyentry);
35 
36 /* Return a new keymap which has all the uppercase letters mapped to run
37    the function info_do_lowercase_version (). */
38 Keymap
39 keymap_make_keymap (void)
40 {
41   int i;
42   Keymap keymap;
43 
44   keymap = (Keymap)xmalloc (256 * sizeof (KEYMAP_ENTRY));
45 
46   for (i = 0; i < 256; i++)
47     {
48       keymap[i].type = ISFUNC;
49       keymap[i].function = (InfoCommand *)NULL;
50     }
51 
52   for (i = 'A'; i < ('Z' + 1); i++)
53     {
54       keymap[i].type = ISFUNC;
55 #if defined(INFOKEY)
56       keymap[Meta(i)].type = ISFUNC;
57       keymap[Meta(i)].function =
58 #endif /* INFOKEY */
59       keymap[i].function = InfoCmd(info_do_lowercase_version);
60     }
61 
62   return (keymap);
63 }
64 
65 #if defined(INFOKEY)
66 static FUNCTION_KEYSEQ *
67 find_function_keyseq (Keymap map, int c, Keymap rootmap)
68 {
69   FUNCTION_KEYSEQ *k;
70 
71   if (map[c].type != ISFUNC)
72     abort();
73   if (map[c].function == NULL)
74     return NULL;
75   for (k = map[c].function->keys; k; k = k->next)
76     {
77       const unsigned char *p;
78       Keymap m = rootmap;
79       if (k->map != rootmap)
80 	continue;
81       for (p = (unsigned char *) k->keyseq; *p && m[*p].type == ISKMAP; p++)
82 	m = (Keymap)m[*p].function;
83       if (*p != c || p[1])
84 	continue;
85       if (m[*p].type != ISFUNC)
86 	abort ();
87       break;
88     }
89   return k;
90 }
91 
92 static void
93 add_function_keyseq (InfoCommand *function,
94     const char *keyseq, Keymap rootmap)
95 {
96   FUNCTION_KEYSEQ *ks;
97 
98   if (function == NULL ||
99       function == InfoCmd(info_do_lowercase_version) ||
100       function == InfoCmd(ea_insert))
101     return;
102   ks = (FUNCTION_KEYSEQ *)xmalloc (sizeof(FUNCTION_KEYSEQ));
103   ks->next = function->keys;
104   ks->map = rootmap;
105   ks->keyseq = xstrdup(keyseq);
106   function->keys = ks;
107 }
108 
109 static void
110 remove_function_keyseq (InfoCommand *function,
111     const char *keyseq, Keymap rootmap)
112 {
113 
114   FUNCTION_KEYSEQ *k, *kp;
115 
116   if (function == NULL ||
117       function == InfoCmd(info_do_lowercase_version) ||
118       function == InfoCmd(ea_insert))
119     return;
120   for (kp = NULL, k = function->keys; k; kp = k, k = k->next)
121     if (k->map == rootmap && strcmp(k->keyseq, keyseq) == 0)
122       break;
123   if (!k)
124     abort ();
125   if (kp)
126     kp->next = k->next;
127   else
128     function->keys = k->next;
129 }
130 #endif /* INFOKEY */
131 
132 /* Return a new keymap which is a copy of MAP. */
133 Keymap
134 keymap_copy_keymap (Keymap map, Keymap rootmap, Keymap newroot)
135 {
136   int i;
137   Keymap keymap;
138 #if defined(INFOKEY)
139   FUNCTION_KEYSEQ *ks;
140 #endif /* INFOKEY */
141 
142   keymap = keymap_make_keymap ();
143   if (!newroot)
144     newroot = keymap;
145 
146   for (i = 0; i < 256; i++)
147     {
148       keymap[i].type = map[i].type;
149       switch (map[i].type)
150 	{
151 	case ISFUNC:
152 	  keymap[i].function = map[i].function;
153 #if defined(INFOKEY)
154 	  ks = find_function_keyseq (map, i, rootmap);
155 	  if (ks)
156 	    add_function_keyseq(map[i].function, ks->keyseq, newroot);
157 #endif /* INFOKEY */
158 	  break;
159 	case ISKMAP:
160 	  keymap[i].function = (InfoCommand *)keymap_copy_keymap
161             ((Keymap)map[i].function, rootmap, NULL);
162 	  break;
163 	}
164     }
165   return (keymap);
166 }
167 
168 /* Free the keymap and its descendants. */
169 void
170 keymap_discard_keymap (Keymap map, Keymap rootmap)
171 {
172   int i;
173 
174   if (!map)
175     return;
176   if (!rootmap)
177     rootmap = map;
178 
179   for (i = 0; i < 256; i++)
180     {
181 #if defined(INFOKEY)
182       FUNCTION_KEYSEQ *ks;
183 #endif /* INFOKEY */
184       switch (map[i].type)
185         {
186         case ISFUNC:
187 #if defined(INFOKEY)
188 	  ks = find_function_keyseq(map, i, rootmap);
189 	  if (ks)
190 	    remove_function_keyseq (map[i].function, ks->keyseq, rootmap);
191 #endif /* INFOKEY */
192           break;
193 
194         case ISKMAP:
195           keymap_discard_keymap ((Keymap)map[i].function, rootmap);
196           break;
197 
198         }
199     }
200   free(map);
201 }
202 
203 /* Conditionally bind key sequence. */
204 static int
205 keymap_bind_keyseq (Keymap map,
206     const char *keyseq, KEYMAP_ENTRY *keyentry)
207 {
208   Keymap m = map;
209   const unsigned char *s = (unsigned char *) keyseq;
210   int c;
211 
212   if (s == NULL || *s == '\0') return 0;
213 
214   while ((c = *s++) != '\0')
215     {
216 #if defined(INFOKEY)
217       FUNCTION_KEYSEQ *ks;
218 #endif /* INFOKEY */
219       switch (m[c].type)
220         {
221         case ISFUNC:
222 #if defined(INFOKEY)
223 	  ks = find_function_keyseq(m, c, map);
224 	  if (ks)
225 	    remove_function_keyseq (m[c].function, ks->keyseq, map);
226 #else /* !INFOKEY */
227           if (!(m[c].function == NULL || (
228                 m != map &&
229                 m[c].function == InfoCmd(info_do_lowercase_version))
230 	      ))
231             return 0;
232 #endif /* !INFOKEY */
233 
234           if (*s != '\0')
235             {
236               m[c].type = ISKMAP;
237               /* Here we are casting the Keymap pointer returned from
238                  keymap_make_keymap to an InfoCommand pointer.  Ugh.
239                  This makes the `function' structure garbage
240                  if it's actually interpreted as an InfoCommand.
241                  Should really be using a union, and taking steps to
242                  avoid the possible error.  */
243               m[c].function = (InfoCommand *)keymap_make_keymap ();
244             }
245           break;
246 
247         case ISKMAP:
248 #if defined(INFOKEY)
249 	  if (*s == '\0')
250 	    keymap_discard_keymap ((Keymap)m[c].function, map);
251 #else /* !INFOKEY */
252           if (*s == '\0')
253             return 0;
254 #endif
255           break;
256         }
257       if (*s != '\0')
258         {
259           m = (Keymap)m[c].function;
260         }
261       else
262         {
263 #if defined(INFOKEY)
264 	  add_function_keyseq (keyentry->function, keyseq, map);
265 #endif /* INFOKEY */
266           m[c] = *keyentry;
267         }
268     }
269 
270   return 1;
271 }
272 
273 /* Initialize the standard info keymaps. */
274 
275 Keymap info_keymap = NULL;
276 Keymap echo_area_keymap = NULL;
277 
278 #if !defined(INFOKEY)
279 
280 static void
281 initialize_emacs_like_keymaps ()
282 {
283   int i;
284   Keymap map;
285 
286   if (!info_keymap)
287     {
288       info_keymap = keymap_make_keymap ();
289       echo_area_keymap = keymap_make_keymap ();
290     }
291 
292   info_keymap[ESC].type = ISKMAP;
293   info_keymap[ESC].function = (InfoCommand *)keymap_make_keymap ();
294   info_keymap[Control ('x')].type = ISKMAP;
295   info_keymap[Control ('x')].function = (InfoCommand *)keymap_make_keymap ();
296 
297   /* Bind the echo area insert routines.  Let's make all characters
298      insertable by default, regardless of which character set we might
299      be using.  */
300   for (i = 0; i < 256; i++)
301     echo_area_keymap[i].function = ea_insert;
302 
303   echo_area_keymap[ESC].type = ISKMAP;
304   echo_area_keymap[ESC].function = (InfoCommand *) keymap_make_keymap ();
305   echo_area_keymap[Control ('x')].type = ISKMAP;
306   echo_area_keymap[Control ('x')].function
307     = (InfoCommand *) keymap_make_keymap ();
308 
309   /* Bind numeric arg functions for both echo area and info window maps. */
310   for (i = '0'; i < '9' + 1; i++)
311     {
312       ((Keymap) info_keymap[ESC].function)[i].function
313         = ((Keymap) echo_area_keymap[ESC].function)[i].function
314         = info_add_digit_to_numeric_arg;
315     }
316   ((Keymap) info_keymap[ESC].function)['-'].function =
317     ((Keymap) echo_area_keymap[ESC].function)['-'].function =
318       info_add_digit_to_numeric_arg;
319 
320   info_keymap['-'].function = info_add_digit_to_numeric_arg;
321 
322   /* Bind the echo area routines. */
323   map = echo_area_keymap;
324 
325   map[Control ('a')].function = ea_beg_of_line;
326   map[Control ('b')].function = ea_backward;
327   map[Control ('d')].function = ea_delete;
328   map[Control ('e')].function = ea_end_of_line;
329   map[Control ('f')].function = ea_forward;
330   map[Control ('g')].function = ea_abort;
331   map[Control ('h')].function = ea_rubout;
332   map[Control ('k')].function = ea_kill_line;
333   map[Control ('l')].function = info_redraw_display;
334   map[Control ('q')].function = ea_quoted_insert;
335   map[Control ('t')].function = ea_transpose_chars;
336   map[Control ('u')].function = info_universal_argument;
337   map[Control ('y')].function = ea_yank;
338 
339   map[LFD].function = ea_newline;
340   map[RET].function = ea_newline;
341   map[SPC].function = ea_complete;
342   map[TAB].function = ea_complete;
343   map['?'].function = ea_possible_completions;
344 #ifdef __MSDOS__
345   /* PC users will lynch me if I don't give them their usual DEL effect...  */
346   map[DEL].function = ea_delete;
347 #else
348   map[DEL].function = ea_rubout;
349 #endif
350 
351   /* Bind the echo area ESC keymap. */
352   map = (Keymap)echo_area_keymap[ESC].function;
353 
354   map[Control ('g')].function = ea_abort;
355   map[Control ('v')].function = ea_scroll_completions_window;
356   map['b'].function = ea_backward_word;
357   map['d'].function = ea_kill_word;
358   map['f'].function = ea_forward_word;
359 #if defined (NAMED_FUNCTIONS)
360   /* map['x'].function = info_execute_command; */
361 #endif /* NAMED_FUNCTIONS */
362   map['y'].function = ea_yank_pop;
363   map['?'].function = ea_possible_completions;
364   map[TAB].function = ea_tab_insert;
365   map[DEL].function = ea_backward_kill_word;
366 
367   /* Bind the echo area Control-x keymap. */
368   map = (Keymap)echo_area_keymap[Control ('x')].function;
369 
370   map['o'].function = info_next_window;
371   map[DEL].function = ea_backward_kill_line;
372 
373   /* Arrow key bindings for echo area keymaps.  It seems that some
374      terminals do not match their termcap entries, so it's best to just
375      define everything with both of the usual prefixes.  */
376   map = echo_area_keymap;
377   keymap_bind_keyseq (map, term_ku, &map[Control ('p')]); /* up */
378   keymap_bind_keyseq (map, "\033OA", &map[Control ('p')]);
379   keymap_bind_keyseq (map, "\033[A", &map[Control ('p')]);
380   keymap_bind_keyseq (map, term_kd, &map[Control ('n')]); /* down */
381   keymap_bind_keyseq (map, "\033OB", &map[Control ('n')]);
382   keymap_bind_keyseq (map, "\033[B", &map[Control ('n')]);
383   keymap_bind_keyseq (map, term_kr, &map[Control ('f')]); /* right */
384   keymap_bind_keyseq (map, "\033OC", &map[Control ('f')]);
385   keymap_bind_keyseq (map, "\033[C", &map[Control ('f')]);
386   keymap_bind_keyseq (map, term_kl, &map[Control ('b')]); /* left */
387   keymap_bind_keyseq (map, "\033OD", &map[Control ('b')]);
388   keymap_bind_keyseq (map, "\033[D", &map[Control ('b')]);
389   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
390   keymap_bind_keyseq (map, term_kh, &map[Control ('a')]); /* home */
391   keymap_bind_keyseq (map, term_ke, &map[Control ('e')]); /* end */
392 
393   map = (Keymap)echo_area_keymap[ESC].function;
394   keymap_bind_keyseq (map, term_kl, &map['b']); /* left */
395   keymap_bind_keyseq (map, "\033OA", &map['b']);
396   keymap_bind_keyseq (map, "\033[A", &map['b']);
397   keymap_bind_keyseq (map, term_kr, &map['f']); /* right */
398   keymap_bind_keyseq (map, "\033OB", &map['f']);
399   keymap_bind_keyseq (map, "\033[B", &map['f']);
400   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
401 
402   map = (Keymap)echo_area_keymap[Control ('x')].function;
403   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
404 
405   /* Bind commands for Info window keymaps. */
406   map = info_keymap;
407   map[TAB].function = info_move_to_next_xref;
408   map[LFD].function = info_select_reference_this_line;
409   map[RET].function = info_select_reference_this_line;
410   map[SPC].function = info_scroll_forward;
411   map[Control ('a')].function = info_beginning_of_line;
412   map[Control ('b')].function = info_backward_char;
413   map[Control ('e')].function = info_end_of_line;
414   map[Control ('f')].function = info_forward_char;
415   map[Control ('g')].function = info_abort_key;
416   map[Control ('h')].function = info_get_help_window;
417   map[Control ('l')].function = info_redraw_display;
418   map[Control ('n')].function = info_next_line;
419   map[Control ('p')].function = info_prev_line;
420   map[Control ('r')].function = isearch_backward;
421   map[Control ('s')].function = isearch_forward;
422   map[Control ('u')].function = info_universal_argument;
423   map[Control ('v')].function = info_scroll_forward_page_only;
424   map[','].function = info_next_index_match;
425   map['/'].function = info_search;
426 
427   for (i = '1'; i < '9' + 1; i++)
428     map[i].function = info_menu_digit;
429   map['0'].function = info_last_menu_item;
430 
431   map['<'].function = info_first_node;
432   map['>'].function = info_last_node;
433   map['?'].function = info_get_help_window;
434   map['['].function = info_global_prev_node;
435   map[']'].function = info_global_next_node;
436 
437   map['b'].function = info_beginning_of_node;
438   map['d'].function = info_dir_node;
439   map['e'].function = info_end_of_node;
440   map['f'].function = info_xref_item;
441   map['g'].function = info_goto_node;
442   map['G'].function = info_menu_sequence;
443   map['h'].function = info_get_info_help_node;
444   map['i'].function = info_index_search;
445   map['I'].function = info_goto_invocation_node;
446   map['l'].function = info_history_node;
447   map['m'].function = info_menu_item;
448   map['n'].function = info_next_node;
449   map['O'].function = info_goto_invocation_node;
450   map['p'].function = info_prev_node;
451   map['q'].function = info_quit;
452   map['r'].function = info_xref_item;
453   map['s'].function = info_search;
454   map['S'].function = info_search_case_sensitively;
455   map['t'].function = info_top_node;
456   map['u'].function = info_up_node;
457   map[DEL].function = info_scroll_backward;
458 
459   /* Bind members in the ESC map for Info windows. */
460   map = (Keymap)info_keymap[ESC].function;
461   map[Control ('f')].function = info_show_footnotes;
462   map[Control ('g')].function = info_abort_key;
463   map[TAB].function = info_move_to_prev_xref;
464   map[Control ('v')].function = info_scroll_other_window;
465   map['<'].function = info_beginning_of_node;
466   map['>'].function = info_end_of_node;
467   map['b'].function = info_backward_word;
468   map['f'].function = info_forward_word;
469   map['r'].function = info_move_to_window_line;
470   map['v'].function = info_scroll_backward_page_only;
471 #if defined (NAMED_FUNCTIONS)
472   map['x'].function = info_execute_command;
473 #endif /* NAMED_FUNCTIONS */
474   map[DEL].function = info_scroll_other_window_backward;
475 
476   /* Bind members in the Control-X map for Info windows. */
477   map = (Keymap)info_keymap[Control ('x')].function;
478 
479   map[Control ('b')].function = list_visited_nodes;
480   map[Control ('c')].function = info_quit;
481   map[Control ('f')].function = info_view_file;
482   map[Control ('g')].function = info_abort_key;
483   map[Control ('v')].function = info_view_file;
484   map['0'].function = info_delete_window;
485   map['1'].function = info_keep_one_window;
486   map['2'].function = info_split_window;
487   map['^'].function = info_grow_window;
488   map['b'].function = select_visited_node;
489   map['k'].function = info_kill_node;
490   map['n'].function = info_search_next;
491   map['N'].function = info_search_previous;
492   map['o'].function = info_next_window;
493   map['t'].function = info_tile_windows;
494   map['w'].function = info_toggle_wrap;
495 
496   /* Arrow key bindings for Info windows keymap. */
497   map = info_keymap;
498   keymap_bind_keyseq (map, term_kN, &map[Control ('v')]); /* pagedown */
499   keymap_bind_keyseq (map, term_ku, &map[Control ('p')]); /* up */
500   keymap_bind_keyseq (map, "\033OA", &map[Control ('p')]);
501   keymap_bind_keyseq (map, "\033[A", &map[Control ('p')]);
502   keymap_bind_keyseq (map, term_kd, &map[Control ('n')]); /* down */
503   keymap_bind_keyseq (map, "\033OB", &map[Control ('n')]);
504   keymap_bind_keyseq (map, "\033[B", &map[Control ('n')]);
505   keymap_bind_keyseq (map, term_kr, &map[Control ('f')]); /* right */
506   keymap_bind_keyseq (map, "\033OC", &map[Control ('f')]);
507   keymap_bind_keyseq (map, "\033[C", &map[Control ('f')]);
508   keymap_bind_keyseq (map, term_kl, &map[Control ('b')]); /* left */
509   keymap_bind_keyseq (map, "\033OD", &map[Control ('b')]);
510   keymap_bind_keyseq (map, "\033[D", &map[Control ('b')]);
511   keymap_bind_keyseq (map, term_kh, &map['b']);	/* home */
512   keymap_bind_keyseq (map, term_ke, &map['e']);	/* end */
513   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
514 
515   map = (Keymap)info_keymap[ESC].function;
516   keymap_bind_keyseq (map, term_kl, &map['b']); /* left */
517   keymap_bind_keyseq (map, "\033OA", &map['b']);
518   keymap_bind_keyseq (map, "\033[A", &map['b']);
519   keymap_bind_keyseq (map, term_kr, &map['f']); /* right */
520   keymap_bind_keyseq (map, "\033OB", &map['f']);
521   keymap_bind_keyseq (map, "\033[B", &map['f']);
522   keymap_bind_keyseq (map, term_kN, &map[Control ('v')]); /* pagedown */
523   keymap_bind_keyseq (map, term_kP, &map[DEL]); /* pageup */
524   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
525 
526   /* The alternative to this definition of a `main map' key in the
527      `ESC map' section, is something like:
528     keymap_bind_keyseq (map, term_kP, &((KeyMap)map[ESC].function).map['v']);
529   */
530   keymap_bind_keyseq (info_keymap/*sic*/, term_kP, &map['v']); /* pageup */
531 }
532 
533 static void
534 initialize_vi_like_keymaps ()
535 {
536   int i;
537   Keymap map;
538 
539   if (!info_keymap)
540     {
541       info_keymap = keymap_make_keymap ();
542       echo_area_keymap = keymap_make_keymap ();
543     }
544 
545   info_keymap[ESC].type = ISKMAP;
546   info_keymap[ESC].function = (InfoCommand *)keymap_make_keymap ();
547   info_keymap[Control ('x')].type = ISKMAP;
548   info_keymap[Control ('x')].function = (InfoCommand *)keymap_make_keymap ();
549 
550   /* Bind the echo area insert routines. */
551   for (i = 0; i < 256; i++)
552     echo_area_keymap[i].function = ea_insert;
553 
554   echo_area_keymap[ESC].type = ISKMAP;
555   echo_area_keymap[ESC].function = (InfoCommand *)keymap_make_keymap ();
556   echo_area_keymap[Control ('x')].type = ISKMAP;
557   echo_area_keymap[Control ('x')].function =
558     (InfoCommand *)keymap_make_keymap ();
559 
560   /* Bind numeric arg functions for both echo area and info window maps. */
561   for (i = '0'; i < '9' + 1; i++)
562     {
563       info_keymap[i].function =
564         ((Keymap) echo_area_keymap[ESC].function)[i].function =
565 	info_add_digit_to_numeric_arg;
566     }
567   info_keymap['-'].function =
568     ((Keymap) echo_area_keymap[ESC].function)['-'].function =
569       info_add_digit_to_numeric_arg;
570 
571   /* Bind the echo area routines. */
572   map = echo_area_keymap;
573 
574   map[Control ('a')].function = ea_beg_of_line;
575   map[Control ('b')].function = ea_backward;
576   map[Control ('d')].function = ea_delete;
577   map[Control ('e')].function = ea_end_of_line;
578   map[Control ('f')].function = ea_forward;
579   map[Control ('g')].function = ea_abort;
580   map[Control ('h')].function = ea_rubout;
581   map[Control ('k')].function = ea_kill_line;
582   map[Control ('l')].function = info_redraw_display;
583   map[Control ('q')].function = ea_quoted_insert;
584   map[Control ('t')].function = ea_transpose_chars;
585   map[Control ('u')].function = ea_abort;
586   map[Control ('v')].function = ea_quoted_insert;
587   map[Control ('y')].function = ea_yank;
588 
589   map[LFD].function = ea_newline;
590   map[RET].function = ea_newline;
591   map[SPC].function = ea_complete;
592   map[TAB].function = ea_complete;
593   map['?'].function = ea_possible_completions;
594 #ifdef __MSDOS__
595   /* PC users will lynch me if I don't give them their usual DEL effect...  */
596   map[DEL].function = ea_delete;
597 #else
598   map[DEL].function = ea_rubout;
599 #endif
600 
601   /* Bind the echo area ESC keymap. */
602   map = (Keymap)echo_area_keymap[ESC].function;
603 
604   map[Control ('g')].function = ea_abort;
605   map[Control ('h')].function = ea_backward_kill_word;
606   map[Control ('v')].function = ea_scroll_completions_window;
607   map['0'].function = ea_beg_of_line;
608   map['$'].function = ea_end_of_line;
609   map['b'].function = ea_backward_word;
610   map['d'].function = ea_kill_word;
611   map['f'].function = ea_forward_word;
612   map['h'].function = ea_backward;
613   map['l'].function = ea_forward;
614   map['w'].function = ea_forward_word;
615   map['x'].function = ea_delete;
616   map['X'].function = ea_kill_word;
617   map['y'].function = ea_yank_pop;
618   map['?'].function = ea_possible_completions;
619   map[TAB].function = ea_tab_insert;
620   map[DEL].function = ea_kill_word;
621 
622   /* Bind the echo area Control-x keymap. */
623   map = (Keymap)echo_area_keymap[Control ('x')].function;
624 
625   map['o'].function = info_next_window;
626   map[DEL].function = ea_backward_kill_line;
627 
628   /* Arrow key bindings for echo area keymaps.  It seems that some
629      terminals do not match their termcap entries, so it's best to just
630      define everything with both of the usual prefixes.  */
631   map = echo_area_keymap;
632   keymap_bind_keyseq (map, term_ku, &map[Control ('p')]); /* up */
633   keymap_bind_keyseq (map, "\033OA", &map[Control ('p')]);
634   keymap_bind_keyseq (map, "\033[A", &map[Control ('p')]);
635   keymap_bind_keyseq (map, term_kd, &map[Control ('n')]); /* down */
636   keymap_bind_keyseq (map, "\033OB", &map[Control ('n')]);
637   keymap_bind_keyseq (map, "\033[B", &map[Control ('n')]);
638   keymap_bind_keyseq (map, term_kr, &map[Control ('f')]); /* right */
639   keymap_bind_keyseq (map, "\033OC", &map[Control ('f')]);
640   keymap_bind_keyseq (map, "\033[C", &map[Control ('f')]);
641   keymap_bind_keyseq (map, term_kl, &map[Control ('b')]); /* left */
642   keymap_bind_keyseq (map, "\033OD", &map[Control ('b')]);
643   keymap_bind_keyseq (map, "\033[D", &map[Control ('b')]);
644   keymap_bind_keyseq (map, term_kh, &map[Control ('a')]); /* home */
645   keymap_bind_keyseq (map, term_ke, &map[Control ('e')]); /* end */
646   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
647 
648   map = (Keymap)echo_area_keymap[ESC].function;
649   keymap_bind_keyseq (map, term_kl, &map['b']); /* left */
650   keymap_bind_keyseq (map, "\033OA", &map['b']);
651   keymap_bind_keyseq (map, "\033[A", &map['b']);
652   keymap_bind_keyseq (map, term_kr, &map['f']); /* right */
653   keymap_bind_keyseq (map, "\033OB", &map['f']);
654   keymap_bind_keyseq (map, "\033[B", &map['f']);
655   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
656 
657   map = (Keymap)echo_area_keymap[Control ('x')].function;
658   keymap_bind_keyseq (map, term_kD, &map[DEL]);
659 
660   /* Bind commands for Info window keymaps. */
661   map = info_keymap;
662   map[TAB].function = info_move_to_next_xref;
663   map[LFD].function = info_down_line;
664   map[RET].function = info_down_line;
665   map[SPC].function = info_scroll_forward;
666   map[Control ('a')].function = info_beginning_of_line;
667   map[Control ('b')].function = info_scroll_backward_page_only;
668   map[Control ('d')].function = info_scroll_half_screen_down;
669   map[Control ('e')].function = info_down_line;
670   map[Control ('f')].function = info_scroll_forward_page_only;
671   map[Control ('g')].function = info_abort_key;
672   map[Control ('k')].function = info_up_line;
673   map[Control ('l')].function = info_redraw_display;
674   map[Control ('n')].function = info_down_line;
675   map[Control ('p')].function = info_up_line;
676   map[Control ('r')].function = info_redraw_display;
677   map[Control ('s')].function = isearch_forward;
678   map[Control ('u')].function = info_scroll_half_screen_up;
679   map[Control ('v')].function = info_scroll_forward_page_only;
680   map[Control ('y')].function = info_up_line;
681   map[','].function = info_next_index_match;
682   map['/'].function = info_search;
683 
684   for (i = '1'; i < '9' + 1; i++)
685     ((Keymap) info_keymap[ESC].function)[i].function = info_menu_digit;
686   ((Keymap) info_keymap[ESC].function)['0'].function = info_last_menu_item;
687 
688   map['<'].function = info_first_node;
689   map['>'].function = info_last_node;
690   map['?'].function = info_search_backward;
691   map['['].function = info_global_prev_node;
692   map[']'].function = info_global_next_node;
693   map['\''].function = info_history_node;
694 
695   map['b'].function = info_scroll_backward;
696   map['d'].function = info_scroll_half_screen_down;
697   map['e'].function = info_down_line;
698   map['E'].function = info_view_file;
699   map['f'].function = info_scroll_forward_page_only;
700   map['F'].function = info_scroll_forward_page_only;
701   map['g'].function = info_first_node;
702   map['G'].function = info_last_node;
703   map['h'].function = info_get_help_window;
704   map['H'].function = info_get_help_window;
705   map['i'].function = info_index_search;
706   map['I'].function = info_goto_invocation_node;
707   map['j'].function = info_next_line;
708   map['k'].function = info_prev_line;
709   map['l'].function = info_history_node;
710   map['m'].function = info_menu_item;
711   map['n'].function = info_search_next;
712   map['N'].function = info_search_previous;
713   map['O'].function = info_goto_invocation_node;
714   map['p'].function = info_prev_node;
715   map['q'].function = info_quit;
716   map['Q'].function = info_quit;
717   map['r'].function = info_redraw_display;
718   map['R'].function = info_redraw_display;
719   map['s'].function = info_search;
720   map['S'].function = info_search_case_sensitively;
721   map['t'].function = info_top_node;
722   map['u'].function = info_scroll_half_screen_up;
723   map['w'].function = info_scroll_backward_page_only_set_window;
724   map['y'].function = info_up_line;
725   map['z'].function = info_scroll_forward_page_only_set_window;
726   map['Z'].function = NULL;	/* unbind, so it works to bind "ZZ" below */
727   map[DEL].function = info_scroll_backward;
728   keymap_bind_keyseq (map, term_kD, &map[DEL]);
729   keymap_bind_keyseq (map, ":q", &map['q']);
730   keymap_bind_keyseq (map, ":Q", &map['q']);
731   keymap_bind_keyseq (map, "ZZ", &map['q']);
732 
733   /* Bind members in the ESC map for Info windows. */
734   map = (Keymap)info_keymap[ESC].function;
735   map[Control ('f')].function = info_show_footnotes;
736   map[Control ('g')].function = info_abort_key;
737   map[TAB].function = info_move_to_prev_xref;
738   map[SPC].function = info_scroll_forward_page_only;
739   map[Control ('v')].function = info_scroll_other_window;
740   map['<'].function = info_beginning_of_node;
741   map['>'].function = info_end_of_node;
742   map['/'].function = info_search;
743   map['?'].function = info_search_backward;
744   map['b'].function = info_beginning_of_node;
745   map['d'].function = info_dir_node;
746   map['e'].function = info_end_of_node;
747   map['f'].function = info_xref_item;
748   map['g'].function = info_select_reference_this_line;
749   map['h'].function = info_get_info_help_node;
750   map['m'].function = info_menu_item;
751   map['n'].function = info_search;
752   map['N'].function = info_search_backward;
753   map['r'].function = isearch_backward;
754   map['s'].function = isearch_forward;
755   map['t'].function = info_top_node;
756   map['v'].function = info_scroll_backward_page_only;
757 #if defined (NAMED_FUNCTIONS)
758   map['x'].function = info_execute_command;
759 #endif /* NAMED_FUNCTIONS */
760   map[DEL].function = info_scroll_other_window_backward;
761 
762   /* Bind members in the Control-X map for Info windows. */
763   map = (Keymap)info_keymap[Control ('x')].function;
764 
765   map[Control ('b')].function = list_visited_nodes;
766   map[Control ('c')].function = info_quit;
767   map[Control ('f')].function = info_view_file;
768   map[Control ('g')].function = info_abort_key;
769   map[Control ('v')].function = info_view_file;
770   map[LFD].function = info_select_reference_this_line;
771   map[RET].function = info_select_reference_this_line;
772   map['0'].function = info_delete_window;
773   map['1'].function = info_keep_one_window;
774   map['2'].function = info_split_window;
775   map['^'].function = info_grow_window;
776   map['b'].function = select_visited_node;
777   map['g'].function = info_goto_node;
778   map['i'].function = info_index_search;
779   map['I'].function = info_goto_invocation_node;
780   map['k'].function = info_kill_node;
781   map['n'].function = info_next_node;
782   map['o'].function = info_next_window;
783   map['O'].function = info_goto_invocation_node;
784   map['p'].function = info_prev_node;
785   map['r'].function = info_xref_item;
786   map['t'].function = info_tile_windows;
787   map['u'].function = info_up_node;
788   map['w'].function = info_toggle_wrap;
789   map[','].function = info_next_index_match;
790   keymap_bind_keyseq (info_keymap, ":e", &map[Control ('v')]);
791 
792   /* Arrow key bindings for Info windows keymap. */
793   map = info_keymap;
794   keymap_bind_keyseq (map, term_kN, &map[Control ('v')]); /* pagedown */
795   keymap_bind_keyseq (map, term_ku, &map[Control ('p')]); /* up */
796   keymap_bind_keyseq (map, "\033OA", &map[Control ('p')]);
797   keymap_bind_keyseq (map, "\033[A", &map[Control ('p')]);
798   keymap_bind_keyseq (map, term_kd, &map[Control ('n')]); /* down */
799   keymap_bind_keyseq (map, "\033OB", &map[Control ('n')]);
800   keymap_bind_keyseq (map, "\033[B", &map[Control ('n')]);
801   keymap_bind_keyseq (map, term_kr, &map[Control ('f')]); /* right */
802   keymap_bind_keyseq (map, "\033OC", &map[Control ('f')]);
803   keymap_bind_keyseq (map, "\033[C", &map[Control ('f')]);
804   keymap_bind_keyseq (map, term_kl, &map[Control ('b')]); /* left */
805   keymap_bind_keyseq (map, "\033OD", &map[Control ('b')]);
806   keymap_bind_keyseq (map, "\033[D", &map[Control ('b')]);
807   keymap_bind_keyseq (map, term_kh, &map['b']);	/* home */
808   keymap_bind_keyseq (map, term_ke, &map['e']);	/* end */
809 
810   map = (Keymap)info_keymap[ESC].function;
811   keymap_bind_keyseq (map, term_kl, &map['b']); /* left */
812   keymap_bind_keyseq (map, "\033OA", &map['b']);
813   keymap_bind_keyseq (map, "\033[A", &map['b']);
814   keymap_bind_keyseq (map, term_kr, &map['f']); /* right */
815   keymap_bind_keyseq (map, "\033OB", &map['f']);
816   keymap_bind_keyseq (map, "\033[B", &map['f']);
817   keymap_bind_keyseq (map, term_kN, &map[Control ('v')]); /* pagedown */
818   keymap_bind_keyseq (map, term_kP, &map[DEL]); /* pageup */
819   keymap_bind_keyseq (map, term_kD, &map[DEL]);	/* delete */
820 
821   /* The alternative to this definition of a `main map' key in the
822      `ESC map' section, is something like:
823     keymap_bind_keyseq (map, term_kP, &((KeyMap)map[ESC].function).map['v']);
824   */
825   keymap_bind_keyseq (info_keymap/*sic*/, term_kP, &map['v']); /* pageup */
826 }
827 
828 void
829 initialize_info_keymaps ()
830 {
831   if (vi_keys_p)
832     initialize_vi_like_keymaps ();
833   else
834     initialize_emacs_like_keymaps ();
835 }
836 
837 #else /* defined(INFOKEY) */
838 
839 /* Make sure that we don't have too many command codes defined. */
840 
841 #if A_NCOMMANDS > A_MAX_COMMAND + 1
842 #error "too many commands defined"
843 #endif
844 
845 /* Initialize the keymaps from the .info keymap file. */
846 
847 #define NUL	'\0'
848 
849 static unsigned char default_emacs_like_info_keys[] =
850 {
851 	0,	/* suppress-default-keybindings flag */
852 	TAB, NUL,			A_info_move_to_next_xref,
853 	LFD, NUL,			A_info_select_reference_this_line,
854 	RET, NUL,			A_info_select_reference_this_line,
855 	SPC, NUL,			A_info_scroll_forward,
856 	CONTROL('a'), NUL,		A_info_beginning_of_line,
857 	CONTROL('b'), NUL,		A_info_backward_char,
858 	CONTROL('e'), NUL,		A_info_end_of_line,
859 	CONTROL('f'), NUL,		A_info_forward_char,
860 	CONTROL('g'), NUL,		A_info_abort_key,
861 	CONTROL('h'), NUL,		A_info_get_help_window,
862 	CONTROL('l'), NUL,		A_info_redraw_display,
863 	CONTROL('n'), NUL,		A_info_next_line,
864 	CONTROL('p'), NUL,		A_info_prev_line,
865 	CONTROL('r'), NUL,		A_isearch_backward,
866 	CONTROL('s'), NUL,		A_isearch_forward,
867 	CONTROL('u'), NUL,		A_info_universal_argument,
868 	CONTROL('v'), NUL,		A_info_scroll_forward_page_only,
869 	',', NUL,			A_info_next_index_match,
870 	'/', NUL,			A_info_search,
871 	'0', NUL,			A_info_last_menu_item,
872 	'1', NUL,			A_info_menu_digit,
873 	'2', NUL,			A_info_menu_digit,
874 	'3', NUL,			A_info_menu_digit,
875 	'4', NUL,			A_info_menu_digit,
876 	'5', NUL,			A_info_menu_digit,
877 	'6', NUL,			A_info_menu_digit,
878 	'7', NUL,			A_info_menu_digit,
879 	'8', NUL,			A_info_menu_digit,
880 	'9', NUL,			A_info_menu_digit,
881 	'<', NUL,			A_info_first_node,
882 	'>', NUL,			A_info_last_node,
883 	'?', NUL,			A_info_get_help_window,
884 	'[', NUL,			A_info_global_prev_node,
885 	']', NUL,			A_info_global_next_node,
886 	'b', NUL,			A_info_beginning_of_node,
887 	'd', NUL,			A_info_dir_node,
888 	'e', NUL,			A_info_end_of_node,
889 	'f', NUL,			A_info_xref_item,
890 	'g', NUL,			A_info_goto_node,
891 	'G', NUL,			A_info_menu_sequence,
892 	'h', NUL,			A_info_get_info_help_node,
893 	'i', NUL,			A_info_index_search,
894 	'l', NUL,			A_info_history_node,
895 	'm', NUL,			A_info_menu_item,
896 	'n', NUL,			A_info_next_node,
897 	'O', NUL,			A_info_goto_invocation_node,
898 	'p', NUL,			A_info_prev_node,
899 	'q', NUL,			A_info_quit,
900 	'r', NUL,			A_info_xref_item,
901 	's', NUL,			A_info_search,
902 	'S', NUL,			A_info_search_case_sensitively,
903 	't', NUL,			A_info_top_node,
904 	'u', NUL,			A_info_up_node,
905 	DEL, NUL,			A_info_scroll_backward,
906 	ESC, '0', NUL,			A_info_add_digit_to_numeric_arg,
907 	ESC, '1', NUL,			A_info_add_digit_to_numeric_arg,
908 	ESC, '2', NUL,			A_info_add_digit_to_numeric_arg,
909 	ESC, '3', NUL,			A_info_add_digit_to_numeric_arg,
910 	ESC, '4', NUL,			A_info_add_digit_to_numeric_arg,
911 	ESC, '5', NUL,			A_info_add_digit_to_numeric_arg,
912 	ESC, '6', NUL,			A_info_add_digit_to_numeric_arg,
913 	ESC, '7', NUL,			A_info_add_digit_to_numeric_arg,
914 	ESC, '8', NUL,			A_info_add_digit_to_numeric_arg,
915 	ESC, '9', NUL,			A_info_add_digit_to_numeric_arg,
916 	ESC, '-', NUL,			A_info_add_digit_to_numeric_arg,
917 	ESC, CONTROL('f'), NUL,		A_info_show_footnotes,
918 	ESC, CONTROL('g'), NUL,		A_info_abort_key,
919 	ESC, TAB, NUL,			A_info_move_to_prev_xref,
920 	ESC, CONTROL('v'), NUL,		A_info_scroll_other_window,
921 	ESC, '<', NUL,			A_info_beginning_of_node,
922 	ESC, '>', NUL,			A_info_end_of_node,
923 	ESC, 'b', NUL,			A_info_backward_word,
924 	ESC, 'f', NUL,			A_info_forward_word,
925 	ESC, 'r', NUL,			A_info_move_to_window_line,
926 	ESC, 'v', NUL,			A_info_scroll_backward_page_only,
927 	Meta('0'), NUL,			A_info_add_digit_to_numeric_arg,
928 	Meta('1'), NUL,			A_info_add_digit_to_numeric_arg,
929 	Meta('2'), NUL,			A_info_add_digit_to_numeric_arg,
930 	Meta('3'), NUL,			A_info_add_digit_to_numeric_arg,
931 	Meta('4'), NUL,			A_info_add_digit_to_numeric_arg,
932 	Meta('5'), NUL,			A_info_add_digit_to_numeric_arg,
933 	Meta('6'), NUL,			A_info_add_digit_to_numeric_arg,
934 	Meta('7'), NUL,			A_info_add_digit_to_numeric_arg,
935 	Meta('8'), NUL,			A_info_add_digit_to_numeric_arg,
936 	Meta('9'), NUL,			A_info_add_digit_to_numeric_arg,
937 	Meta('-'), NUL,			A_info_add_digit_to_numeric_arg,
938 	Meta(CONTROL('f')), NUL,	A_info_show_footnotes,
939 	Meta(CONTROL('g')), NUL,	A_info_abort_key,
940 	Meta(TAB), NUL,			A_info_move_to_prev_xref,
941 	Meta(CONTROL('v')), NUL,	A_info_scroll_other_window,
942 	Meta('<'), NUL,			A_info_beginning_of_node,
943 	Meta('>'), NUL,			A_info_end_of_node,
944 	Meta('b'), NUL,			A_info_backward_word,
945 	Meta('f'), NUL,			A_info_forward_word,
946 	Meta('r'), NUL,			A_info_move_to_window_line,
947 	Meta('v'), NUL,			A_info_scroll_backward_page_only,
948 #if defined (NAMED_FUNCTIONS)
949 	ESC, 'x', NUL,			A_info_execute_command,
950 	Meta('x'), NUL,			A_info_execute_command,
951 #endif /* NAMED_FUNCTIONS */
952 
953 	CONTROL('x'), CONTROL('b'), NUL,	A_list_visited_nodes,
954 	CONTROL('x'), CONTROL('c'), NUL,	A_info_quit,
955 	CONTROL('x'), CONTROL('f'), NUL,	A_info_view_file,
956 	CONTROL('x'), CONTROL('g'), NUL,	A_info_abort_key,
957 	CONTROL('x'), CONTROL('v'), NUL,	A_info_view_file,
958 	CONTROL('x'), '0', NUL,		A_info_delete_window,
959 	CONTROL('x'), '1', NUL,		A_info_keep_one_window,
960 	CONTROL('x'), '2', NUL,		A_info_split_window,
961 	CONTROL('x'), '^', NUL,		A_info_grow_window,
962 	CONTROL('x'), 'b', NUL,		A_select_visited_node,
963 	CONTROL('x'), 'k', NUL,		A_info_kill_node,
964 	CONTROL('x'), 'n', NUL,		A_info_search_next,
965 	CONTROL('x'), 'N', NUL,		A_info_search_previous,
966 	CONTROL('x'), 'o', NUL,		A_info_next_window,
967 	CONTROL('x'), 't', NUL,		A_info_tile_windows,
968 	CONTROL('x'), 'w', NUL,		A_info_toggle_wrap,
969 
970 /*	Arrow key bindings for info keymaps.  It seems that some
971 	terminals do not match their termcap entries, so it's best to just
972 	define everything with both of the usual prefixes.  */
973 
974 	SK_ESCAPE, SK_PAGE_UP, NUL,		A_info_scroll_backward_page_only,
975 	SK_ESCAPE, SK_PAGE_DOWN, NUL,		A_info_scroll_forward_page_only,
976 	SK_ESCAPE, SK_UP_ARROW, NUL,		A_info_prev_line,
977 	'\033', 'O', 'A', NUL,			A_info_prev_line,
978 	'\033', '[', 'A', NUL,			A_info_prev_line,
979 	SK_ESCAPE, SK_DOWN_ARROW, NUL,		A_info_next_line,
980 	'\033', 'O', 'B', NUL,			A_info_next_line,
981 	'\033', '[', 'B', NUL,			A_info_next_line,
982 	SK_ESCAPE, SK_RIGHT_ARROW, NUL,		A_info_forward_char,
983 	'\033', 'O', 'C', NUL,			A_info_forward_char,
984 	'\033', '[', 'C', NUL,			A_info_forward_char,
985 	SK_ESCAPE, SK_LEFT_ARROW, NUL,		A_info_backward_char,
986 	'\033', 'O', 'D', NUL,			A_info_backward_char,
987 	'\033', '[', 'D', NUL,			A_info_backward_char,
988 	SK_ESCAPE, SK_HOME, NUL,		A_info_beginning_of_node,
989 	SK_ESCAPE, SK_END, NUL,			A_info_end_of_node,
990 	SK_ESCAPE, SK_DELETE, NUL,		A_info_scroll_backward,
991 
992 	ESC, SK_ESCAPE, SK_PAGE_UP, NUL,	A_info_scroll_other_window_backward,
993 	ESC, SK_ESCAPE, SK_PAGE_DOWN, NUL,	A_info_scroll_other_window,
994 	ESC, SK_ESCAPE, SK_UP_ARROW, NUL,	A_info_prev_line,
995 	ESC, '\033', 'O', 'A', NUL,		A_info_prev_line,
996 	ESC, '\033', '[', 'A', NUL,		A_info_prev_line,
997 	ESC, SK_ESCAPE, SK_DOWN_ARROW, NUL,	A_info_next_line,
998 	ESC, '\033', 'O', 'B', NUL,		A_info_next_line,
999 	ESC, '\033', '[', 'B', NUL,		A_info_next_line,
1000 	ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL,	A_info_forward_word,
1001 	ESC, '\033', 'O', 'C', NUL,		A_info_forward_word,
1002 	ESC, '\033', '[', 'C', NUL,		A_info_forward_word,
1003 	ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL,	A_info_backward_word,
1004 	ESC, '\033', 'O', 'D', NUL,		A_info_backward_word,
1005 	ESC, '\033', '[', 'D', NUL,		A_info_backward_word,
1006 };
1007 
1008 static unsigned char default_emacs_like_ea_keys[] =
1009 {
1010 	0,	/* suppress-default-keybindings flag */
1011 	ESC, '0', NUL,			A_info_add_digit_to_numeric_arg,
1012 	ESC, '1', NUL,			A_info_add_digit_to_numeric_arg,
1013 	ESC, '2', NUL,			A_info_add_digit_to_numeric_arg,
1014 	ESC, '3', NUL,			A_info_add_digit_to_numeric_arg,
1015 	ESC, '4', NUL,			A_info_add_digit_to_numeric_arg,
1016 	ESC, '5', NUL,			A_info_add_digit_to_numeric_arg,
1017 	ESC, '6', NUL,			A_info_add_digit_to_numeric_arg,
1018 	ESC, '7', NUL,			A_info_add_digit_to_numeric_arg,
1019 	ESC, '8', NUL,			A_info_add_digit_to_numeric_arg,
1020 	ESC, '9', NUL,			A_info_add_digit_to_numeric_arg,
1021 	ESC, '-', NUL,			A_info_add_digit_to_numeric_arg,
1022 	Meta('0'), NUL,			A_info_add_digit_to_numeric_arg,
1023 	Meta('1'), NUL,			A_info_add_digit_to_numeric_arg,
1024 	Meta('2'), NUL,			A_info_add_digit_to_numeric_arg,
1025 	Meta('3'), NUL,			A_info_add_digit_to_numeric_arg,
1026 	Meta('4'), NUL,			A_info_add_digit_to_numeric_arg,
1027 	Meta('5'), NUL,			A_info_add_digit_to_numeric_arg,
1028 	Meta('6'), NUL,			A_info_add_digit_to_numeric_arg,
1029 	Meta('7'), NUL,			A_info_add_digit_to_numeric_arg,
1030 	Meta('8'), NUL,			A_info_add_digit_to_numeric_arg,
1031 	Meta('9'), NUL,			A_info_add_digit_to_numeric_arg,
1032 	Meta('-'), NUL,			A_info_add_digit_to_numeric_arg,
1033 	ESC, CONTROL('g'), NUL,		A_ea_abort,
1034 	ESC, CONTROL('v'), NUL,		A_ea_scroll_completions_window,
1035 	ESC, 'b', NUL,			A_ea_backward_word,
1036 	ESC, 'd', NUL,			A_ea_kill_word,
1037 	ESC, 'f', NUL,			A_ea_forward_word,
1038 	ESC, 'y', NUL,			A_ea_yank_pop,
1039 	ESC, '?', NUL,			A_ea_possible_completions,
1040 	ESC, TAB, NUL,			A_ea_tab_insert,
1041 	ESC, DEL, NUL,			A_ea_backward_kill_word,
1042 	Meta(CONTROL('g')), NUL,	A_ea_abort,
1043 	Meta(CONTROL('v')), NUL,	A_ea_scroll_completions_window,
1044 	Meta('b'), NUL,			A_ea_backward_word,
1045 	Meta('d'), NUL,			A_ea_kill_word,
1046 	Meta('f'), NUL,			A_ea_forward_word,
1047 	Meta('y'), NUL,			A_ea_yank_pop,
1048 	Meta('?'), NUL,			A_ea_possible_completions,
1049 	Meta(TAB), NUL,			A_ea_tab_insert,
1050 	Meta(DEL), NUL,			A_ea_backward_kill_word,
1051 	CONTROL('a'), NUL,		A_ea_beg_of_line,
1052 	CONTROL('b'), NUL,		A_ea_backward,
1053 	CONTROL('d'), NUL,		A_ea_delete,
1054 	CONTROL('e'), NUL,		A_ea_end_of_line,
1055 	CONTROL('f'), NUL,		A_ea_forward,
1056 	CONTROL('g'), NUL,		A_ea_abort,
1057 	CONTROL('h'), NUL,		A_ea_rubout,
1058 /*	CONTROL('k') */
1059 	SK_ESCAPE, SK_LITERAL, NUL,	A_ea_kill_line,
1060 	CONTROL('l'), NUL,		A_info_redraw_display,
1061 	CONTROL('q'), NUL,		A_ea_quoted_insert,
1062 	CONTROL('t'), NUL,		A_ea_transpose_chars,
1063 	CONTROL('u'), NUL,		A_info_universal_argument,
1064 	CONTROL('y'), NUL,		A_ea_yank,
1065 	LFD, NUL,			A_ea_newline,
1066 	RET, NUL,			A_ea_newline,
1067 	SPC, NUL,			A_ea_complete,
1068 	TAB, NUL,			A_ea_complete,
1069 	'?', NUL,			A_ea_possible_completions,
1070 #ifdef __MSDOS__
1071         /* PC users will lynch me if I don't give them their usual DEL
1072 	   effect...  */
1073 	DEL, NUL,			A_ea_delete,
1074 #else
1075 	DEL, NUL,			A_ea_rubout,
1076 #endif
1077 #if defined (NAMED_FUNCTIONS)
1078   /* 	ESC, 'x', NUL,			A_info_execute_command, */
1079   /* 	Meta('x'), NUL,			A_info_execute_command, */
1080 #endif /* NAMED_FUNCTIONS */
1081 	CONTROL('x'), 'o', NUL,		A_info_next_window,
1082   	CONTROL('x'), DEL, NUL,		A_ea_backward_kill_line,
1083 
1084 /*	Arrow key bindings for echo area keymaps.  It seems that some
1085 	terminals do not match their termcap entries, so it's best to just
1086 	define everything with both of the usual prefixes.  */
1087 
1088 	SK_ESCAPE, SK_RIGHT_ARROW, NUL,		A_ea_forward,
1089 	'\033', 'O', 'C', NUL,			A_ea_forward,
1090 	'\033', '[', 'C', NUL,			A_ea_forward,
1091 	SK_ESCAPE, SK_LEFT_ARROW, NUL,		A_ea_backward,
1092 	'\033', 'O', 'D', NUL,			A_ea_backward,
1093 	'\033', '[', 'D', NUL,			A_ea_backward,
1094 	ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL,	A_ea_forward_word,
1095 	ESC, '\033', 'O', 'C', NUL,		A_ea_forward_word,
1096 	ESC, '\033', '[', 'C', NUL,		A_ea_forward_word,
1097 	ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL,	A_ea_backward_word,
1098 	ESC, '\033', 'O', 'D', NUL,		A_ea_backward_word,
1099 	ESC, '\033', '[', 'D', NUL,		A_ea_backward_word,
1100 #ifdef __MSDOS__
1101 	SK_ESCAPE, SK_DELETE, NUL,		A_ea_delete,
1102 #else
1103 	SK_ESCAPE, SK_DELETE, NUL,		A_ea_rubout,
1104 #endif
1105 	SK_ESCAPE, SK_HOME, NUL,		A_ea_beg_of_line,
1106 	SK_ESCAPE, SK_END, NUL,			A_ea_end_of_line,
1107 	ESC, SK_ESCAPE, SK_DELETE, NUL,		A_ea_backward_kill_word,
1108 	CONTROL('x'), SK_ESCAPE, SK_DELETE, NUL,A_ea_backward_kill_line,
1109 };
1110 
1111 static unsigned char default_vi_like_info_keys[] =
1112 {
1113 	0,	/* suppress-default-keybindings flag */
1114 	'0', NUL,			A_info_add_digit_to_numeric_arg,
1115 	'1', NUL,			A_info_add_digit_to_numeric_arg,
1116 	'2', NUL,			A_info_add_digit_to_numeric_arg,
1117 	'3', NUL,			A_info_add_digit_to_numeric_arg,
1118 	'4', NUL,			A_info_add_digit_to_numeric_arg,
1119 	'5', NUL,			A_info_add_digit_to_numeric_arg,
1120 	'6', NUL,			A_info_add_digit_to_numeric_arg,
1121 	'7', NUL,			A_info_add_digit_to_numeric_arg,
1122 	'8', NUL,			A_info_add_digit_to_numeric_arg,
1123 	'9', NUL,			A_info_add_digit_to_numeric_arg,
1124 	'-', NUL,			A_info_add_digit_to_numeric_arg,
1125 	TAB, NUL,			A_info_move_to_next_xref,
1126 	LFD, NUL,			A_info_down_line,
1127 	RET, NUL,			A_info_down_line,
1128 	SPC, NUL,			A_info_scroll_forward,
1129 	CONTROL('a'), NUL,		A_info_beginning_of_line,
1130 	CONTROL('b'), NUL,		A_info_scroll_backward_page_only,
1131 	CONTROL('d'), NUL,		A_info_scroll_half_screen_down,
1132 	CONTROL('e'), NUL,		A_info_down_line,
1133 	CONTROL('f'), NUL,		A_info_scroll_forward_page_only,
1134 	CONTROL('g'), NUL,		A_info_abort_key,
1135 	CONTROL('k'), NUL,		A_info_up_line,
1136 	CONTROL('l'), NUL,		A_info_redraw_display,
1137 	CONTROL('n'), NUL,		A_info_down_line,
1138 	CONTROL('p'), NUL,		A_info_up_line,
1139 	CONTROL('r'), NUL,		A_info_redraw_display,
1140 	CONTROL('s'), NUL,		A_isearch_forward,
1141 	CONTROL('u'), NUL,		A_info_scroll_half_screen_up,
1142 	CONTROL('v'), NUL,		A_info_scroll_forward_page_only,
1143 	CONTROL('y'), NUL,		A_info_up_line,
1144 	',', NUL,			A_info_next_index_match,
1145 	'/', NUL,			A_info_search,
1146 	ESC, '0', NUL,			A_info_last_menu_item,
1147 	ESC, '1', NUL,			A_info_menu_digit,
1148 	ESC, '2', NUL,			A_info_menu_digit,
1149 	ESC, '3', NUL,			A_info_menu_digit,
1150 	ESC, '4', NUL,			A_info_menu_digit,
1151 	ESC, '5', NUL,			A_info_menu_digit,
1152 	ESC, '6', NUL,			A_info_menu_digit,
1153 	ESC, '7', NUL,			A_info_menu_digit,
1154 	ESC, '8', NUL,			A_info_menu_digit,
1155 	ESC, '9', NUL,			A_info_menu_digit,
1156 	Meta('0'), NUL,			A_info_last_menu_item,
1157 	Meta('1'), NUL,			A_info_menu_digit,
1158 	Meta('2'), NUL,			A_info_menu_digit,
1159 	Meta('3'), NUL,			A_info_menu_digit,
1160 	Meta('4'), NUL,			A_info_menu_digit,
1161 	Meta('5'), NUL,			A_info_menu_digit,
1162 	Meta('6'), NUL,			A_info_menu_digit,
1163 	Meta('7'), NUL,			A_info_menu_digit,
1164 	Meta('8'), NUL,			A_info_menu_digit,
1165 	Meta('9'), NUL,			A_info_menu_digit,
1166 	'<', NUL,			A_info_first_node,
1167 	'>', NUL,			A_info_last_node,
1168 	'?', NUL,			A_info_search_backward,
1169 	'[', NUL,			A_info_global_prev_node,
1170 	']', NUL,			A_info_global_next_node,
1171 	'\'', NUL,			A_info_history_node,
1172 	'b', NUL,			A_info_scroll_backward,
1173 	'd', NUL,			A_info_scroll_half_screen_down,
1174 	'e', NUL,			A_info_down_line,
1175 	'E', NUL,			A_info_view_file,
1176 	':', 'e', NUL,			A_info_view_file,
1177 	'f', NUL,			A_info_scroll_forward_page_only,
1178 	'F', NUL,			A_info_scroll_forward_page_only,
1179 	'g', NUL,			A_info_first_node,
1180 	'G', NUL,			A_info_last_node,
1181 	'h', NUL,			A_info_get_help_window,
1182 	'H', NUL,			A_info_get_help_window,
1183 	'i', NUL,			A_info_index_search,
1184 	'I', NUL,			A_info_goto_invocation_node,
1185 	'j', NUL,			A_info_next_line,
1186 	'k', NUL,			A_info_prev_line,
1187 	'l', NUL,			A_info_history_node,
1188 	'm', NUL,			A_info_menu_item,
1189 	'n', NUL,			A_info_search_next,
1190 	'N', NUL,			A_info_search_previous,
1191 	'O', NUL,			A_info_goto_invocation_node,
1192 	'p', NUL,			A_info_prev_node,
1193 	'q', NUL,			A_info_quit,
1194 	'Q', NUL,			A_info_quit,
1195 	':', 'q', NUL,			A_info_quit,
1196 	':', 'Q', NUL,			A_info_quit,
1197 	'Z', 'Z', NUL,			A_info_quit,
1198 	'r', NUL,			A_info_redraw_display,
1199 	'R', NUL,			A_info_redraw_display,
1200 	's', NUL,			A_info_search,
1201 	'S', NUL,			A_info_search_case_sensitively,
1202 	't', NUL,			A_info_top_node,
1203 	'u', NUL,			A_info_scroll_half_screen_up,
1204 	'w', NUL,			A_info_scroll_backward_page_only_set_window,
1205 	'y', NUL,			A_info_up_line,
1206 	'z', NUL,			A_info_scroll_forward_page_only_set_window,
1207 	DEL, NUL,			A_info_scroll_backward,
1208 	ESC, CONTROL('f'), NUL,		A_info_show_footnotes,
1209 	ESC, CONTROL('g'), NUL,		A_info_abort_key,
1210 	ESC, TAB, NUL,			A_info_move_to_prev_xref,
1211 	ESC, SPC, NUL,			A_info_scroll_forward_page_only,
1212 	ESC, CONTROL('v'), NUL,		A_info_scroll_other_window,
1213 	ESC, '<', NUL,			A_info_beginning_of_node,
1214 	ESC, '>', NUL,			A_info_end_of_node,
1215 	ESC, '/', NUL,			A_info_search,
1216 	ESC, '?', NUL,			A_info_search_backward,
1217 	ESC, 'b', NUL,			A_info_beginning_of_node,
1218 	ESC, 'd', NUL,			A_info_dir_node,
1219 	ESC, 'e', NUL,			A_info_end_of_node,
1220 	ESC, 'f', NUL,			A_info_xref_item,
1221 	ESC, 'g', NUL,			A_info_select_reference_this_line,
1222 	ESC, 'h', NUL,			A_info_get_info_help_node,
1223 	ESC, 'm', NUL,			A_info_menu_item,
1224 	ESC, 'n', NUL,			A_info_search,
1225 	ESC, 'N', NUL,			A_info_search_backward,
1226 	ESC, 'r', NUL,			A_isearch_backward,
1227 	ESC, 's', NUL,			A_isearch_forward,
1228 	ESC, 't', NUL,			A_info_top_node,
1229 	ESC, 'v', NUL,			A_info_scroll_backward_page_only,
1230 #if defined (NAMED_FUNCTIONS)
1231 	ESC, 'x', NUL,			A_info_execute_command,
1232 	Meta('x'), NUL,			A_info_execute_command,
1233 #endif /* NAMED_FUNCTIONS */
1234 	ESC, DEL, NUL,			A_info_scroll_other_window_backward,
1235 	CONTROL('x'), CONTROL('b'), NUL,	A_list_visited_nodes,
1236 	CONTROL('x'), CONTROL('c'), NUL,	A_info_quit,
1237 	CONTROL('x'), CONTROL('f'), NUL,	A_info_view_file,
1238 	CONTROL('x'), CONTROL('g'), NUL,	A_info_abort_key,
1239 	CONTROL('x'), CONTROL('v'), NUL,	A_info_view_file,
1240 	CONTROL('x'), LFD, NUL,		A_info_select_reference_this_line,
1241 	CONTROL('x'), RET, NUL,		A_info_select_reference_this_line,
1242 	CONTROL('x'), '0', NUL,		A_info_delete_window,
1243 	CONTROL('x'), '1', NUL,		A_info_keep_one_window,
1244 	CONTROL('x'), '2', NUL,		A_info_split_window,
1245 	CONTROL('x'), '^', NUL,		A_info_grow_window,
1246 	CONTROL('x'), 'b', NUL,		A_select_visited_node,
1247 	CONTROL('x'), 'g', NUL,		A_info_goto_node,
1248 	CONTROL('x'), 'i', NUL,		A_info_index_search,
1249 	CONTROL('x'), 'I', NUL,		A_info_goto_invocation_node,
1250 	CONTROL('x'), 'k', NUL,		A_info_kill_node,
1251 	CONTROL('x'), 'n', NUL,		A_info_next_node,
1252 	CONTROL('x'), 'o', NUL,		A_info_next_window,
1253 	CONTROL('x'), 'O', NUL,		A_info_goto_invocation_node,
1254 	CONTROL('x'), 'p', NUL,		A_info_prev_node,
1255 	CONTROL('x'), 'r', NUL,		A_info_xref_item,
1256 	CONTROL('x'), 't', NUL,		A_info_tile_windows,
1257 	CONTROL('x'), 'u', NUL,		A_info_up_node,
1258 	CONTROL('x'), 'w', NUL,		A_info_toggle_wrap,
1259 	CONTROL('x'), ',', NUL,		A_info_next_index_match,
1260 
1261 /*	Arrow key bindings for info keymaps.  It seems that some
1262 	terminals do not match their termcap entries, so it's best to just
1263 	define everything with both of the usual prefixes.  */
1264 
1265 	SK_ESCAPE, SK_PAGE_UP, NUL,		A_info_scroll_backward_page_only,
1266 	SK_ESCAPE, SK_PAGE_DOWN, NUL,		A_info_scroll_forward_page_only,
1267 	SK_ESCAPE, SK_UP_ARROW, NUL,		A_info_up_line,
1268 	'\033', 'O', 'A', NUL,			A_info_up_line,
1269 	'\033', '[', 'A', NUL,			A_info_up_line,
1270 	SK_ESCAPE, SK_DOWN_ARROW, NUL,		A_info_down_line,
1271 	'\033', 'O', 'B', NUL,			A_info_down_line,
1272 	'\033', '[', 'B', NUL,			A_info_down_line,
1273 	SK_ESCAPE, SK_RIGHT_ARROW, NUL,		A_info_scroll_forward_page_only,
1274 	'\033', 'O', 'C', NUL,			A_info_scroll_forward_page_only,
1275 	'\033', '[', 'C', NUL,			A_info_scroll_forward_page_only,
1276 	SK_ESCAPE, SK_LEFT_ARROW, NUL,		A_info_scroll_backward_page_only,
1277 	'\033', 'O', 'D', NUL,			A_info_scroll_backward_page_only,
1278 	'\033', '[', 'D', NUL,			A_info_scroll_backward_page_only,
1279 	SK_ESCAPE, SK_HOME, NUL,		A_info_beginning_of_node,
1280 	SK_ESCAPE, SK_END, NUL,			A_info_end_of_node,
1281 	ESC, SK_ESCAPE, SK_PAGE_DOWN, NUL,	A_info_scroll_other_window,
1282 	ESC, SK_ESCAPE, SK_PAGE_UP, NUL,	A_info_scroll_other_window_backward,
1283 	ESC, SK_ESCAPE, SK_DELETE, NUL,		A_info_scroll_other_window_backward,
1284 	ESC, SK_ESCAPE, SK_UP_ARROW, NUL,	A_info_prev_node,
1285 	ESC, '\033', 'O', 'A', NUL,		A_info_prev_node,
1286 	ESC, '\033', '[', 'A', NUL,		A_info_prev_node,
1287 	ESC, SK_ESCAPE, SK_DOWN_ARROW, NUL,	A_info_next_node,
1288 	ESC, '\033', 'O', 'B', NUL,		A_info_next_node,
1289 	ESC, '\033', '[', 'B', NUL,		A_info_next_node,
1290 	ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL,	A_info_xref_item,
1291 	ESC, '\033', 'O', 'C', NUL,		A_info_xref_item,
1292 	ESC, '\033', '[', 'C', NUL,		A_info_xref_item,
1293 	ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL,	A_info_beginning_of_node,
1294 	ESC, '\033', 'O', 'D', NUL,		A_info_beginning_of_node,
1295 	ESC, '\033', '[', 'D', NUL,		A_info_beginning_of_node,
1296 	CONTROL('x'), SK_ESCAPE, SK_DELETE, NUL,A_ea_backward_kill_line,
1297 };
1298 
1299 static unsigned char default_vi_like_ea_keys[] =
1300 {
1301 	0,	/* suppress-default-keybindings flag */
1302 	ESC, '1', NUL,			A_info_add_digit_to_numeric_arg,
1303 	ESC, '2', NUL,			A_info_add_digit_to_numeric_arg,
1304 	ESC, '3', NUL,			A_info_add_digit_to_numeric_arg,
1305 	ESC, '4', NUL,			A_info_add_digit_to_numeric_arg,
1306 	ESC, '5', NUL,			A_info_add_digit_to_numeric_arg,
1307 	ESC, '6', NUL,			A_info_add_digit_to_numeric_arg,
1308 	ESC, '7', NUL,			A_info_add_digit_to_numeric_arg,
1309 	ESC, '8', NUL,			A_info_add_digit_to_numeric_arg,
1310 	ESC, '9', NUL,			A_info_add_digit_to_numeric_arg,
1311 	ESC, '-', NUL,			A_info_add_digit_to_numeric_arg,
1312 	Meta('1'), NUL,			A_info_add_digit_to_numeric_arg,
1313 	Meta('2'), NUL,			A_info_add_digit_to_numeric_arg,
1314 	Meta('3'), NUL,			A_info_add_digit_to_numeric_arg,
1315 	Meta('4'), NUL,			A_info_add_digit_to_numeric_arg,
1316 	Meta('5'), NUL,			A_info_add_digit_to_numeric_arg,
1317 	Meta('6'), NUL,			A_info_add_digit_to_numeric_arg,
1318 	Meta('7'), NUL,			A_info_add_digit_to_numeric_arg,
1319 	Meta('8'), NUL,			A_info_add_digit_to_numeric_arg,
1320 	Meta('9'), NUL,			A_info_add_digit_to_numeric_arg,
1321 	Meta('-'), NUL,			A_info_add_digit_to_numeric_arg,
1322 	ESC, CONTROL('g'), NUL,		A_ea_abort,
1323 	ESC, CONTROL('h'), NUL,		A_ea_backward_kill_word,
1324 	ESC, CONTROL('v'), NUL,		A_ea_scroll_completions_window,
1325 	ESC, '0', NUL,			A_ea_beg_of_line,
1326 	ESC, '$', NUL,			A_ea_end_of_line,
1327 	ESC, 'b', NUL,			A_ea_backward_word,
1328 	ESC, 'd', NUL,			A_ea_kill_word,
1329 	ESC, 'f', NUL,			A_ea_forward_word,
1330 	ESC, 'h', NUL,			A_ea_forward,
1331 	ESC, 'l', NUL,			A_ea_backward,
1332 	ESC, 'w', NUL,			A_ea_forward_word,
1333 	ESC, 'x', NUL,			A_ea_delete,
1334 	ESC, 'X', NUL,			A_ea_kill_word,
1335 	ESC, 'y', NUL,			A_ea_yank_pop,
1336 	ESC, '?', NUL,			A_ea_possible_completions,
1337 	ESC, TAB, NUL,			A_ea_tab_insert,
1338 	ESC, DEL, NUL,			A_ea_kill_word,
1339 	Meta(CONTROL('g')), NUL,	A_ea_abort,
1340 	Meta(CONTROL('h')), NUL,	A_ea_backward_kill_word,
1341 	Meta(CONTROL('v')), NUL,	A_ea_scroll_completions_window,
1342 	Meta('0'), NUL,			A_ea_beg_of_line,
1343 	Meta('$'), NUL,			A_ea_end_of_line,
1344 	Meta('b'), NUL,			A_ea_backward_word,
1345 	Meta('d'), NUL,			A_ea_kill_word,
1346 	Meta('f'), NUL,			A_ea_forward_word,
1347 	Meta('h'), NUL,			A_ea_forward,
1348 	Meta('l'), NUL,			A_ea_backward,
1349 	Meta('w'), NUL,			A_ea_forward_word,
1350 	Meta('x'), NUL,			A_ea_delete,
1351 	Meta('X'), NUL,			A_ea_kill_word,
1352 	Meta('y'), NUL,			A_ea_yank_pop,
1353 	Meta('?'), NUL,			A_ea_possible_completions,
1354 	Meta(TAB), NUL,			A_ea_tab_insert,
1355 	Meta(DEL), NUL,			A_ea_kill_word,
1356 	CONTROL('a'), NUL,		A_ea_beg_of_line,
1357 	CONTROL('b'), NUL,		A_ea_backward,
1358 	CONTROL('d'), NUL,		A_ea_delete,
1359 	CONTROL('e'), NUL,		A_ea_end_of_line,
1360 	CONTROL('f'), NUL,		A_ea_forward,
1361 	CONTROL('g'), NUL,		A_ea_abort,
1362 	CONTROL('h'), NUL,		A_ea_rubout,
1363 /*	CONTROL('k') */
1364 	SK_ESCAPE, SK_LITERAL, NUL,	A_ea_kill_line,
1365 	CONTROL('l'), NUL,		A_info_redraw_display,
1366 	CONTROL('q'), NUL,		A_ea_quoted_insert,
1367 	CONTROL('t'), NUL,		A_ea_transpose_chars,
1368 	CONTROL('u'), NUL,		A_ea_abort,
1369 	CONTROL('v'), NUL,		A_ea_quoted_insert,
1370 	CONTROL('y'), NUL,		A_ea_yank,
1371 	LFD, NUL,			A_ea_newline,
1372 	RET, NUL,			A_ea_newline,
1373 	SPC, NUL,			A_ea_complete,
1374 	TAB, NUL,			A_ea_complete,
1375 	'?', NUL,			A_ea_possible_completions,
1376 #ifdef __MSDOS__
1377         /* PC users will lynch me if I don't give them their usual DEL
1378 	   effect...  */
1379 	DEL, NUL,			A_ea_delete,
1380 #else
1381 	DEL, NUL,			A_ea_rubout,
1382 #endif
1383 	CONTROL('x'), 'o', NUL,		A_info_next_window,
1384   	CONTROL('x'), DEL, NUL,		A_ea_backward_kill_line,
1385 
1386   /* Arrow key bindings for echo area keymaps.  It seems that some
1387      terminals do not match their termcap entries, so it's best to just
1388      define everything with both of the usual prefixes.  */
1389 
1390 	SK_ESCAPE, SK_RIGHT_ARROW, NUL,		A_ea_forward,
1391 	'\033', 'O', 'C', NUL,			A_ea_forward,
1392 	'\033', '[', 'C', NUL,			A_ea_forward,
1393 	SK_ESCAPE, SK_LEFT_ARROW, NUL,		A_ea_backward,
1394 	'\033', 'O', 'D', NUL,			A_ea_backward,
1395 	'\033', '[', 'D', NUL,			A_ea_backward,
1396 	SK_ESCAPE, SK_HOME, NUL,		A_ea_beg_of_line,
1397 	SK_ESCAPE, SK_END, NUL,			A_ea_end_of_line,
1398 #ifdef __MSDOS__
1399 	SK_ESCAPE, SK_DELETE, NUL,		A_ea_delete,
1400 #else
1401 	SK_DELETE, SK_DELETE, NUL,		A_ea_rubout,
1402 #endif
1403 	ESC, SK_ESCAPE, SK_RIGHT_ARROW, NUL,	A_ea_forward_word,
1404 	ESC, '\033', 'O', 'C', NUL,		A_ea_forward_word,
1405 	ESC, '\033', '[', 'C', NUL,		A_ea_forward_word,
1406 	ESC, SK_ESCAPE, SK_LEFT_ARROW, NUL,	A_ea_backward_word,
1407 	ESC, '\033', 'O', 'D', NUL,		A_ea_backward_word,
1408 	ESC, '\033', '[', 'D', NUL,		A_ea_backward_word,
1409 	ESC, SK_ESCAPE, SK_DELETE, NUL,		A_ea_kill_word,
1410 	CONTROL('x'), SK_ESCAPE, SK_DELETE, NUL,A_ea_backward_kill_line,
1411 };
1412 
1413 static unsigned char *user_info_keys;
1414 static unsigned int user_info_keys_len;
1415 static unsigned char *user_ea_keys;
1416 static unsigned int user_ea_keys_len;
1417 static unsigned char *user_vars;
1418 static unsigned int user_vars_len;
1419 
1420 /*
1421  * Return the size of a file, or 0 if the size can't be determined.
1422  */
1423 static unsigned long
1424 filesize(int f)
1425 {
1426 	long pos = lseek(f, 0L, SEEK_CUR);
1427 	long sz = -1L;
1428 	if (pos != -1L)
1429 	{
1430 		sz = lseek(f, 0L, SEEK_END);
1431 		lseek(f, pos, SEEK_SET);
1432 	}
1433 	return sz == -1L ? 0L : sz;
1434 }
1435 
1436 /* Get an integer from a infokey file.
1437    Integers are stored as two bytes, low order first, in radix INFOKEY_RADIX.
1438  */
1439 static int
1440 getint(unsigned char **sp)
1441 {
1442 	int n;
1443 
1444 	if ( !((*sp)[0] < INFOKEY_RADIX && (*sp)[1] < INFOKEY_RADIX) )
1445 		return -1;
1446 	n = (*sp)[0] + (*sp)[1] * INFOKEY_RADIX;
1447 	*sp += 2;
1448 	return n;
1449 }
1450 
1451 
1452 /* Fetch the contents of the standard infokey file "$HOME/.info".  Return
1453    true if ok, false if not.  */
1454 static int
1455 fetch_user_maps(void)
1456 {
1457 	char *filename = NULL;
1458 	char *homedir;
1459 	int f;
1460 	unsigned char *buf;
1461 	unsigned long len;
1462 	long nread;
1463 	unsigned char *p;
1464 	int n;
1465 
1466 	/* Find and open file. */
1467 	if ((filename = getenv("INFOKEY")) != NULL)
1468 		filename = xstrdup(filename);
1469 	else if ((homedir = getenv("HOME")) != NULL)
1470 	{
1471 		filename = xmalloc(strlen(homedir) + 2 + strlen(INFOKEY_FILE));
1472 		strcpy(filename, homedir);
1473 		strcat(filename, "/");
1474 		strcat(filename, INFOKEY_FILE);
1475 	}
1476 #ifdef __MSDOS__
1477 	/* Poor baby, she doesn't have a HOME...  */
1478 	else
1479 		filename = xstrdup(INFOKEY_FILE); /* try current directory */
1480 #endif
1481 	if (filename == NULL || (f = open(filename, O_RDONLY)) == (-1))
1482 	{
1483 		if (filename && errno != ENOENT)
1484 		{
1485 			info_error(filesys_error_string(filename, errno),
1486                             NULL, NULL);
1487 			free(filename);
1488 		}
1489 		return 0;
1490 	}
1491 	SET_BINARY (f);
1492 
1493 	/* Ensure that the file is a reasonable size. */
1494 	len = filesize(f);
1495 	if (len < INFOKEY_NMAGIC + 2 || len > 100 * 1024)
1496 	{
1497 		/* Bad file (a valid file must have at least 9 chars, and
1498 		   more than 100 KB is a problem). */
1499 		if (len < INFOKEY_NMAGIC + 2)
1500 			info_error((char *) _("Ignoring invalid infokey file `%s' - too small"),
1501 				   filename, NULL);
1502 		else
1503 			info_error((char *) _("Ignoring invalid infokey file `%s' - too big"),
1504 				   filename, NULL);
1505 		close(f);
1506 		free(filename);
1507 		return 0;
1508 	}
1509 
1510 	/* Read the file into a buffer. */
1511 	buf = (unsigned char *)xmalloc((int)len);
1512 	nread = read(f, buf, (unsigned int) len);
1513 	close(f);
1514 	if ((unsigned int) nread != len)
1515 	{
1516 		info_error((char *) _("Error reading infokey file `%s' - short read"),
1517                     filename, NULL);
1518 		free(buf);
1519 		free(filename);
1520 		return 0;
1521 	}
1522 
1523 	/* Check the header, trailer, and version of the file to increase
1524 	   our confidence that the contents are valid.  */
1525 	if (	buf[0] != INFOKEY_MAGIC_S0
1526 		|| buf[1] != INFOKEY_MAGIC_S1
1527 		|| buf[2] != INFOKEY_MAGIC_S2
1528 		|| buf[3] != INFOKEY_MAGIC_S3
1529 		|| buf[len - 4] != INFOKEY_MAGIC_E0
1530 		|| buf[len - 3] != INFOKEY_MAGIC_E1
1531 		|| buf[len - 2] != INFOKEY_MAGIC_E2
1532 		|| buf[len - 1] != INFOKEY_MAGIC_E3
1533 	)
1534 	{
1535 		info_error((char *) _("Invalid infokey file `%s' (bad magic numbers) -- run infokey to update it"),
1536                     filename, NULL);
1537 		free(filename);
1538 		return 0;
1539 	}
1540 	if (len < INFOKEY_NMAGIC + strlen(VERSION) + 1
1541             || strcmp(VERSION, (char *) (buf + 4)) != 0)
1542 	{
1543 		info_error
1544                   ((char *) _("Your infokey file `%s' is out of date -- run infokey to update it"),
1545                     filename, NULL);
1546 		free(filename);
1547 		return 0;
1548 	}
1549 
1550 	/* Extract the pieces.  */
1551 	for (p = buf + 4 + strlen(VERSION) + 1;
1552              (unsigned int) (p - buf) < len - 4;
1553              p += n)
1554 	{
1555 		int s = *p++;
1556 
1557 		n = getint(&p);
1558 		if (n < 0 || (unsigned int) n > len - 4 - (p - buf))
1559 		{
1560 			info_error((char *) _("Invalid infokey file `%s' (bad section length) -- run infokey to update it"),
1561                             filename, NULL);
1562 			free(filename);
1563 			return 0;
1564 		}
1565 
1566 		switch (s)
1567 		{
1568 		case INFOKEY_SECTION_INFO:
1569 			user_info_keys = p;
1570 			user_info_keys_len = n;
1571 			break;
1572 		case INFOKEY_SECTION_EA:
1573 			user_ea_keys = p;
1574 			user_ea_keys_len = n;
1575 			break;
1576 		case INFOKEY_SECTION_VAR:
1577 			user_vars = p;
1578 			user_vars_len = n;
1579 			break;
1580 		default:
1581 			info_error((char *) _("Invalid infokey file `%s' (bad section code) -- run infokey to update it"),
1582                             filename, NULL);
1583 			free(filename);
1584 			return 0;
1585 		}
1586 	}
1587 
1588 	free(filename);
1589 	return 1;
1590 }
1591 
1592 /* Decode special key sequences from the infokey file.  Return zero
1593    if the key sequence includes special keys which the terminal
1594    doesn't define.
1595  */
1596 static int
1597 decode_keys(unsigned char *src, unsigned int slen,
1598     unsigned char *dst, unsigned int dlen)
1599 {
1600 	unsigned char *s = src;
1601 	unsigned char *d = dst;
1602 
1603 #define To_dst(c) do { \
1604   if ((unsigned int) (d - dst) < dlen) *d++ = (c); \
1605 } while (0)
1606 
1607 	while ((unsigned int) (s - src) < slen)
1608 	{
1609 		unsigned char c = ISMETA(*s) ? UNMETA(*s) : *s;
1610 
1611 		if (c == SK_ESCAPE)
1612 		{
1613 			char *t;
1614 			static char lit[] = { SK_ESCAPE, NUL };
1615 
1616 			switch ((unsigned int) (s + 1 - src) < slen ? s[1] : '\0')
1617 			{
1618 			case SK_RIGHT_ARROW:	t = term_kr; break;
1619 			case SK_LEFT_ARROW:	t = term_kl; break;
1620 			case SK_UP_ARROW:	t = term_ku; break;
1621 			case SK_DOWN_ARROW:	t = term_kd; break;
1622 			case SK_PAGE_UP:	t = term_kP; break;
1623 			case SK_PAGE_DOWN:	t = term_kN; break;
1624 			case SK_HOME:		t = term_kh; break;
1625 			case SK_END:		t = term_ke; break;
1626 			case SK_DELETE:		t = term_kx; break;
1627 			case SK_INSERT:		t = term_ki; break;
1628 			case SK_LITERAL:
1629 			default:		t = lit; break;
1630 			}
1631 			if (t == NULL)
1632 				return 0;
1633 			while (*t)
1634 				To_dst(ISMETA(*s) ? Meta(*t++) : *t++);
1635 			s += 2;
1636 		}
1637 		else
1638 		{
1639 			if (ISMETA(*s))
1640 				To_dst(Meta(*s++));
1641 			else
1642 				To_dst(*s++);
1643 		}
1644 	}
1645 
1646 	To_dst('\0');
1647 
1648 	return 1;
1649 
1650 #undef To_dst
1651 
1652 }
1653 
1654 /* Convert an infokey file section to keymap bindings.  Return false if
1655    the default bindings are to be suppressed.  */
1656 static int
1657 section_to_keymaps(Keymap map, unsigned char *table, unsigned int len)
1658 {
1659 	int stop;
1660 	unsigned char *p;
1661 	unsigned char *seq = NULL;
1662 	unsigned int seqlen = 0;
1663 	enum { getseq, gotseq, getaction } state = getseq;
1664 
1665 	stop = len > 0 ? table[0] : 0;
1666 
1667 	for (p = table + 1; (unsigned int) (p - table) < len; p++)
1668 	{
1669 		switch (state)
1670 		{
1671 		case getseq:
1672 			if (*p)
1673 			{
1674 				seq = p;
1675 				state = gotseq;
1676 			}
1677 			break;
1678 
1679 		case gotseq:
1680 			if (!*p)
1681 			{
1682 				seqlen = p - seq;
1683 				state = getaction;
1684 			}
1685 			break;
1686 
1687 		case getaction:
1688 			{
1689 				unsigned int action = *p;
1690 				unsigned char keyseq[256];
1691 				KEYMAP_ENTRY ke;
1692 
1693 				state = getseq;
1694 				/* If decode_keys returns zero, it
1695 				   means that seq includes keys which
1696 				   the terminal doesn't support, like
1697 				   PageDown.  In that case, don't bind
1698 				   the key sequence.  */
1699 				if (decode_keys(seq, seqlen, keyseq,
1700 						sizeof keyseq))
1701 				{
1702 					keyseq[sizeof keyseq - 1] = '\0';
1703 					ke.type = ISFUNC;
1704 					ke.function =
1705 					  action < A_NCOMMANDS
1706 					  ? &function_doc_array[action]
1707 					  : NULL;
1708 					keymap_bind_keyseq(map,
1709                                             (const char *) keyseq, &ke);
1710 				}
1711 			}
1712 			break;
1713 		}
1714 	}
1715 	if (state != getseq)
1716 		info_error((char *) _("Bad data in infokey file -- some key bindings ignored"),
1717                     NULL, NULL);
1718 	return !stop;
1719 }
1720 
1721 /* Convert an infokey file section to variable settings.
1722  */
1723 static void
1724 section_to_vars(unsigned char *table, unsigned int len)
1725 {
1726 	enum { getvar, gotvar, getval, gotval } state = getvar;
1727 	unsigned char *var = NULL;
1728 	unsigned char *val = NULL;
1729 	unsigned char *p;
1730 
1731 	for (p = table; (unsigned int) (p - table) < len; p++)
1732 	  {
1733 	    switch (state)
1734 	      {
1735 	      case getvar:
1736 		if (*p)
1737 		  {
1738 		    var = p;
1739 		    state = gotvar;
1740 		  }
1741 		break;
1742 
1743 	      case gotvar:
1744 		if (!*p)
1745 		  state = getval;
1746 		break;
1747 
1748 	      case getval:
1749 		if (*p)
1750 		  {
1751 		    val = p;
1752 		    state = gotval;
1753 		  }
1754 		break;
1755 
1756 	      case gotval:
1757 		if (!*p)
1758 		  {
1759 		    set_variable_to_value((char *) var, (char *) val);
1760 		    state = getvar;
1761 		  }
1762 		break;
1763 	      }
1764 	  }
1765       if (state != getvar)
1766 	info_error((char *) _("Bad data in infokey file -- some var settings ignored"),
1767             NULL, NULL);
1768 }
1769 
1770 void
1771 initialize_info_keymaps (void)
1772 {
1773   int i;
1774   int suppress_info_default_bindings = 0;
1775   int suppress_ea_default_bindings = 0;
1776 
1777   if (!info_keymap)
1778     {
1779       info_keymap = keymap_make_keymap ();
1780       echo_area_keymap = keymap_make_keymap ();
1781     }
1782 
1783   /* Bind the echo area insert routines. */
1784   for (i = 0; i < 256; i++)
1785     if (isprint (i))
1786       echo_area_keymap[i].function = InfoCmd(ea_insert);
1787 
1788   /* Get user-defined keys and variables.  */
1789   if (fetch_user_maps())
1790     {
1791       if (user_info_keys_len && user_info_keys[0])
1792 	suppress_info_default_bindings = 1;
1793       if (user_ea_keys_len && user_ea_keys[0])
1794 	suppress_ea_default_bindings = 1;
1795     }
1796 
1797   /* Apply the default bindings, unless the user says to suppress
1798      them.  */
1799   if (vi_keys_p)
1800     {
1801       if (!suppress_info_default_bindings)
1802 	section_to_keymaps(info_keymap, default_vi_like_info_keys,
1803 			   sizeof(default_vi_like_info_keys));
1804       if (!suppress_ea_default_bindings)
1805 	  section_to_keymaps(echo_area_keymap, default_vi_like_ea_keys,
1806 			     sizeof(default_vi_like_ea_keys));
1807     }
1808   else
1809     {
1810       if (!suppress_info_default_bindings)
1811 	section_to_keymaps(info_keymap, default_emacs_like_info_keys,
1812 			   sizeof(default_emacs_like_info_keys));
1813       if (!suppress_ea_default_bindings)
1814 	  section_to_keymaps(echo_area_keymap, default_emacs_like_ea_keys,
1815 			     sizeof(default_emacs_like_ea_keys));
1816     }
1817 
1818   /* If the user specified custom bindings, apply them on top of the
1819      default ones.  */
1820   if (user_info_keys_len)
1821     section_to_keymaps(info_keymap, user_info_keys, user_info_keys_len);
1822 
1823   if (user_ea_keys_len)
1824     section_to_keymaps(echo_area_keymap, user_ea_keys, user_ea_keys_len);
1825 
1826   if (user_vars_len)
1827     section_to_vars(user_vars, user_vars_len);
1828 }
1829 
1830 #endif /* defined(INFOKEY) */
1831 /* vim: set sw=2 cino={1s>2sn-s^-se-s: */
1832