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