xref: /csrg-svn/lib/libedit/key.c (revision 61275)
154220Sbostic /*-
2*61275Sbostic  * Copyright (c) 1992, 1993
3*61275Sbostic  *	The Regents of the University of California.  All rights reserved.
454220Sbostic  *
554220Sbostic  * This code is derived from software contributed to Berkeley by
654220Sbostic  * Christos Zoulas of Cornell University.
754220Sbostic  *
854220Sbostic  * %sccs.include.redist.c%
954220Sbostic  */
1054220Sbostic 
1154624Schristos #if !defined(lint) && !defined(SCCSID)
12*61275Sbostic static char sccsid[] = "@(#)key.c	8.1 (Berkeley) 06/04/93";
1354624Schristos #endif /* not lint && not SCCSID */
1454220Sbostic 
1554220Sbostic /*
1654624Schristos  * key.c: This module contains the procedures for maintaining
1754624Schristos  *	  the extended-key map.
1854220Sbostic  *
1954220Sbostic  *      An extended-key (key) is a sequence of keystrokes introduced
2054220Sbostic  *	with an sequence introducer and consisting of an arbitrary
2154220Sbostic  *	number of characters.  This module maintains a map (the el->el_key.map)
2254220Sbostic  *	to convert these extended-key sequences into input strs
2354220Sbostic  *	(XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
2454220Sbostic  *
2554220Sbostic  *      Warning:
2654220Sbostic  *	  If key is a substr of some other keys, then the longer
2754220Sbostic  *	  keys are lost!!  That is, if the keys "abcd" and "abcef"
2854220Sbostic  *	  are in el->el_key.map, adding the key "abc" will cause the first two
2954220Sbostic  *	  definitions to be lost.
3054220Sbostic  *
3154220Sbostic  *      Restrictions:
3254220Sbostic  *      -------------
3354220Sbostic  *      1) It is not possible to have one key that is a
3454220Sbostic  *	   substr of another.
3554220Sbostic  */
3654220Sbostic #include "sys.h"
3754220Sbostic #include <string.h>
3854220Sbostic #include <stdlib.h>
3954220Sbostic 
4054220Sbostic #include "el.h"
4154220Sbostic 
4254220Sbostic /*
4354220Sbostic  * The Nodes of the el->el_key.map.  The el->el_key.map is a linked list
4454220Sbostic  * of these node elements
4554220Sbostic  */
4654220Sbostic struct key_node_t {
4754220Sbostic     char        ch;		/* single character of key 		*/
4854220Sbostic     int         type;		/* node type				*/
4954220Sbostic     key_value_t val; 		/* command code or pointer to str, 	*/
5054220Sbostic 				/* if this is a leaf 			*/
5154220Sbostic     struct key_node_t *next;	/* ptr to next char of this key 	*/
5254220Sbostic     struct key_node_t *sibling;	/* ptr to another key with same prefix 	*/
5354220Sbostic };
5454220Sbostic 
5554220Sbostic private	int            node_trav	__P((EditLine *, key_node_t *, char *,
5654220Sbostic 					     key_value_t *));
5754220Sbostic private	int            node__try	__P((key_node_t *, char *,
5854220Sbostic 					     key_value_t *, int));
5954220Sbostic private	key_node_t    *node__get	__P((int));
6054220Sbostic private	void	       node__put	__P((key_node_t *));
6154220Sbostic private	int	       node__delete	__P((key_node_t **, char *));
6254220Sbostic private	int	       node_lookup 	__P((EditLine *, char *, key_node_t *,
6354220Sbostic 					     int));
6454220Sbostic private	int	       node_enum	__P((EditLine *, key_node_t *, int));
6554220Sbostic private	int	       key__decode_char	__P((char *, int, int));
6654220Sbostic 
6754220Sbostic #define KEY_BUFSIZ	EL_BUFSIZ
6854220Sbostic 
6954220Sbostic 
7054220Sbostic /* key_init():
7154220Sbostic  *	Initialize the key maps
7254220Sbostic  */
7354220Sbostic protected int
key_init(el)7454220Sbostic key_init(el)
7554220Sbostic     EditLine *el;
7654220Sbostic {
7754220Sbostic     el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ);
7854220Sbostic     el->el_key.map = NULL;
7954220Sbostic     key_reset(el);
8054220Sbostic     return 0;
8154220Sbostic }
8254220Sbostic 
8354220Sbostic 
8454220Sbostic /* key_end():
8554220Sbostic  *	Free the key maps
8654220Sbostic  */
8754220Sbostic protected void
key_end(el)8854220Sbostic key_end(el)
8954220Sbostic     EditLine *el;
9054220Sbostic {
9154220Sbostic     el_free((ptr_t) el->el_key.buf);
9254220Sbostic     el->el_key.buf = NULL;
9354220Sbostic     /* XXX: provide a function to clear the keys */
9454220Sbostic     el->el_key.map = NULL;
9554220Sbostic }
9654220Sbostic 
9754220Sbostic 
9854220Sbostic /* key_map_cmd():
9954220Sbostic  *	Associate cmd with a key value
10054220Sbostic  */
10154220Sbostic protected key_value_t *
key_map_cmd(el,cmd)10254220Sbostic key_map_cmd(el, cmd)
10354220Sbostic     EditLine *el;
10454220Sbostic     int cmd;
10554220Sbostic {
10654220Sbostic     el->el_key.val.cmd = (el_action_t) cmd;
10754220Sbostic     return &el->el_key.val;
10854220Sbostic }
10954220Sbostic 
11054220Sbostic 
11154220Sbostic /* key_map_str():
11254220Sbostic  *	Associate str with a key value
11354220Sbostic  */
11454220Sbostic protected key_value_t *
key_map_str(el,str)11554220Sbostic key_map_str(el, str)
11654220Sbostic     EditLine *el;
11754220Sbostic     char  *str;
11854220Sbostic {
11954220Sbostic     el->el_key.val.str = str;
12054220Sbostic     return &el->el_key.val;
12154220Sbostic }
12254220Sbostic 
12354220Sbostic 
12454220Sbostic /* key_reset():
12554220Sbostic  *	Takes all nodes on el->el_key.map and puts them on free list.  Then
12654220Sbostic  *	initializes el->el_key.map with arrow keys
12754220Sbostic  *	[Always bind the ansi arrow keys?]
12854220Sbostic  */
12954220Sbostic protected void
key_reset(el)13054220Sbostic key_reset(el)
13154220Sbostic     EditLine *el;
13254220Sbostic {
13354220Sbostic     node__put(el->el_key.map);
13454220Sbostic     el->el_key.map = NULL;
13554220Sbostic     return;
13654220Sbostic }
13754220Sbostic 
13854220Sbostic 
13954220Sbostic /* key_get():
14054220Sbostic  *	Calls the recursive function with entry point el->el_key.map
14154220Sbostic  *      Looks up *ch in map and then reads characters until a
14254220Sbostic  *      complete match is found or a mismatch occurs. Returns the
14354220Sbostic  *      type of the match found (XK_STR, XK_CMD, or XK_EXE).
14454220Sbostic  *      Returns NULL in val.str and XK_STR for no match.
14554220Sbostic  *      The last character read is returned in *ch.
14654220Sbostic  */
14754220Sbostic protected int
key_get(el,ch,val)14854220Sbostic key_get(el, ch, val)
14954220Sbostic     EditLine    *el;
15054220Sbostic     char        *ch;
15154220Sbostic     key_value_t *val;
15254220Sbostic {
15354220Sbostic     return node_trav(el, el->el_key.map, ch, val);
15454220Sbostic }
15554220Sbostic 
15654220Sbostic 
15754220Sbostic 
15854220Sbostic /* key_add():
15954220Sbostic  *      Adds key to the el->el_key.map and associates the value in val with it.
16054220Sbostic  *      If key is already is in el->el_key.map, the new code is applied to the
16154220Sbostic  *      existing key. Ntype specifies if code is a command, an
16254220Sbostic  *      out str or a unix command.
16354220Sbostic  */
16454220Sbostic protected void
key_add(el,key,val,ntype)16554220Sbostic key_add(el, key, val, ntype)
16654220Sbostic     EditLine    *el;
16754220Sbostic     char        *key;
16854220Sbostic     key_value_t *val;
16954220Sbostic     int          ntype;
17054220Sbostic {
17154220Sbostic     if (key[0] == '\0') {
17254220Sbostic 	(void) fprintf(el->el_errfile,
17354220Sbostic 		       "key_add: Null extended-key not allowed.\n");
17454220Sbostic 	return;
17554220Sbostic     }
17654220Sbostic 
17754220Sbostic     if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
17854220Sbostic 	(void) fprintf(el->el_errfile,
17954220Sbostic 		       "key_add: sequence-lead-in command not allowed\n");
18054220Sbostic 	return;
18154220Sbostic     }
18254220Sbostic 
18354220Sbostic     if (el->el_key.map == NULL)
18454220Sbostic 	/* tree is initially empty.  Set up new node to match key[0] */
18554220Sbostic 	el->el_key.map = node__get(key[0]);	/* it is properly initialized */
18654220Sbostic 
18754220Sbostic     /* Now recurse through el->el_key.map */
18854220Sbostic     (void) node__try(el->el_key.map, key, val, ntype);
18954220Sbostic     return;
19054220Sbostic }
19154220Sbostic 
19254220Sbostic 
19354220Sbostic /* key_clear():
19454220Sbostic  *
19554220Sbostic  */
19654220Sbostic protected void
key_clear(el,map,in)19754220Sbostic key_clear(el, map, in)
19854220Sbostic     EditLine *el;
19954220Sbostic     el_action_t *map;
20054220Sbostic     char   *in;
20154220Sbostic {
20254220Sbostic     if ((map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) &&
20354220Sbostic 	((map == el->el_map.key &&
20454220Sbostic 	  el->el_map.alt[(unsigned char) *in] != ED_SEQUENCE_LEAD_IN) ||
20554220Sbostic 	 (map == el->el_map.alt &&
20654220Sbostic 	  el->el_map.key[(unsigned char) *in] != ED_SEQUENCE_LEAD_IN)))
20754220Sbostic 	(void) key_delete(el, in);
20854220Sbostic }
20954220Sbostic 
21054220Sbostic 
21154220Sbostic /* key_delete():
21254220Sbostic  *      Delete the key and all longer keys staring with key, if
21354220Sbostic  *      they exists.
21454220Sbostic  */
21554220Sbostic protected int
key_delete(el,key)21654220Sbostic key_delete(el, key)
21754220Sbostic     EditLine *el;
21854220Sbostic     char   *key;
21954220Sbostic {
22054220Sbostic     if (key[0] == '\0') {
22154220Sbostic 	(void) fprintf(el->el_errfile,
22254220Sbostic 		       "key_delete: Null extended-key not allowed.\n");
22354220Sbostic 	return -1;
22454220Sbostic     }
22554220Sbostic 
22654220Sbostic     if (el->el_key.map == NULL)
22754220Sbostic 	return 0;
22854220Sbostic 
22954220Sbostic     (void) node__delete(&el->el_key.map, key);
23054220Sbostic     return 0;
23154220Sbostic }
23254220Sbostic 
23354220Sbostic 
23454220Sbostic /* key_print():
23554220Sbostic  *	Print the binding associated with key key.
23654220Sbostic  *	Print entire el->el_key.map if null
23754220Sbostic  */
23854220Sbostic protected void
key_print(el,key)23954220Sbostic key_print(el, key)
24054220Sbostic     EditLine *el;
24154220Sbostic     char   *key;
24254220Sbostic {
24354220Sbostic     /* do nothing if el->el_key.map is empty and null key specified */
24454220Sbostic     if (el->el_key.map == NULL && *key == 0)
24554220Sbostic 	return;
24654220Sbostic 
24754220Sbostic     el->el_key.buf[0] =  '"';
24854220Sbostic     if (node_lookup(el, key, el->el_key.map, 1) <= -1)
24954220Sbostic 	/* key is not bound */
25054220Sbostic 	(void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n", key);
25154220Sbostic     return;
25254220Sbostic }
25354220Sbostic 
25454220Sbostic 
25554220Sbostic /* node_trav():
25654220Sbostic  *	recursively traverses node in tree until match or mismatch is
25754220Sbostic  * 	found.  May read in more characters.
25854220Sbostic  */
25954220Sbostic private int
node_trav(el,ptr,ch,val)26054220Sbostic node_trav(el, ptr, ch, val)
26154220Sbostic     EditLine     *el;
26254220Sbostic     key_node_t   *ptr;
26354220Sbostic     char         *ch;
26454220Sbostic     key_value_t  *val;
26554220Sbostic {
26654220Sbostic     if (ptr->ch == *ch) {
26754220Sbostic 	/* match found */
26854220Sbostic 	if (ptr->next) {
26954220Sbostic 	    /* key not complete so get next char */
27054220Sbostic 	    if (el_getc(el, ch) != 1) {	/* if EOF or error */
27154220Sbostic 		val->cmd = ED_END_OF_FILE;
27254220Sbostic 		return XK_CMD;/* PWP: Pretend we just read an end-of-file */
27354220Sbostic 	    }
27454220Sbostic 	    return node_trav(el, ptr->next, ch, val);
27554220Sbostic 	}
27654220Sbostic 	else {
27754220Sbostic 	    *val = ptr->val;
27854220Sbostic 	    if (ptr->type != XK_CMD)
27954220Sbostic 		*ch = '\0';
28054220Sbostic 	    return ptr->type;
28154220Sbostic 	}
28254220Sbostic     }
28354220Sbostic     else {
28454220Sbostic 	/* no match found here */
28554220Sbostic 	if (ptr->sibling) {
28654220Sbostic 	    /* try next sibling */
28754220Sbostic 	    return node_trav(el, ptr->sibling, ch, val);
28854220Sbostic 	}
28954220Sbostic 	else {
29054220Sbostic 	    /* no next sibling -- mismatch */
29154220Sbostic 	    val->str = NULL;
29254220Sbostic 	    return XK_STR;
29354220Sbostic 	}
29454220Sbostic     }
29554220Sbostic }
29654220Sbostic 
29754220Sbostic 
29854220Sbostic /* node__try():
29954220Sbostic  * 	Find a node that matches *str or allocate a new one
30054220Sbostic  */
30154220Sbostic private int
node__try(ptr,str,val,ntype)30254220Sbostic node__try(ptr, str, val, ntype)
30354220Sbostic     key_node_t   *ptr;
30454220Sbostic     char         *str;
30554220Sbostic     key_value_t  *val;
30654220Sbostic     int           ntype;
30754220Sbostic {
30854220Sbostic     if (ptr->ch != *str) {
30954220Sbostic 	key_node_t *xm;
31054220Sbostic 
31154220Sbostic 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
31254220Sbostic 	    if (xm->sibling->ch == *str)
31354220Sbostic 		break;
31454220Sbostic 	if (xm->sibling == NULL)
31554220Sbostic 	    xm->sibling = node__get(*str);	/* setup new node */
31654220Sbostic 	ptr = xm->sibling;
31754220Sbostic     }
31854220Sbostic 
31954220Sbostic     if (*++str == '\0') {
32054220Sbostic 	/* we're there */
32154220Sbostic 	if (ptr->next != NULL) {
32254220Sbostic 	    node__put(ptr->next);	/* lose longer keys with this prefix */
32354220Sbostic 	    ptr->next = NULL;
32454220Sbostic 	}
32556545Schristos 	switch (ptr->type) {
32656545Schristos 	case XK_CMD:
32758378Smarc 	case XK_NOD:
32856545Schristos 	    break;
32956545Schristos 	case XK_STR:
33056545Schristos 	case XK_EXE:
33156545Schristos 	    if (ptr->val.str)
33256545Schristos 		el_free((ptr_t) ptr->val.str);
33356545Schristos 	    break;
33456545Schristos 	default:
33556545Schristos 	    abort();
33656545Schristos 	    break;
33756545Schristos 	}
33856545Schristos 
33954220Sbostic 	switch (ptr->type = ntype) {
34054220Sbostic 	case XK_CMD:
34154220Sbostic 	    ptr->val = *val;
34254220Sbostic 	    break;
34354220Sbostic 	case XK_STR:
34454220Sbostic 	case XK_EXE:
34554220Sbostic 	    ptr->val.str = strdup(val->str);
34654220Sbostic 	    break;
34754220Sbostic 	default:
34854220Sbostic 	    abort();
34954220Sbostic 	    break;
35054220Sbostic 	}
35154220Sbostic     }
35254220Sbostic     else {
35354220Sbostic 	/* still more chars to go */
35454220Sbostic 	if (ptr->next == NULL)
35554220Sbostic 	    ptr->next = node__get(*str);	/* setup new node */
35654220Sbostic 	(void) node__try(ptr->next, str, val, ntype);
35754220Sbostic     }
35854220Sbostic     return 0;
35954220Sbostic }
36054220Sbostic 
36154220Sbostic 
36254220Sbostic /* node__delete():
36354220Sbostic  *	Delete node that matches str
36454220Sbostic  */
36554220Sbostic private int
node__delete(inptr,str)36654220Sbostic node__delete(inptr, str)
36754220Sbostic     key_node_t **inptr;
36854220Sbostic     char   *str;
36954220Sbostic {
37054220Sbostic     key_node_t *ptr;
37154220Sbostic     key_node_t *prev_ptr = NULL;
37254220Sbostic 
37354220Sbostic     ptr = *inptr;
37454220Sbostic 
37554220Sbostic     if (ptr->ch != *str) {
37654220Sbostic 	key_node_t *xm;
37754220Sbostic 
37854220Sbostic 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
37954220Sbostic 	    if (xm->sibling->ch == *str)
38054220Sbostic 		break;
38154220Sbostic 	if (xm->sibling == NULL)
38254220Sbostic 	    return 0;
38354220Sbostic 	prev_ptr = xm;
38454220Sbostic 	ptr = xm->sibling;
38554220Sbostic     }
38654220Sbostic 
38754220Sbostic     if (*++str == '\0') {
38854220Sbostic 	/* we're there */
38954220Sbostic 	if (prev_ptr == NULL)
39054220Sbostic 	    *inptr = ptr->sibling;
39154220Sbostic 	else
39254220Sbostic 	    prev_ptr->sibling = ptr->sibling;
39354220Sbostic 	ptr->sibling = NULL;
39454220Sbostic 	node__put(ptr);
39554220Sbostic 	return 1;
39654220Sbostic     }
39754220Sbostic     else if (ptr->next != NULL && node__delete(&ptr->next, str) == 1) {
39854220Sbostic 	if (ptr->next != NULL)
39954220Sbostic 	    return 0;
40054220Sbostic 	if (prev_ptr == NULL)
40154220Sbostic 	    *inptr = ptr->sibling;
40254220Sbostic 	else
40354220Sbostic 	    prev_ptr->sibling = ptr->sibling;
40454220Sbostic 	ptr->sibling = NULL;
40554220Sbostic 	node__put(ptr);
40654220Sbostic 	return 1;
40754220Sbostic     }
40854220Sbostic     else {
40954220Sbostic 	return 0;
41054220Sbostic     }
41154220Sbostic }
41254220Sbostic 
41354220Sbostic /* node__put():
41454220Sbostic  *	Puts a tree of nodes onto free list using free(3).
41554220Sbostic  */
41654220Sbostic private void
node__put(ptr)41754220Sbostic node__put(ptr)
41854220Sbostic     key_node_t *ptr;
41954220Sbostic {
42054220Sbostic     if (ptr == NULL)
42154220Sbostic 	return;
42254220Sbostic 
42354220Sbostic     if (ptr->next != NULL) {
42454220Sbostic 	node__put(ptr->next);
42554220Sbostic 	ptr->next = NULL;
42654220Sbostic     }
42754220Sbostic 
42854220Sbostic     node__put(ptr->sibling);
42954220Sbostic 
43054220Sbostic     switch (ptr->type) {
43154220Sbostic     case XK_CMD:
43254220Sbostic     case XK_NOD:
43354220Sbostic 	break;
43454220Sbostic     case XK_EXE:
43554220Sbostic     case XK_STR:
43654220Sbostic 	if (ptr->val.str != NULL)
43754220Sbostic 	    el_free((ptr_t) ptr->val.str);
43854220Sbostic 	break;
43954220Sbostic     default:
44054220Sbostic 	abort();
44154220Sbostic 	break;
44254220Sbostic     }
44354220Sbostic     el_free((ptr_t) ptr);
44454220Sbostic }
44554220Sbostic 
44654220Sbostic 
44754220Sbostic /* node__get():
44854220Sbostic  *	Returns pointer to an key_node_t for ch.
44954220Sbostic  */
45054220Sbostic private key_node_t *
node__get(ch)45154220Sbostic node__get(ch)
45254220Sbostic     int    ch;
45354220Sbostic {
45454220Sbostic     key_node_t *ptr;
45554220Sbostic 
45654220Sbostic     ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
45754220Sbostic     ptr->ch = ch;
45854220Sbostic     ptr->type = XK_NOD;
45954220Sbostic     ptr->val.str = NULL;
46054220Sbostic     ptr->next = NULL;
46154220Sbostic     ptr->sibling = NULL;
46254220Sbostic     return ptr;
46354220Sbostic }
46454220Sbostic 
46554220Sbostic 
46654220Sbostic 
46754220Sbostic /* node_lookup():
46854220Sbostic  *	look for the str starting at node ptr.
46954220Sbostic  *	Print if last node
47054220Sbostic  */
47154220Sbostic private int
node_lookup(el,str,ptr,cnt)47254220Sbostic node_lookup(el, str, ptr, cnt)
47354220Sbostic     EditLine   *el;
47454220Sbostic     char       *str;
47554220Sbostic     key_node_t *ptr;
47654220Sbostic     int         cnt;
47754220Sbostic {
47854220Sbostic     int     ncnt;
47954220Sbostic 
48054220Sbostic     if (ptr == NULL)
48154220Sbostic 	return -1;		/* cannot have null ptr */
48254220Sbostic 
48354220Sbostic     if (*str == 0) {
48454220Sbostic 	/* no more chars in str.  node_enum from here. */
48554220Sbostic 	(void) node_enum(el, ptr, cnt);
48654220Sbostic 	return 0;
48754220Sbostic     }
48854220Sbostic     else {
48954220Sbostic 	/* If match put this char into el->el_key.buf.  Recurse */
49054220Sbostic 	if (ptr->ch == *str) {
49154220Sbostic 	    /* match found */
49254220Sbostic 	    ncnt = key__decode_char(el->el_key.buf, cnt,
49354220Sbostic 				    (unsigned char) ptr->ch);
49454220Sbostic 	    if (ptr->next != NULL)
49554220Sbostic 		/* not yet at leaf */
49654220Sbostic 		return node_lookup(el, str + 1, ptr->next, ncnt + 1);
49754220Sbostic 	    else {
49854220Sbostic 		/* next node is null so key should be complete */
49954220Sbostic 		if (str[1] == 0) {
50054220Sbostic 		    el->el_key.buf[ncnt + 1] = '"';
50154220Sbostic 		    el->el_key.buf[ncnt + 2] = '\0';
50254220Sbostic 		    key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
50354220Sbostic 		    return 0;
50454220Sbostic 		}
50554220Sbostic 		else
50654220Sbostic 		    return -1;/* mismatch -- str still has chars */
50754220Sbostic 	    }
50854220Sbostic 	}
50954220Sbostic 	else {
51054220Sbostic 	    /* no match found try sibling */
51154220Sbostic 	    if (ptr->sibling)
51254220Sbostic 		return node_lookup(el, str, ptr->sibling, cnt);
51354220Sbostic 	    else
51454220Sbostic 		return -1;
51554220Sbostic 	}
51654220Sbostic     }
51754220Sbostic }
51854220Sbostic 
51954220Sbostic 
52054220Sbostic /* node_enum():
52154220Sbostic  *	Traverse the node printing the characters it is bound in buffer
52254220Sbostic  */
52354220Sbostic private int
node_enum(el,ptr,cnt)52454220Sbostic node_enum(el, ptr, cnt)
52554220Sbostic     EditLine *el;
52654220Sbostic     key_node_t *ptr;
52754220Sbostic     int     cnt;
52854220Sbostic {
52954220Sbostic     int     ncnt;
53054220Sbostic 
53154220Sbostic     if (cnt >= KEY_BUFSIZ - 5) {	/* buffer too small */
53254220Sbostic 	el->el_key.buf[++cnt] = '"';
53354220Sbostic 	el->el_key.buf[++cnt] = '\0';
53454220Sbostic 	(void) fprintf(el->el_errfile,
53554220Sbostic 		    "Some extended keys too long for internal print buffer");
53654220Sbostic 	(void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
53754220Sbostic 	return 0;
53854220Sbostic     }
53954220Sbostic 
54054220Sbostic     if (ptr == NULL) {
54154220Sbostic #ifdef DEBUG_EDIT
54254220Sbostic 	(void) fprintf(el->el_errfile, "node_enum: BUG!! Null ptr passed\n!");
54354220Sbostic #endif
54454220Sbostic 	return -1;
54554220Sbostic     }
54654220Sbostic 
54754220Sbostic     /* put this char at end of str */
54854220Sbostic     ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch);
54954220Sbostic     if (ptr->next == NULL) {
55054220Sbostic 	/* print this key and function */
55154220Sbostic 	el->el_key.buf[ncnt + 1] = '"';
55254220Sbostic 	el->el_key.buf[ncnt + 2] = '\0';
55354220Sbostic 	key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
55454220Sbostic     }
55554220Sbostic     else
55654220Sbostic 	(void) node_enum(el, ptr->next, ncnt + 1);
55754220Sbostic 
55854220Sbostic     /* go to sibling if there is one */
55954220Sbostic     if (ptr->sibling)
56054220Sbostic 	(void) node_enum(el, ptr->sibling, cnt);
56154220Sbostic     return 0;
56254220Sbostic }
56354220Sbostic 
56454220Sbostic 
56554220Sbostic /* key_kprint():
56654220Sbostic  *	Print the specified key and its associated
56754220Sbostic  *	function specified by val
56854220Sbostic  */
56954624Schristos protected void
key_kprint(el,key,val,ntype)57054220Sbostic key_kprint(el, key, val, ntype)
57154220Sbostic     EditLine      *el;
57254220Sbostic     char          *key;
57354220Sbostic     key_value_t   *val;
57454220Sbostic     int            ntype;
57554220Sbostic {
57654220Sbostic     el_bindings_t *fp;
57754220Sbostic     char unparsbuf[EL_BUFSIZ];
57854220Sbostic     static char *fmt = "%-15s->  %s\n";
57954220Sbostic 
58054220Sbostic     if (val != NULL)
58154220Sbostic 	switch (ntype) {
58254220Sbostic 	case XK_STR:
58354220Sbostic 	case XK_EXE:
58454220Sbostic 	    (void) fprintf(el->el_errfile, fmt, key,
58554220Sbostic 			   key__decode_str(val->str, unparsbuf,
58654220Sbostic 					      ntype == XK_STR ? "\"\"" : "[]"));
58754220Sbostic 	    break;
58854220Sbostic 	case XK_CMD:
58954220Sbostic 	    for (fp = el->el_map.help; fp->name; fp++)
59054220Sbostic 		if (val->cmd == fp->func) {
59154220Sbostic 		    (void) fprintf(el->el_errfile, fmt, key, fp->name);
59254220Sbostic 		    break;
59354220Sbostic 		}
59454220Sbostic #ifdef DEBUG_KEY
59554220Sbostic 	    if (fp->name == NULL)
59654220Sbostic 		(void) fprintf(el->el_errfile, "BUG! Command not found.\n");
59754220Sbostic #endif
59854220Sbostic 
59954220Sbostic 	    break;
60054220Sbostic 	default:
60154220Sbostic 	    abort();
60254220Sbostic 	    break;
60354220Sbostic 	}
60454220Sbostic     else
60554220Sbostic 	(void) fprintf(el->el_errfile, fmt, key, "no input");
60654220Sbostic }
60754220Sbostic 
60854220Sbostic 
60954220Sbostic /* key__decode_char():
61054220Sbostic  *	Put a printable form of char in buf.
61154220Sbostic  */
61254220Sbostic private int
key__decode_char(buf,cnt,ch)61354220Sbostic key__decode_char(buf, cnt, ch)
61454220Sbostic     char *buf;
61554220Sbostic     int   cnt, ch;
61654220Sbostic {
61754220Sbostic     if (ch == 0) {
61854220Sbostic 	buf[cnt++] = '^';
61954220Sbostic 	buf[cnt] = '@';
62054220Sbostic 	return cnt;
62154220Sbostic     }
62254220Sbostic 
62354220Sbostic     if (iscntrl(ch)) {
62454220Sbostic 	buf[cnt++] = '^';
62554220Sbostic 	if (ch == '\177')
62654220Sbostic 	    buf[cnt] = '?';
62754220Sbostic 	else
62854220Sbostic 	    buf[cnt] = ch | 0100;
62954220Sbostic     }
63054220Sbostic     else if (ch == '^') {
63154220Sbostic 	buf[cnt++] = '\\';
63254220Sbostic 	buf[cnt] = '^';
63354220Sbostic     }
63454220Sbostic     else if (ch == '\\') {
63554220Sbostic 	buf[cnt++] = '\\';
63654220Sbostic 	buf[cnt] = '\\';
63754220Sbostic     }
63854220Sbostic     else if (ch == ' ' || (isprint(ch) && !isspace(ch))) {
63954220Sbostic 	buf[cnt] = ch;
64054220Sbostic     }
64154220Sbostic     else {
64254220Sbostic 	buf[cnt++] = '\\';
64354220Sbostic 	buf[cnt++] = ((ch >> 6) & 7) + '0';
64454220Sbostic 	buf[cnt++] = ((ch >> 3) & 7) + '0';
64554220Sbostic 	buf[cnt] = (ch & 7) + '0';
64654220Sbostic     }
64754220Sbostic     return cnt;
64854220Sbostic }
64954220Sbostic 
65054220Sbostic /* key__decode_str():
65154220Sbostic  *	Make a printable version of the ey
65254220Sbostic  */
65354220Sbostic protected char *
key__decode_str(str,buf,sep)65454220Sbostic key__decode_str(str, buf, sep)
65554220Sbostic     char   *str;
65654220Sbostic     char   *buf;
65754220Sbostic     char   *sep;
65854220Sbostic {
65954220Sbostic     char *b, *p;
66054220Sbostic 
66154220Sbostic     b = buf;
66254220Sbostic     if (sep[0] != '\0')
66354220Sbostic 	*b++ = sep[0];
66454220Sbostic     if (*str == 0) {
66554220Sbostic 	*b++ = '^';
66654220Sbostic 	*b++ = '@';
66754220Sbostic 	if (sep[0] != '\0' && sep[1] != '\0')
66854220Sbostic 	    *b++ = sep[1];
66954220Sbostic 	*b++ = 0;
67054220Sbostic 	return buf;
67154220Sbostic     }
67254220Sbostic 
67354220Sbostic     for (p = str; *p != 0; p++) {
67454220Sbostic 	if (iscntrl((unsigned char) *p)) {
67554220Sbostic 	    *b++ = '^';
67654220Sbostic 	    if (*p == '\177')
67754220Sbostic 		*b++ = '?';
67854220Sbostic 	    else
67954220Sbostic 		*b++ = *p | 0100;
68054220Sbostic 	}
68154220Sbostic 	else if (*p == '^' || *p == '\\') {
68254220Sbostic 	    *b++ = '\\';
68354220Sbostic 	    *b++ = *p;
68454220Sbostic 	}
68554220Sbostic 	else if (*p == ' ' || (isprint((unsigned char) *p) &&
68654220Sbostic 			       !isspace((unsigned char) *p))) {
68754220Sbostic 	    *b++ = *p;
68854220Sbostic 	}
68954220Sbostic 	else {
69054220Sbostic 	    *b++ = '\\';
69154220Sbostic 	    *b++ = ((*p >> 6) & 7) + '0';
69254220Sbostic 	    *b++ = ((*p >> 3) & 7) + '0';
69354220Sbostic 	    *b++ = (*p & 7) + '0';
69454220Sbostic 	}
69554220Sbostic     }
69654220Sbostic     if (sep[0] != '\0' && sep[1] != '\0')
69754220Sbostic 	*b++ = sep[1];
69854220Sbostic     *b++ = 0;
69954220Sbostic     return buf;			/* should check for overflow */
70054220Sbostic }
701