xref: /original-bsd/lib/libedit/key.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Christos Zoulas of Cornell University.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if !defined(lint) && !defined(SCCSID)
12 static char sccsid[] = "@(#)key.c	8.1 (Berkeley) 06/04/93";
13 #endif /* not lint && not SCCSID */
14 
15 /*
16  * key.c: This module contains the procedures for maintaining
17  *	  the extended-key map.
18  *
19  *      An extended-key (key) is a sequence of keystrokes introduced
20  *	with an sequence introducer and consisting of an arbitrary
21  *	number of characters.  This module maintains a map (the el->el_key.map)
22  *	to convert these extended-key sequences into input strs
23  *	(XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
24  *
25  *      Warning:
26  *	  If key is a substr of some other keys, then the longer
27  *	  keys are lost!!  That is, if the keys "abcd" and "abcef"
28  *	  are in el->el_key.map, adding the key "abc" will cause the first two
29  *	  definitions to be lost.
30  *
31  *      Restrictions:
32  *      -------------
33  *      1) It is not possible to have one key that is a
34  *	   substr of another.
35  */
36 #include "sys.h"
37 #include <string.h>
38 #include <stdlib.h>
39 
40 #include "el.h"
41 
42 /*
43  * The Nodes of the el->el_key.map.  The el->el_key.map is a linked list
44  * of these node elements
45  */
46 struct key_node_t {
47     char        ch;		/* single character of key 		*/
48     int         type;		/* node type				*/
49     key_value_t val; 		/* command code or pointer to str, 	*/
50 				/* if this is a leaf 			*/
51     struct key_node_t *next;	/* ptr to next char of this key 	*/
52     struct key_node_t *sibling;	/* ptr to another key with same prefix 	*/
53 };
54 
55 private	int            node_trav	__P((EditLine *, key_node_t *, char *,
56 					     key_value_t *));
57 private	int            node__try	__P((key_node_t *, char *,
58 					     key_value_t *, int));
59 private	key_node_t    *node__get	__P((int));
60 private	void	       node__put	__P((key_node_t *));
61 private	int	       node__delete	__P((key_node_t **, char *));
62 private	int	       node_lookup 	__P((EditLine *, char *, key_node_t *,
63 					     int));
64 private	int	       node_enum	__P((EditLine *, key_node_t *, int));
65 private	int	       key__decode_char	__P((char *, int, int));
66 
67 #define KEY_BUFSIZ	EL_BUFSIZ
68 
69 
70 /* key_init():
71  *	Initialize the key maps
72  */
73 protected int
74 key_init(el)
75     EditLine *el;
76 {
77     el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ);
78     el->el_key.map = NULL;
79     key_reset(el);
80     return 0;
81 }
82 
83 
84 /* key_end():
85  *	Free the key maps
86  */
87 protected void
88 key_end(el)
89     EditLine *el;
90 {
91     el_free((ptr_t) el->el_key.buf);
92     el->el_key.buf = NULL;
93     /* XXX: provide a function to clear the keys */
94     el->el_key.map = NULL;
95 }
96 
97 
98 /* key_map_cmd():
99  *	Associate cmd with a key value
100  */
101 protected key_value_t *
102 key_map_cmd(el, cmd)
103     EditLine *el;
104     int cmd;
105 {
106     el->el_key.val.cmd = (el_action_t) cmd;
107     return &el->el_key.val;
108 }
109 
110 
111 /* key_map_str():
112  *	Associate str with a key value
113  */
114 protected key_value_t *
115 key_map_str(el, str)
116     EditLine *el;
117     char  *str;
118 {
119     el->el_key.val.str = str;
120     return &el->el_key.val;
121 }
122 
123 
124 /* key_reset():
125  *	Takes all nodes on el->el_key.map and puts them on free list.  Then
126  *	initializes el->el_key.map with arrow keys
127  *	[Always bind the ansi arrow keys?]
128  */
129 protected void
130 key_reset(el)
131     EditLine *el;
132 {
133     node__put(el->el_key.map);
134     el->el_key.map = NULL;
135     return;
136 }
137 
138 
139 /* key_get():
140  *	Calls the recursive function with entry point el->el_key.map
141  *      Looks up *ch in map and then reads characters until a
142  *      complete match is found or a mismatch occurs. Returns the
143  *      type of the match found (XK_STR, XK_CMD, or XK_EXE).
144  *      Returns NULL in val.str and XK_STR for no match.
145  *      The last character read is returned in *ch.
146  */
147 protected int
148 key_get(el, ch, val)
149     EditLine    *el;
150     char        *ch;
151     key_value_t *val;
152 {
153     return node_trav(el, el->el_key.map, ch, val);
154 }
155 
156 
157 
158 /* key_add():
159  *      Adds key to the el->el_key.map and associates the value in val with it.
160  *      If key is already is in el->el_key.map, the new code is applied to the
161  *      existing key. Ntype specifies if code is a command, an
162  *      out str or a unix command.
163  */
164 protected void
165 key_add(el, key, val, ntype)
166     EditLine    *el;
167     char        *key;
168     key_value_t *val;
169     int          ntype;
170 {
171     if (key[0] == '\0') {
172 	(void) fprintf(el->el_errfile,
173 		       "key_add: Null extended-key not allowed.\n");
174 	return;
175     }
176 
177     if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) {
178 	(void) fprintf(el->el_errfile,
179 		       "key_add: sequence-lead-in command not allowed\n");
180 	return;
181     }
182 
183     if (el->el_key.map == NULL)
184 	/* tree is initially empty.  Set up new node to match key[0] */
185 	el->el_key.map = node__get(key[0]);	/* it is properly initialized */
186 
187     /* Now recurse through el->el_key.map */
188     (void) node__try(el->el_key.map, key, val, ntype);
189     return;
190 }
191 
192 
193 /* key_clear():
194  *
195  */
196 protected void
197 key_clear(el, map, in)
198     EditLine *el;
199     el_action_t *map;
200     char   *in;
201 {
202     if ((map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) &&
203 	((map == el->el_map.key &&
204 	  el->el_map.alt[(unsigned char) *in] != ED_SEQUENCE_LEAD_IN) ||
205 	 (map == el->el_map.alt &&
206 	  el->el_map.key[(unsigned char) *in] != ED_SEQUENCE_LEAD_IN)))
207 	(void) key_delete(el, in);
208 }
209 
210 
211 /* key_delete():
212  *      Delete the key and all longer keys staring with key, if
213  *      they exists.
214  */
215 protected int
216 key_delete(el, key)
217     EditLine *el;
218     char   *key;
219 {
220     if (key[0] == '\0') {
221 	(void) fprintf(el->el_errfile,
222 		       "key_delete: Null extended-key not allowed.\n");
223 	return -1;
224     }
225 
226     if (el->el_key.map == NULL)
227 	return 0;
228 
229     (void) node__delete(&el->el_key.map, key);
230     return 0;
231 }
232 
233 
234 /* key_print():
235  *	Print the binding associated with key key.
236  *	Print entire el->el_key.map if null
237  */
238 protected void
239 key_print(el, key)
240     EditLine *el;
241     char   *key;
242 {
243     /* do nothing if el->el_key.map is empty and null key specified */
244     if (el->el_key.map == NULL && *key == 0)
245 	return;
246 
247     el->el_key.buf[0] =  '"';
248     if (node_lookup(el, key, el->el_key.map, 1) <= -1)
249 	/* key is not bound */
250 	(void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n", key);
251     return;
252 }
253 
254 
255 /* node_trav():
256  *	recursively traverses node in tree until match or mismatch is
257  * 	found.  May read in more characters.
258  */
259 private int
260 node_trav(el, ptr, ch, val)
261     EditLine     *el;
262     key_node_t   *ptr;
263     char         *ch;
264     key_value_t  *val;
265 {
266     if (ptr->ch == *ch) {
267 	/* match found */
268 	if (ptr->next) {
269 	    /* key not complete so get next char */
270 	    if (el_getc(el, ch) != 1) {	/* if EOF or error */
271 		val->cmd = ED_END_OF_FILE;
272 		return XK_CMD;/* PWP: Pretend we just read an end-of-file */
273 	    }
274 	    return node_trav(el, ptr->next, ch, val);
275 	}
276 	else {
277 	    *val = ptr->val;
278 	    if (ptr->type != XK_CMD)
279 		*ch = '\0';
280 	    return ptr->type;
281 	}
282     }
283     else {
284 	/* no match found here */
285 	if (ptr->sibling) {
286 	    /* try next sibling */
287 	    return node_trav(el, ptr->sibling, ch, val);
288 	}
289 	else {
290 	    /* no next sibling -- mismatch */
291 	    val->str = NULL;
292 	    return XK_STR;
293 	}
294     }
295 }
296 
297 
298 /* node__try():
299  * 	Find a node that matches *str or allocate a new one
300  */
301 private int
302 node__try(ptr, str, val, ntype)
303     key_node_t   *ptr;
304     char         *str;
305     key_value_t  *val;
306     int           ntype;
307 {
308     if (ptr->ch != *str) {
309 	key_node_t *xm;
310 
311 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
312 	    if (xm->sibling->ch == *str)
313 		break;
314 	if (xm->sibling == NULL)
315 	    xm->sibling = node__get(*str);	/* setup new node */
316 	ptr = xm->sibling;
317     }
318 
319     if (*++str == '\0') {
320 	/* we're there */
321 	if (ptr->next != NULL) {
322 	    node__put(ptr->next);	/* lose longer keys with this prefix */
323 	    ptr->next = NULL;
324 	}
325 	switch (ptr->type) {
326 	case XK_CMD:
327 	case XK_NOD:
328 	    break;
329 	case XK_STR:
330 	case XK_EXE:
331 	    if (ptr->val.str)
332 		el_free((ptr_t) ptr->val.str);
333 	    break;
334 	default:
335 	    abort();
336 	    break;
337 	}
338 
339 	switch (ptr->type = ntype) {
340 	case XK_CMD:
341 	    ptr->val = *val;
342 	    break;
343 	case XK_STR:
344 	case XK_EXE:
345 	    ptr->val.str = strdup(val->str);
346 	    break;
347 	default:
348 	    abort();
349 	    break;
350 	}
351     }
352     else {
353 	/* still more chars to go */
354 	if (ptr->next == NULL)
355 	    ptr->next = node__get(*str);	/* setup new node */
356 	(void) node__try(ptr->next, str, val, ntype);
357     }
358     return 0;
359 }
360 
361 
362 /* node__delete():
363  *	Delete node that matches str
364  */
365 private int
366 node__delete(inptr, str)
367     key_node_t **inptr;
368     char   *str;
369 {
370     key_node_t *ptr;
371     key_node_t *prev_ptr = NULL;
372 
373     ptr = *inptr;
374 
375     if (ptr->ch != *str) {
376 	key_node_t *xm;
377 
378 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
379 	    if (xm->sibling->ch == *str)
380 		break;
381 	if (xm->sibling == NULL)
382 	    return 0;
383 	prev_ptr = xm;
384 	ptr = xm->sibling;
385     }
386 
387     if (*++str == '\0') {
388 	/* we're there */
389 	if (prev_ptr == NULL)
390 	    *inptr = ptr->sibling;
391 	else
392 	    prev_ptr->sibling = ptr->sibling;
393 	ptr->sibling = NULL;
394 	node__put(ptr);
395 	return 1;
396     }
397     else if (ptr->next != NULL && node__delete(&ptr->next, str) == 1) {
398 	if (ptr->next != NULL)
399 	    return 0;
400 	if (prev_ptr == NULL)
401 	    *inptr = ptr->sibling;
402 	else
403 	    prev_ptr->sibling = ptr->sibling;
404 	ptr->sibling = NULL;
405 	node__put(ptr);
406 	return 1;
407     }
408     else {
409 	return 0;
410     }
411 }
412 
413 /* node__put():
414  *	Puts a tree of nodes onto free list using free(3).
415  */
416 private void
417 node__put(ptr)
418     key_node_t *ptr;
419 {
420     if (ptr == NULL)
421 	return;
422 
423     if (ptr->next != NULL) {
424 	node__put(ptr->next);
425 	ptr->next = NULL;
426     }
427 
428     node__put(ptr->sibling);
429 
430     switch (ptr->type) {
431     case XK_CMD:
432     case XK_NOD:
433 	break;
434     case XK_EXE:
435     case XK_STR:
436 	if (ptr->val.str != NULL)
437 	    el_free((ptr_t) ptr->val.str);
438 	break;
439     default:
440 	abort();
441 	break;
442     }
443     el_free((ptr_t) ptr);
444 }
445 
446 
447 /* node__get():
448  *	Returns pointer to an key_node_t for ch.
449  */
450 private key_node_t *
451 node__get(ch)
452     int    ch;
453 {
454     key_node_t *ptr;
455 
456     ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
457     ptr->ch = ch;
458     ptr->type = XK_NOD;
459     ptr->val.str = NULL;
460     ptr->next = NULL;
461     ptr->sibling = NULL;
462     return ptr;
463 }
464 
465 
466 
467 /* node_lookup():
468  *	look for the str starting at node ptr.
469  *	Print if last node
470  */
471 private int
472 node_lookup(el, str, ptr, cnt)
473     EditLine   *el;
474     char       *str;
475     key_node_t *ptr;
476     int         cnt;
477 {
478     int     ncnt;
479 
480     if (ptr == NULL)
481 	return -1;		/* cannot have null ptr */
482 
483     if (*str == 0) {
484 	/* no more chars in str.  node_enum from here. */
485 	(void) node_enum(el, ptr, cnt);
486 	return 0;
487     }
488     else {
489 	/* If match put this char into el->el_key.buf.  Recurse */
490 	if (ptr->ch == *str) {
491 	    /* match found */
492 	    ncnt = key__decode_char(el->el_key.buf, cnt,
493 				    (unsigned char) ptr->ch);
494 	    if (ptr->next != NULL)
495 		/* not yet at leaf */
496 		return node_lookup(el, str + 1, ptr->next, ncnt + 1);
497 	    else {
498 		/* next node is null so key should be complete */
499 		if (str[1] == 0) {
500 		    el->el_key.buf[ncnt + 1] = '"';
501 		    el->el_key.buf[ncnt + 2] = '\0';
502 		    key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
503 		    return 0;
504 		}
505 		else
506 		    return -1;/* mismatch -- str still has chars */
507 	    }
508 	}
509 	else {
510 	    /* no match found try sibling */
511 	    if (ptr->sibling)
512 		return node_lookup(el, str, ptr->sibling, cnt);
513 	    else
514 		return -1;
515 	}
516     }
517 }
518 
519 
520 /* node_enum():
521  *	Traverse the node printing the characters it is bound in buffer
522  */
523 private int
524 node_enum(el, ptr, cnt)
525     EditLine *el;
526     key_node_t *ptr;
527     int     cnt;
528 {
529     int     ncnt;
530 
531     if (cnt >= KEY_BUFSIZ - 5) {	/* buffer too small */
532 	el->el_key.buf[++cnt] = '"';
533 	el->el_key.buf[++cnt] = '\0';
534 	(void) fprintf(el->el_errfile,
535 		    "Some extended keys too long for internal print buffer");
536 	(void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
537 	return 0;
538     }
539 
540     if (ptr == NULL) {
541 #ifdef DEBUG_EDIT
542 	(void) fprintf(el->el_errfile, "node_enum: BUG!! Null ptr passed\n!");
543 #endif
544 	return -1;
545     }
546 
547     /* put this char at end of str */
548     ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch);
549     if (ptr->next == NULL) {
550 	/* print this key and function */
551 	el->el_key.buf[ncnt + 1] = '"';
552 	el->el_key.buf[ncnt + 2] = '\0';
553 	key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
554     }
555     else
556 	(void) node_enum(el, ptr->next, ncnt + 1);
557 
558     /* go to sibling if there is one */
559     if (ptr->sibling)
560 	(void) node_enum(el, ptr->sibling, cnt);
561     return 0;
562 }
563 
564 
565 /* key_kprint():
566  *	Print the specified key and its associated
567  *	function specified by val
568  */
569 protected void
570 key_kprint(el, key, val, ntype)
571     EditLine      *el;
572     char          *key;
573     key_value_t   *val;
574     int            ntype;
575 {
576     el_bindings_t *fp;
577     char unparsbuf[EL_BUFSIZ];
578     static char *fmt = "%-15s->  %s\n";
579 
580     if (val != NULL)
581 	switch (ntype) {
582 	case XK_STR:
583 	case XK_EXE:
584 	    (void) fprintf(el->el_errfile, fmt, key,
585 			   key__decode_str(val->str, unparsbuf,
586 					      ntype == XK_STR ? "\"\"" : "[]"));
587 	    break;
588 	case XK_CMD:
589 	    for (fp = el->el_map.help; fp->name; fp++)
590 		if (val->cmd == fp->func) {
591 		    (void) fprintf(el->el_errfile, fmt, key, fp->name);
592 		    break;
593 		}
594 #ifdef DEBUG_KEY
595 	    if (fp->name == NULL)
596 		(void) fprintf(el->el_errfile, "BUG! Command not found.\n");
597 #endif
598 
599 	    break;
600 	default:
601 	    abort();
602 	    break;
603 	}
604     else
605 	(void) fprintf(el->el_errfile, fmt, key, "no input");
606 }
607 
608 
609 /* key__decode_char():
610  *	Put a printable form of char in buf.
611  */
612 private int
613 key__decode_char(buf, cnt, ch)
614     char *buf;
615     int   cnt, ch;
616 {
617     if (ch == 0) {
618 	buf[cnt++] = '^';
619 	buf[cnt] = '@';
620 	return cnt;
621     }
622 
623     if (iscntrl(ch)) {
624 	buf[cnt++] = '^';
625 	if (ch == '\177')
626 	    buf[cnt] = '?';
627 	else
628 	    buf[cnt] = ch | 0100;
629     }
630     else if (ch == '^') {
631 	buf[cnt++] = '\\';
632 	buf[cnt] = '^';
633     }
634     else if (ch == '\\') {
635 	buf[cnt++] = '\\';
636 	buf[cnt] = '\\';
637     }
638     else if (ch == ' ' || (isprint(ch) && !isspace(ch))) {
639 	buf[cnt] = ch;
640     }
641     else {
642 	buf[cnt++] = '\\';
643 	buf[cnt++] = ((ch >> 6) & 7) + '0';
644 	buf[cnt++] = ((ch >> 3) & 7) + '0';
645 	buf[cnt] = (ch & 7) + '0';
646     }
647     return cnt;
648 }
649 
650 /* key__decode_str():
651  *	Make a printable version of the ey
652  */
653 protected char *
654 key__decode_str(str, buf, sep)
655     char   *str;
656     char   *buf;
657     char   *sep;
658 {
659     char *b, *p;
660 
661     b = buf;
662     if (sep[0] != '\0')
663 	*b++ = sep[0];
664     if (*str == 0) {
665 	*b++ = '^';
666 	*b++ = '@';
667 	if (sep[0] != '\0' && sep[1] != '\0')
668 	    *b++ = sep[1];
669 	*b++ = 0;
670 	return buf;
671     }
672 
673     for (p = str; *p != 0; p++) {
674 	if (iscntrl((unsigned char) *p)) {
675 	    *b++ = '^';
676 	    if (*p == '\177')
677 		*b++ = '?';
678 	    else
679 		*b++ = *p | 0100;
680 	}
681 	else if (*p == '^' || *p == '\\') {
682 	    *b++ = '\\';
683 	    *b++ = *p;
684 	}
685 	else if (*p == ' ' || (isprint((unsigned char) *p) &&
686 			       !isspace((unsigned char) *p))) {
687 	    *b++ = *p;
688 	}
689 	else {
690 	    *b++ = '\\';
691 	    *b++ = ((*p >> 6) & 7) + '0';
692 	    *b++ = ((*p >> 3) & 7) + '0';
693 	    *b++ = (*p & 7) + '0';
694 	}
695     }
696     if (sep[0] != '\0' && sep[1] != '\0')
697 	*b++ = sep[1];
698     *b++ = 0;
699     return buf;			/* should check for overflow */
700 }
701