xref: /original-bsd/lib/libedit/key.c (revision 942cfc3b)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * 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	5.3 (Berkeley) 10/12/92";
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 	    break;
328 	case XK_STR:
329 	case XK_EXE:
330 	    if (ptr->val.str)
331 		el_free((ptr_t) ptr->val.str);
332 	    break;
333 	default:
334 	    abort();
335 	    break;
336 	}
337 
338 	switch (ptr->type = ntype) {
339 	case XK_CMD:
340 	    ptr->val = *val;
341 	    break;
342 	case XK_STR:
343 	case XK_EXE:
344 	    ptr->val.str = strdup(val->str);
345 	    break;
346 	default:
347 	    abort();
348 	    break;
349 	}
350     }
351     else {
352 	/* still more chars to go */
353 	if (ptr->next == NULL)
354 	    ptr->next = node__get(*str);	/* setup new node */
355 	(void) node__try(ptr->next, str, val, ntype);
356     }
357     return 0;
358 }
359 
360 
361 /* node__delete():
362  *	Delete node that matches str
363  */
364 private int
365 node__delete(inptr, str)
366     key_node_t **inptr;
367     char   *str;
368 {
369     key_node_t *ptr;
370     key_node_t *prev_ptr = NULL;
371 
372     ptr = *inptr;
373 
374     if (ptr->ch != *str) {
375 	key_node_t *xm;
376 
377 	for (xm = ptr; xm->sibling != NULL; xm = xm->sibling)
378 	    if (xm->sibling->ch == *str)
379 		break;
380 	if (xm->sibling == NULL)
381 	    return 0;
382 	prev_ptr = xm;
383 	ptr = xm->sibling;
384     }
385 
386     if (*++str == '\0') {
387 	/* we're there */
388 	if (prev_ptr == NULL)
389 	    *inptr = ptr->sibling;
390 	else
391 	    prev_ptr->sibling = ptr->sibling;
392 	ptr->sibling = NULL;
393 	node__put(ptr);
394 	return 1;
395     }
396     else if (ptr->next != NULL && node__delete(&ptr->next, str) == 1) {
397 	if (ptr->next != NULL)
398 	    return 0;
399 	if (prev_ptr == NULL)
400 	    *inptr = ptr->sibling;
401 	else
402 	    prev_ptr->sibling = ptr->sibling;
403 	ptr->sibling = NULL;
404 	node__put(ptr);
405 	return 1;
406     }
407     else {
408 	return 0;
409     }
410 }
411 
412 /* node__put():
413  *	Puts a tree of nodes onto free list using free(3).
414  */
415 private void
416 node__put(ptr)
417     key_node_t *ptr;
418 {
419     if (ptr == NULL)
420 	return;
421 
422     if (ptr->next != NULL) {
423 	node__put(ptr->next);
424 	ptr->next = NULL;
425     }
426 
427     node__put(ptr->sibling);
428 
429     switch (ptr->type) {
430     case XK_CMD:
431     case XK_NOD:
432 	break;
433     case XK_EXE:
434     case XK_STR:
435 	if (ptr->val.str != NULL)
436 	    el_free((ptr_t) ptr->val.str);
437 	break;
438     default:
439 	abort();
440 	break;
441     }
442     el_free((ptr_t) ptr);
443 }
444 
445 
446 /* node__get():
447  *	Returns pointer to an key_node_t for ch.
448  */
449 private key_node_t *
450 node__get(ch)
451     int    ch;
452 {
453     key_node_t *ptr;
454 
455     ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t));
456     ptr->ch = ch;
457     ptr->type = XK_NOD;
458     ptr->val.str = NULL;
459     ptr->next = NULL;
460     ptr->sibling = NULL;
461     return ptr;
462 }
463 
464 
465 
466 /* node_lookup():
467  *	look for the str starting at node ptr.
468  *	Print if last node
469  */
470 private int
471 node_lookup(el, str, ptr, cnt)
472     EditLine   *el;
473     char       *str;
474     key_node_t *ptr;
475     int         cnt;
476 {
477     int     ncnt;
478 
479     if (ptr == NULL)
480 	return -1;		/* cannot have null ptr */
481 
482     if (*str == 0) {
483 	/* no more chars in str.  node_enum from here. */
484 	(void) node_enum(el, ptr, cnt);
485 	return 0;
486     }
487     else {
488 	/* If match put this char into el->el_key.buf.  Recurse */
489 	if (ptr->ch == *str) {
490 	    /* match found */
491 	    ncnt = key__decode_char(el->el_key.buf, cnt,
492 				    (unsigned char) ptr->ch);
493 	    if (ptr->next != NULL)
494 		/* not yet at leaf */
495 		return node_lookup(el, str + 1, ptr->next, ncnt + 1);
496 	    else {
497 		/* next node is null so key should be complete */
498 		if (str[1] == 0) {
499 		    el->el_key.buf[ncnt + 1] = '"';
500 		    el->el_key.buf[ncnt + 2] = '\0';
501 		    key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
502 		    return 0;
503 		}
504 		else
505 		    return -1;/* mismatch -- str still has chars */
506 	    }
507 	}
508 	else {
509 	    /* no match found try sibling */
510 	    if (ptr->sibling)
511 		return node_lookup(el, str, ptr->sibling, cnt);
512 	    else
513 		return -1;
514 	}
515     }
516 }
517 
518 
519 /* node_enum():
520  *	Traverse the node printing the characters it is bound in buffer
521  */
522 private int
523 node_enum(el, ptr, cnt)
524     EditLine *el;
525     key_node_t *ptr;
526     int     cnt;
527 {
528     int     ncnt;
529 
530     if (cnt >= KEY_BUFSIZ - 5) {	/* buffer too small */
531 	el->el_key.buf[++cnt] = '"';
532 	el->el_key.buf[++cnt] = '\0';
533 	(void) fprintf(el->el_errfile,
534 		    "Some extended keys too long for internal print buffer");
535 	(void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf);
536 	return 0;
537     }
538 
539     if (ptr == NULL) {
540 #ifdef DEBUG_EDIT
541 	(void) fprintf(el->el_errfile, "node_enum: BUG!! Null ptr passed\n!");
542 #endif
543 	return -1;
544     }
545 
546     /* put this char at end of str */
547     ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch);
548     if (ptr->next == NULL) {
549 	/* print this key and function */
550 	el->el_key.buf[ncnt + 1] = '"';
551 	el->el_key.buf[ncnt + 2] = '\0';
552 	key_kprint(el, el->el_key.buf, &ptr->val, ptr->type);
553     }
554     else
555 	(void) node_enum(el, ptr->next, ncnt + 1);
556 
557     /* go to sibling if there is one */
558     if (ptr->sibling)
559 	(void) node_enum(el, ptr->sibling, cnt);
560     return 0;
561 }
562 
563 
564 /* key_kprint():
565  *	Print the specified key and its associated
566  *	function specified by val
567  */
568 protected void
569 key_kprint(el, key, val, ntype)
570     EditLine      *el;
571     char          *key;
572     key_value_t   *val;
573     int            ntype;
574 {
575     el_bindings_t *fp;
576     char unparsbuf[EL_BUFSIZ];
577     static char *fmt = "%-15s->  %s\n";
578 
579     if (val != NULL)
580 	switch (ntype) {
581 	case XK_STR:
582 	case XK_EXE:
583 	    (void) fprintf(el->el_errfile, fmt, key,
584 			   key__decode_str(val->str, unparsbuf,
585 					      ntype == XK_STR ? "\"\"" : "[]"));
586 	    break;
587 	case XK_CMD:
588 	    for (fp = el->el_map.help; fp->name; fp++)
589 		if (val->cmd == fp->func) {
590 		    (void) fprintf(el->el_errfile, fmt, key, fp->name);
591 		    break;
592 		}
593 #ifdef DEBUG_KEY
594 	    if (fp->name == NULL)
595 		(void) fprintf(el->el_errfile, "BUG! Command not found.\n");
596 #endif
597 
598 	    break;
599 	default:
600 	    abort();
601 	    break;
602 	}
603     else
604 	(void) fprintf(el->el_errfile, fmt, key, "no input");
605 }
606 
607 
608 /* key__decode_char():
609  *	Put a printable form of char in buf.
610  */
611 private int
612 key__decode_char(buf, cnt, ch)
613     char *buf;
614     int   cnt, ch;
615 {
616     if (ch == 0) {
617 	buf[cnt++] = '^';
618 	buf[cnt] = '@';
619 	return cnt;
620     }
621 
622     if (iscntrl(ch)) {
623 	buf[cnt++] = '^';
624 	if (ch == '\177')
625 	    buf[cnt] = '?';
626 	else
627 	    buf[cnt] = ch | 0100;
628     }
629     else if (ch == '^') {
630 	buf[cnt++] = '\\';
631 	buf[cnt] = '^';
632     }
633     else if (ch == '\\') {
634 	buf[cnt++] = '\\';
635 	buf[cnt] = '\\';
636     }
637     else if (ch == ' ' || (isprint(ch) && !isspace(ch))) {
638 	buf[cnt] = ch;
639     }
640     else {
641 	buf[cnt++] = '\\';
642 	buf[cnt++] = ((ch >> 6) & 7) + '0';
643 	buf[cnt++] = ((ch >> 3) & 7) + '0';
644 	buf[cnt] = (ch & 7) + '0';
645     }
646     return cnt;
647 }
648 
649 /* key__decode_str():
650  *	Make a printable version of the ey
651  */
652 protected char *
653 key__decode_str(str, buf, sep)
654     char   *str;
655     char   *buf;
656     char   *sep;
657 {
658     char *b, *p;
659 
660     b = buf;
661     if (sep[0] != '\0')
662 	*b++ = sep[0];
663     if (*str == 0) {
664 	*b++ = '^';
665 	*b++ = '@';
666 	if (sep[0] != '\0' && sep[1] != '\0')
667 	    *b++ = sep[1];
668 	*b++ = 0;
669 	return buf;
670     }
671 
672     for (p = str; *p != 0; p++) {
673 	if (iscntrl((unsigned char) *p)) {
674 	    *b++ = '^';
675 	    if (*p == '\177')
676 		*b++ = '?';
677 	    else
678 		*b++ = *p | 0100;
679 	}
680 	else if (*p == '^' || *p == '\\') {
681 	    *b++ = '\\';
682 	    *b++ = *p;
683 	}
684 	else if (*p == ' ' || (isprint((unsigned char) *p) &&
685 			       !isspace((unsigned char) *p))) {
686 	    *b++ = *p;
687 	}
688 	else {
689 	    *b++ = '\\';
690 	    *b++ = ((*p >> 6) & 7) + '0';
691 	    *b++ = ((*p >> 3) & 7) + '0';
692 	    *b++ = (*p & 7) + '0';
693 	}
694     }
695     if (sep[0] != '\0' && sep[1] != '\0')
696 	*b++ = sep[1];
697     *b++ = 0;
698     return buf;			/* should check for overflow */
699 }
700