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