keymacro.c revision 84260
11558Srgrimes/*-
292058Sobrien * Copyright (c) 1992, 1993
392058Sobrien *	The Regents of the University of California.  All rights reserved.
492058Sobrien *
51558Srgrimes * This code is derived from software contributed to Berkeley by
61558Srgrimes * Christos Zoulas of Cornell University.
71558Srgrimes *
81558Srgrimes * Redistribution and use in source and binary forms, with or without
91558Srgrimes * modification, are permitted provided that the following conditions
101558Srgrimes * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 3. All advertising materials mentioning features or use of this software
171558Srgrimes *    must display the following acknowledgement:
181558Srgrimes *	This product includes software developed by the University of
191558Srgrimes *	California, Berkeley and its contributors.
201558Srgrimes * 4. Neither the name of the University nor the names of its contributors
211558Srgrimes *    may be used to endorse or promote products derived from this software
221558Srgrimes *    without specific prior written permission.
2392058Sobrien *
241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341558Srgrimes * SUCH DAMAGE.
351558Srgrimes *
361558Srgrimes *	$NetBSD: key.c,v 1.11 2001/01/23 15:55:30 jdolecek Exp $
371558Srgrimes */
381558Srgrimes
3992058Sobrien#include <sys/cdefs.h>
4092058Sobrien__FBSDID("$FreeBSD: head/lib/libedit/key.c 84260 2001-10-01 08:41:27Z obrien $");
411558Srgrimes#if !defined(lint) && !defined(SCCSID)
421558Srgrimesstatic char sccsid[] = "@(#)key.c	8.1 (Berkeley) 6/4/93";
43115449Sobrien#endif /* not lint && not SCCSID */
441558Srgrimes#include <sys/cdefs.h>
4536632Scharnier__FBSDID("$FreeBSD: head/lib/libedit/key.c 84260 2001-10-01 08:41:27Z obrien $");
461558Srgrimes
471558Srgrimes/*
481558Srgrimes * key.c: This module contains the procedures for maintaining
491558Srgrimes *	  the extended-key map.
501558Srgrimes *
511558Srgrimes *      An extended-key (key) is a sequence of keystrokes introduced
521558Srgrimes *	with an sequence introducer and consisting of an arbitrary
53115449Sobrien *	number of characters.  This module maintains a map (the el->el_key.map)
5436632Scharnier *	to convert these extended-key sequences into input strs
5599365Smarkm *	(XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
5699365Smarkm *
5799365Smarkm *      Warning:
581558Srgrimes *	  If key is a substr of some other keys, then the longer
59114552Sphk *	  keys are lost!!  That is, if the keys "abcd" and "abcef"
601558Srgrimes *	  are in el->el_key.map, adding the key "abc" will cause the first two
611558Srgrimes *	  definitions to be lost.
6213544Sjoerg *
63103669Sphk *      Restrictions:
641558Srgrimes *      -------------
65101994Sbmilekic *      1) It is not possible to have one key that is a
66227231Sae *	   substr of another.
671558Srgrimes */
68112307Sru#include "sys.h"
691558Srgrimes#include <string.h>
701558Srgrimes#include <stdlib.h>
711558Srgrimes
72114569Sphk#include "el.h"
7313544Sjoerg
7413544Sjoerg/*
7513544Sjoerg * The Nodes of the el->el_key.map.  The el->el_key.map is a linked list
761558Srgrimes * of these node elements
7726542Scharnier */
7859216Simpstruct key_node_t {
7999365Smarkm	char		ch;		/* single character of key 	 */
801558Srgrimes	int		type;		/* node type			 */
811558Srgrimes	key_value_t	val;		/* command code or pointer to str,  */
82114571Sphk					/* if this is a leaf 		 */
83227270Sae	struct key_node_t *next;	/* ptr to next char of this key  */
84114571Sphk	struct key_node_t *sibling;	/* ptr to another key with same prefix*/
85133347Sdes};
86114571Sphk
87133347Sdesprivate int		 node_trav(EditLine *, key_node_t *, char *,
88114571Sphk    key_value_t *);
89121222Sphkprivate int		 node__try(EditLine *, key_node_t *, const char *,
90114571Sphk    key_value_t *, int);
91114571Sphkprivate key_node_t	*node__get(int);
92114571Sphkprivate void		 node__put(EditLine *, key_node_t *);
93114571Sphkprivate int		 node__delete(EditLine *, key_node_t **, char *);
94114571Sphkprivate int		 node_lookup(EditLine *, char *, key_node_t *, int);
95114571Sphkprivate int		 node_enum(EditLine *, key_node_t *, int);
96114571Sphkprivate int		 key__decode_char(char *, int, int);
9713544Sjoerg
981558Srgrimes#define	KEY_BUFSIZ	EL_BUFSIZ
99174501Smarcel
1001558Srgrimes
101114571Sphk/* key_init():
102183143Slulf *	Initialize the key maps
103114571Sphk */
1041558Srgrimesprotected int
105114571Sphkkey_init(EditLine *el)
106114571Sphk{
107114574Sphk
108219449Suqs	el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ);
109114571Sphk	if (el->el_key.buf == NULL)
110114571Sphk		return (-1);
1111558Srgrimes	el->el_key.map = NULL;
11273034Sjwd	key_reset(el);
11373034Sjwd	return (0);
114114571Sphk}
115114571Sphk
116114571Sphk
11773034Sjwd/* key_end():
118114571Sphk *	Free the key maps
119114574Sphk */
120114571Sphkprotected void
1211558Srgrimeskey_end(EditLine *el)
122196383Smarcel{
123115995Sphk
124115995Sphk	el_free((ptr_t) el->el_key.buf);
125115995Sphk	el->el_key.buf = NULL;
126115995Sphk	/* XXX: provide a function to clear the keys */
127115995Sphk	el->el_key.map = NULL;
128115995Sphk}
129115696Sphk
130115696Sphk
131114551Sphk/* key_map_cmd():
132114550Sphk *	Associate cmd with a key value
133228417Sed */
134109872Sphkprotected key_value_t *
1351558Srgrimeskey_map_cmd(EditLine *el, int cmd)
1361558Srgrimes{
137112307Sru
138114571Sphk	el->el_key.val.cmd = (el_action_t) cmd;
139127650Sluigi	return (&el->el_key.val);
1401558Srgrimes}
14113544Sjoerg
14292541Simp
1431558Srgrimes/* key_map_str():
1441558Srgrimes *	Associate str with a key value
145183143Slulf */
146183143Slulfprotected key_value_t *
147183143Slulfkey_map_str(EditLine *el, char *str)
148183143Slulf{
149183143Slulf
1501558Srgrimes	el->el_key.val.str = str;
151163539Smaxim	return (&el->el_key.val);
1521558Srgrimes}
153114574Sphk
154114574Sphk
155114574Sphk/* key_reset():
1561558Srgrimes *	Takes all nodes on el->el_key.map and puts them on free list.  Then
1571558Srgrimes *	initializes el->el_key.map with arrow keys
1581558Srgrimes *	[Always bind the ansi arrow keys?]
1591558Srgrimes */
1601558Srgrimesprotected void
1611558Srgrimeskey_reset(EditLine *el)
162127650Sluigi{
163127650Sluigi
164127650Sluigi	node__put(el, el->el_key.map);
165112307Sru	el->el_key.map = NULL;
166115948Sphk	return;
167115948Sphk}
168115948Sphk
169115948Sphk
170115696Sphk/* key_get():
171115696Sphk *	Calls the recursive function with entry point el->el_key.map
172114550Sphk *      Looks up *ch in map and then reads characters until a
173114571Sphk *      complete match is found or a mismatch occurs. Returns the
174114571Sphk *      type of the match found (XK_STR, XK_CMD, or XK_EXE).
175114550Sphk *      Returns NULL in val.str and XK_STR for no match.
176112307Sru *      The last character read is returned in *ch.
17773034Sjwd */
17873034Sjwdprotected int
17973034Sjwdkey_get(EditLine *el, char *ch, key_value_t *val)
1801558Srgrimes{
1811558Srgrimes
1821558Srgrimes	return (node_trav(el, el->el_key.map, ch, val));
1831558Srgrimes}
1841558Srgrimes
1851558Srgrimes
1861558Srgrimes/* key_add():
1871558Srgrimes *      Adds key to the el->el_key.map and associates the value in val with it.
1881558Srgrimes *      If key is already is in el->el_key.map, the new code is applied to the
1891558Srgrimes *      existing key. Ntype specifies if code is a command, an
1901558Srgrimes *      out str or a unix command.
191114571Sphk */
192114571Sphkprotected void
193114571Sphkkey_add(EditLine *el, const char *key, key_value_t *val, int ntype)
194114571Sphk{
1951558Srgrimes
1961558Srgrimes	if (key[0] == '\0') {
1971558Srgrimes		(void) fprintf(el->el_errfile,
1981558Srgrimes		    "key_add: Null extended-key not allowed.\n");
1991558Srgrimes		return;
2001558Srgrimes	}
2011558Srgrimes	if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
2021558Srgrimes		(void) fprintf(el->el_errfile,
2031558Srgrimes		    "key_add: sequence-lead-in command not allowed\n");
2041558Srgrimes		return;
2051558Srgrimes	}
2061558Srgrimes	if (el->el_key.map == NULL)
207114571Sphk		/* tree is initially empty.  Set up new node to match key[0] */
2081558Srgrimes		el->el_key.map = node__get(key[0]);
2091558Srgrimes			/* it is properly initialized */
210115995Sphk
211115995Sphk	/* Now recurse through el->el_key.map */
2121558Srgrimes	(void) node__try(el, el->el_key.map, key, val, ntype);
213114569Sphk	return;
214127650Sluigi}
215139856Srse
216114569Sphk
217183143Slulf/* key_clear():
218183143Slulf *
219183143Slulf */
220183143Slulfprotected void
221183143Slulfkey_clear(EditLine *el, el_action_t *map, char *in)
222183143Slulf{
223183143Slulf
224183143Slulf	if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) &&
225183143Slulf	    ((map == el->el_map.key &&
226183143Slulf	    el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) ||
227183143Slulf	    (map == el->el_map.alt &&
228183143Slulf	    el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN)))
229183487Slulf		(void) key_delete(el, in);
230183496Slulf}
231183143Slulf
232183143Slulf
233183496Slulf/* key_delete():
2341558Srgrimes *      Delete the key and all longer keys staring with key, if
2351558Srgrimes *      they exists.
236114571Sphk */
237114571Sphkprotected int
238114571Sphkkey_delete(EditLine *el, char *key)
239114571Sphk{
240114571Sphk
2411558Srgrimes	if (key[0] == '\0') {
2421558Srgrimes		(void) fprintf(el->el_errfile,
24348957Sbillf		    "key_delete: Null extended-key not allowed.\n");
24448957Sbillf		return (-1);
24548957Sbillf	}
2461558Srgrimes	if (el->el_key.map == NULL)
2471558Srgrimes		return (0);
2481558Srgrimes
249114571Sphk	(void) node__delete(el, &el->el_key.map, key);
250121222Sphk	return (0);
251114571Sphk}
2521558Srgrimes
2531558Srgrimes
2541558Srgrimes/* key_print():
2551558Srgrimes *	Print the binding associated with key key.
2561558Srgrimes *	Print entire el->el_key.map if null
257114571Sphk */
258114571Sphkprotected void
259114571Sphkkey_print(EditLine *el, char *key)
2601558Srgrimes{
2611558Srgrimes
2621558Srgrimes	/* do nothing if el->el_key.map is empty and null key specified */
2631558Srgrimes	if (el->el_key.map == NULL && *key == 0)
2641558Srgrimes		return;
2651558Srgrimes
266114569Sphk	el->el_key.buf[0] = '"';
267114571Sphk	if (node_lookup(el, key, el->el_key.map, 1) <= -1)
26837865Sbde		/* key is not bound */
26937865Sbde		(void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n",
270114571Sphk		    key);
2711558Srgrimes	return;
2721558Srgrimes}
2731558Srgrimes
274114571Sphk
275114571Sphk/* node_trav():
276114571Sphk *	recursively traverses node in tree until match or mismatch is
277114571Sphk * 	found.  May read in more characters.
278114571Sphk */
2791558Srgrimesprivate int
280114571Sphknode_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val)
281114571Sphk{
282121222Sphk
283114571Sphk	if (ptr->ch == *ch) {
284114571Sphk		/* match found */
2851558Srgrimes		if (ptr->next) {
2861558Srgrimes			/* key not complete so get next char */
2871558Srgrimes			if (el_getc(el, ch) != 1) {	/* if EOF or error */
2881558Srgrimes				val->cmd = ED_END_OF_FILE;
289114571Sphk				return (XK_CMD);
290121222Sphk				/* PWP: Pretend we just read an end-of-file */
2911558Srgrimes			}
292114571Sphk			return (node_trav(el, ptr->next, ch, val));
293114571Sphk		} else {
294114571Sphk			*val = ptr->val;
2951558Srgrimes			if (ptr->type != XK_CMD)
2961558Srgrimes				*ch = '\0';
2971558Srgrimes			return (ptr->type);
2981558Srgrimes		}
2991558Srgrimes	} else {
300121222Sphk		/* no match found here */
301121222Sphk		if (ptr->sibling) {
302121222Sphk			/* try next sibling */
303121222Sphk			return (node_trav(el, ptr->sibling, ch, val));
304121222Sphk		} else {
305121222Sphk			/* no next sibling -- mismatch */
306174501Smarcel			val->str = NULL;
307121222Sphk			return (XK_STR);
308121222Sphk		}
309121222Sphk	}
310121222Sphk}
311121222Sphk
312121222Sphk
313121222Sphk/* node__try():
314121222Sphk * 	Find a node that matches *str or allocate a new one
315121222Sphk */
316121222Sphkprivate int
317121222Sphknode__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ntype)
3181558Srgrimes{
319111286Sru
3201558Srgrimes	if (ptr->ch != *str) {
321114571Sphk		key_node_t *xm;
322114571Sphk
3231558Srgrimes		for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
32492541Simp			if (xm->sibling->ch == *str)
32513550Sjoerg				break;
32613550Sjoerg		if (xm->sibling == NULL)
32713550Sjoerg			xm->sibling = node__get(*str);	/* setup new node */
32813550Sjoerg		ptr = xm->sibling;
32913544Sjoerg	}
33036632Scharnier	if (*++str == '\0') {
33136632Scharnier		/* we're there */
3321558Srgrimes		if (ptr->next != NULL) {
3331558Srgrimes			node__put(el, ptr->next);
3341558Srgrimes				/* lose longer keys with this prefix */
3351558Srgrimes			ptr->next = NULL;
336114571Sphk		}
337114571Sphk		switch (ptr->type) {
3381558Srgrimes		case XK_CMD:
339209614Sjh		case XK_NOD:
340114571Sphk			break;
341114571Sphk		case XK_STR:
342114571Sphk		case XK_EXE:
343114571Sphk			if (ptr->val.str)
344114571Sphk				el_free((ptr_t) ptr->val.str);
345114571Sphk			break;
346114571Sphk		default:
347114571Sphk			EL_ABORT((el->el_errfile, "Bad XK_ type %d\n",
348219448Suqs			    ptr->type));
349209614Sjh			break;
350114571Sphk		}
351216095Skevlo
352114571Sphk		switch (ptr->type = ntype) {
353133347Sdes		case XK_CMD:
354114571Sphk			ptr->val = *val;
355114571Sphk			break;
356114571Sphk		case XK_STR:
357114571Sphk		case XK_EXE:
358227270Sae			ptr->val.str = strdup(val->str);
359211873Sjh			break;
360211873Sjh		default:
361211873Sjh			EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
362211873Sjh			break;
363211873Sjh		}
364211873Sjh	} else {
365211873Sjh		/* still more chars to go */
366211873Sjh		if (ptr->next == NULL)
367211873Sjh			ptr->next = node__get(*str);	/* setup new node */
368211873Sjh		(void) node__try(el, ptr->next, str, val, ntype);
369227270Sae	}
370211873Sjh	return (0);
371211873Sjh}
372211873Sjh
373211873Sjh
374211873Sjh/* node__delete():
375211873Sjh *	Delete node that matches str
376211873Sjh */
377211873Sjhprivate int
378211873Sjhnode__delete(EditLine *el, key_node_t **inptr, char *str)
379211873Sjh{
380211873Sjh	key_node_t *ptr;
381114571Sphk	key_node_t *prev_ptr = NULL;
382114571Sphk
383211873Sjh	ptr = *inptr;
384114569Sphk
385114569Sphk	if (ptr->ch != *str) {
386114571Sphk		key_node_t *xm;
38738384Sdfr
38873034Sjwd		for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
389114574Sphk			if (xm->sibling->ch == *str)
390114571Sphk				break;
39173034Sjwd		if (xm->sibling == NULL)
392109878Sphk			return (0);
393109878Sphk		prev_ptr = xm;
394109878Sphk		ptr = xm->sibling;
395109878Sphk	}
396109878Sphk	if (*++str == '\0') {
397109878Sphk		/* we're there */
398114571Sphk		if (prev_ptr == NULL)
399114571Sphk			*inptr = ptr->sibling;
400114673Sphk		else
401114673Sphk			prev_ptr->sibling = ptr->sibling;
402196383Smarcel		ptr->sibling = NULL;
403229049Ssobomax		node__put(el, ptr);
404115696Sphk		return (1);
405114569Sphk	} else if (ptr->next != NULL &&
406114569Sphk	    node__delete(el, &ptr->next, str) == 1) {
407114569Sphk		if (ptr->next != NULL)
408127650Sluigi			return (0);
409127650Sluigi		if (prev_ptr == NULL)
410127650Sluigi			*inptr = ptr->sibling;
411211873Sjh		else
412211873Sjh			prev_ptr->sibling = ptr->sibling;
413211873Sjh		ptr->sibling = NULL;
414227270Sae		node__put(el, ptr);
415227296Sae		return (1);
416227296Sae	} else {
417227270Sae		return (0);
418227270Sae	}
419227270Sae}
420227270Sae
421227270Sae
422227270Sae/* node__put():
423227270Sae *	Puts a tree of nodes onto free list using free(3).
424227270Sae */
425227270Saeprivate void
426211873Sjhnode__put(EditLine *el, key_node_t *ptr)
427227270Sae{
428211873Sjh	if (ptr == NULL)
429211873Sjh		return;
430127650Sluigi
431183143Slulf	if (ptr->next != NULL) {
432115624Sphk		node__put(el, ptr->next);
433115624Sphk		ptr->next = NULL;
434114569Sphk	}
435183143Slulf	node__put(el, ptr->sibling);
436133347Sdes
437229049Ssobomax	switch (ptr->type) {
438114569Sphk	case XK_CMD:
439114571Sphk	case XK_NOD:
440114571Sphk		break;
441114571Sphk	case XK_EXE:
442114571Sphk	case XK_STR:
443114571Sphk		if (ptr->val.str != NULL)
444114569Sphk			el_free((ptr_t) ptr->val.str);
445114569Sphk		break;
446115624Sphk	default:
447115624Sphk		EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type));
448114569Sphk		break;
449183143Slulf	}
450114571Sphk	el_free((ptr_t) ptr);
451114569Sphk}
452114571Sphk
453114571Sphk
454114571Sphk/* node__get():
455114571Sphk *	Returns pointer to an key_node_t for ch.
456114571Sphk */
457114569Sphkprivate key_node_t *
458114569Sphknode__get(int ch)
459114569Sphk{
460114571Sphk	key_node_t *ptr;
461114569Sphk
462114569Sphk	ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
463114569Sphk	if (ptr == NULL)
464114569Sphk		return NULL;
465114569Sphk	ptr->ch = ch;
466109878Sphk	ptr->type = XK_NOD;
4671558Srgrimes	ptr->val.str = NULL;
4681558Srgrimes	ptr->next = NULL;
4691558Srgrimes	ptr->sibling = NULL;
470127650Sluigi	return (ptr);
471127650Sluigi}
472127650Sluigi
473127650Sluigi
474127650Sluigi
475127650Sluigi/* node_lookup():
476127650Sluigi *	look for the str starting at node ptr.
477127650Sluigi *	Print if last node
478127650Sluigi */
479127650Sluigiprivate int
480127650Sluiginode_lookup(EditLine *el, char *str, key_node_t *ptr, int cnt)
481127650Sluigi{
482127650Sluigi	int ncnt;
483127650Sluigi
484127650Sluigi	if (ptr == NULL)
4851558Srgrimes		return (-1);	/* cannot have null ptr */
4861558Srgrimes
4871558Srgrimes	if (*str == 0) {
488114571Sphk		/* no more chars in str.  node_enum from here. */
489114571Sphk		(void) node_enum(el, ptr, cnt);
4901558Srgrimes		return (0);
491209614Sjh	} else {
492196383Smarcel		/* If match put this char into el->el_key.buf.  Recurse */
493114673Sphk		if (ptr->ch == *str) {
494114569Sphk			/* match found */
4951558Srgrimes			ncnt = key__decode_char(el->el_key.buf, cnt,
496114569Sphk			    (unsigned char) ptr->ch);
497114569Sphk			if (ptr->next != NULL)
498215704Sbrucec				/* not yet at leaf */
499127650Sluigi				return (node_lookup(el, str + 1, ptr->next,
500127650Sluigi				    ncnt + 1));
501183143Slulf			else {
502183143Slulf			    /* next node is null so key should be complete */
503183143Slulf				if (str[1] == 0) {
504183143Slulf					el->el_key.buf[ncnt + 1] = '"';
505183143Slulf					el->el_key.buf[ncnt + 2] = '\0';
506115696Sphk					key_kprint(el, el->el_key.buf,
507134973Sbrooks					    &ptr->val, ptr->type);
508134973Sbrooks					return (0);
509134973Sbrooks				} else
510114550Sphk					return (-1);
511209614Sjh					/* mismatch -- str still has chars */
512209614Sjh			}
513114569Sphk		} else {
514209614Sjh			/* no match found try sibling */
515209614Sjh			if (ptr->sibling)
516114569Sphk				return (node_lookup(el, str, ptr->sibling,
517115696Sphk				    cnt));
518115696Sphk			else
519115696Sphk				return (-1);
520114571Sphk		}
521114571Sphk	}
522114673Sphk}
523183143Slulf
524183143Slulf
525196383Smarcel/* node_enum():
526196383Smarcel *	Traverse the node printing the characters it is bound in buffer
527196383Smarcel */
528196383Smarcelprivate int
529196383Smarcelnode_enum(EditLine *el, key_node_t *ptr, int cnt)
530196383Smarcel{
531196383Smarcel	int ncnt;
532196383Smarcel
533196383Smarcel	if (cnt >= KEY_BUFSIZ - 5) {	/* buffer too small */
534196383Smarcel		el->el_key.buf[++cnt] = '"';
535114673Sphk		el->el_key.buf[++cnt] = '\0';
536196383Smarcel		(void) fprintf(el->el_errfile,
537196383Smarcel		    "Some extended keys too long for internal print buffer");
538114673Sphk		(void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
539196383Smarcel		return (0);
540196383Smarcel	}
541196383Smarcel	if (ptr == NULL) {
542196383Smarcel#ifdef DEBUG_EDIT
543196383Smarcel		(void) fprintf(el->el_errfile,
544196383Smarcel		    "node_enum: BUG!! Null ptr passed\n!");
545196383Smarcel#endif
546196383Smarcel		return (-1);
547114571Sphk	}
5481558Srgrimes	/* put this char at end of str */
5491558Srgrimes	ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch);
5501558Srgrimes	if (ptr->next == NULL) {
551114571Sphk		/* print this key and function */
55292541Simp		el->el_key.buf[ncnt + 1] = '"';
5531558Srgrimes		el->el_key.buf[ncnt + 2] = '\0';
55492541Simp		key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
55592541Simp	} else
5561558Srgrimes		(void) node_enum(el, ptr->next, ncnt + 1);
557114571Sphk
558114571Sphk	/* go to sibling if there is one */
559114571Sphk	if (ptr->sibling)
5601558Srgrimes		(void) node_enum(el, ptr->sibling, cnt);
561114574Sphk	return (0);
562114574Sphk}
563114574Sphk
564114574Sphk
565114574Sphk/* key_kprint():
566114574Sphk *	Print the specified key and its associated
567114574Sphk *	function specified by val
568114574Sphk */
569114574Sphkprotected void
570114574Sphkkey_kprint(EditLine *el, char *key, key_value_t *val, int ntype)
571114574Sphk{
572114574Sphk	el_bindings_t *fp;
573114574Sphk	char unparsbuf[EL_BUFSIZ];
574114574Sphk	static const char fmt[] = "%-15s->  %s\n";
575114574Sphk
576114574Sphk	if (val != NULL)
577114574Sphk		switch (ntype) {
578114574Sphk		case XK_STR:
579114574Sphk		case XK_EXE:
580114574Sphk			(void) fprintf(el->el_outfile, fmt, key,
581114574Sphk			    key__decode_str(val->str, unparsbuf,
582114574Sphk				ntype == XK_STR ? "\"\"" : "[]"));
583114574Sphk			break;
584114574Sphk		case XK_CMD:
585114574Sphk			for (fp = el->el_map.help; fp->name; fp++)
586114574Sphk				if (val->cmd == fp->func) {
587114574Sphk					(void) fprintf(el->el_outfile, fmt,
588114574Sphk					    key, fp->name);
589114574Sphk					break;
590114574Sphk				}
591114574Sphk#ifdef DEBUG_KEY
592114574Sphk			if (fp->name == NULL)
593114574Sphk				(void) fprintf(el->el_outfile,
594114574Sphk				    "BUG! Command not found.\n");
595114574Sphk#endif
596114574Sphk
597114574Sphk			break;
598114574Sphk		default:
599114574Sphk			EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype));
600114574Sphk			break;
601114574Sphk		}
602114574Sphk	else
6031558Srgrimes		(void) fprintf(el->el_outfile, fmt, key, "no input");
604219449Suqs}
6051558Srgrimes
6061558Srgrimes
6071558Srgrimes/* key__decode_char():
608219449Suqs *	Put a printable form of char in buf.
60937234Sbde */
610107041Sjulianprivate int
6111558Srgrimeskey__decode_char(char *buf, int cnt, int ch)
6121558Srgrimes{
6131558Srgrimes	ch = (unsigned char)ch;
6141558Srgrimes
6151558Srgrimes	if (ch == 0) {
6161558Srgrimes		buf[cnt++] = '^';
617219449Suqs		buf[cnt] = '@';
61837234Sbde		return (cnt);
61937234Sbde	}
6201558Srgrimes	if (iscntrl(ch)) {
6211558Srgrimes		buf[cnt++] = '^';
6221558Srgrimes		if (ch == 0177)
623219449Suqs			buf[cnt] = '?';
62437234Sbde		else
62537234Sbde			buf[cnt] = toascii(ch) | 0100;
6261558Srgrimes	} else if (ch == '^') {
6271558Srgrimes		buf[cnt++] = '\\';
6281558Srgrimes		buf[cnt] = '^';
6295393Sgibbs	} else if (ch == '\\') {
63037234Sbde		buf[cnt++] = '\\';
63137234Sbde		buf[cnt] = '\\';
63237234Sbde	} else if (ch == ' ' || (isprint(ch) && !isspace(ch))) {
6335393Sgibbs		buf[cnt] = ch;
6345393Sgibbs	} else {
6355393Sgibbs		buf[cnt++] = '\\';
6361558Srgrimes		buf[cnt++] = (((unsigned int) ch >> 6) & 7) + '0';
6371558Srgrimes		buf[cnt++] = (((unsigned int) ch >> 3) & 7) + '0';
6381558Srgrimes		buf[cnt] = (ch & 7) + '0';
6391558Srgrimes	}
640114574Sphk	return (cnt);
641114574Sphk}
642114574Sphk
643114571Sphk/* key__decode_str():
6441558Srgrimes *	Make a printable version of the ey
6451558Srgrimes */
6461558Srgrimesprotected char *
6471558Srgrimeskey__decode_str(char *str, char *buf, char *sep)
6481558Srgrimes{
649114571Sphk	char *b, *p;
650114571Sphk
6511558Srgrimes	b = buf;
65292541Simp	if (sep[0] != '\0')
6531558Srgrimes		*b++ = sep[0];
65424180Simp	if (*str == 0) {
6551558Srgrimes		*b++ = '^';
65624180Simp		*b++ = '@';
65724180Simp		if (sep[0] != '\0' && sep[1] != '\0')
65836632Scharnier			*b++ = sep[1];
6591558Srgrimes		*b++ = 0;
6601558Srgrimes		return (buf);
661114571Sphk	}
66224180Simp	for (p = str; *p != 0; p++) {
6631558Srgrimes		if (iscntrl((unsigned char) *p)) {
6641558Srgrimes			*b++ = '^';
6651558Srgrimes			if (*p == '\177')
66624180Simp				*b++ = '?';
66724180Simp			else
66836632Scharnier				*b++ = toascii(*p) | 0100;
6691558Srgrimes		} else if (*p == '^' || *p == '\\') {
6701558Srgrimes			*b++ = '\\';
6711558Srgrimes			*b++ = *p;
672114571Sphk		} else if (*p == ' ' || (isprint((unsigned char) *p) &&
673114571Sphk			!isspace((unsigned char) *p))) {
674114571Sphk			*b++ = *p;
675114571Sphk		} else {
676114571Sphk			*b++ = '\\';
6771558Srgrimes			*b++ = (((unsigned int) *p >> 6) & 7) + '0';
6781558Srgrimes			*b++ = (((unsigned int) *p >> 3) & 7) + '0';
6791558Srgrimes			*b++ = (*p & 7) + '0';
6801558Srgrimes		}
681114571Sphk	}
682114571Sphk	if (sep[0] != '\0' && sep[1] != '\0')
6831558Srgrimes		*b++ = sep[1];
6841558Srgrimes	*b++ = 0;
6851558Srgrimes	return (buf);		/* should check for overflow */
6861558Srgrimes}
6871558Srgrimes