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