2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Christos Zoulas of Cornell University.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * @(#)key.c 8.1 (Berkeley) 6/4/93
33 * $NetBSD: key.c,v 1.19 2006/03/23 20:22:51 christos Exp $
34 * $DragonFly: src/lib/libedit/key.c,v 1.6 2007/05/05 00:27:39 pavalos Exp $
40 * key.c: This module contains the procedures for maintaining
41 * the extended-key map.
43 * An extended-key (key) is a sequence of keystrokes introduced
44 * with a sequence introducer and consisting of an arbitrary
45 * number of characters. This module maintains a map (the el->el_key.map)
46 * to convert these extended-key sequences into input strs
47 * (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE).
50 * If key is a substr of some other keys, then the longer
51 * keys are lost!! That is, if the keys "abcd" and "abcef"
52 * are in el->el_key.map, adding the key "abc" will cause the first two
53 * definitions to be lost.
57 * 1) It is not possible to have one key that is a
66 * The Nodes of the el->el_key.map. The el->el_key.map is a linked list
67 * of these node elements
70 char ch
; /* single character of key */
71 int type
; /* node type */
72 key_value_t val
; /* command code or pointer to str, */
73 /* if this is a leaf */
74 struct key_node_t
*next
; /* ptr to next char of this key */
75 struct key_node_t
*sibling
; /* ptr to another key with same prefix*/
78 private int node_trav(EditLine
*, key_node_t
*, char *,
80 private int node__try(EditLine
*, key_node_t
*, const char *,
82 private key_node_t
*node__get(int);
83 private void node__free(key_node_t
*);
84 private void node__put(EditLine
*, key_node_t
*);
85 private int node__delete(EditLine
*, key_node_t
**, const char *);
86 private int node_lookup(EditLine
*, const char *, key_node_t
*,
88 private int node_enum(EditLine
*, key_node_t
*, int);
90 #define KEY_BUFSIZ EL_BUFSIZ
94 * Initialize the key maps
97 key_init(EditLine
*el
)
100 el
->el_key
.buf
= (char *) el_malloc(KEY_BUFSIZ
);
101 if (el
->el_key
.buf
== NULL
)
103 el
->el_key
.map
= NULL
;
112 key_end(EditLine
*el
)
115 el_free((ptr_t
) el
->el_key
.buf
);
116 el
->el_key
.buf
= NULL
;
117 node__free(el
->el_key
.map
);
122 * Associate cmd with a key value
124 protected key_value_t
*
125 key_map_cmd(EditLine
*el
, int cmd
)
128 el
->el_key
.val
.cmd
= (el_action_t
) cmd
;
129 return (&el
->el_key
.val
);
134 * Associate str with a key value
136 protected key_value_t
*
137 key_map_str(EditLine
*el
, char *str
)
140 el
->el_key
.val
.str
= str
;
141 return (&el
->el_key
.val
);
146 * Takes all nodes on el->el_key.map and puts them on free list. Then
147 * initializes el->el_key.map with arrow keys
148 * [Always bind the ansi arrow keys?]
151 key_reset(EditLine
*el
)
154 node__put(el
, el
->el_key
.map
);
155 el
->el_key
.map
= NULL
;
161 * Calls the recursive function with entry point el->el_key.map
162 * Looks up *ch in map and then reads characters until a
163 * complete match is found or a mismatch occurs. Returns the
164 * type of the match found (XK_STR, XK_CMD, or XK_EXE).
165 * Returns NULL in val.str and XK_STR for no match.
166 * The last character read is returned in *ch.
169 key_get(EditLine
*el
, char *ch
, key_value_t
*val
)
172 return (node_trav(el
, el
->el_key
.map
, ch
, val
));
177 * Adds key to the el->el_key.map and associates the value in val with it.
178 * If key is already is in el->el_key.map, the new code is applied to the
179 * existing key. Ntype specifies if code is a command, an
180 * out str or a unix command.
183 key_add(EditLine
*el
, const char *key
, key_value_t
*val
, int ntype
)
186 if (key
[0] == '\0') {
187 (void) fprintf(el
->el_errfile
,
188 "key_add: Null extended-key not allowed.\n");
191 if (ntype
== XK_CMD
&& val
->cmd
== ED_SEQUENCE_LEAD_IN
) {
192 (void) fprintf(el
->el_errfile
,
193 "key_add: sequence-lead-in command not allowed\n");
196 if (el
->el_key
.map
== NULL
)
197 /* tree is initially empty. Set up new node to match key[0] */
198 el
->el_key
.map
= node__get(key
[0]);
199 /* it is properly initialized */
201 /* Now recurse through el->el_key.map */
202 (void) node__try(el
, el
->el_key
.map
, key
, val
, ntype
);
211 key_clear(EditLine
*el
, el_action_t
*map
, const char *in
)
214 if ((map
[(unsigned char)*in
] == ED_SEQUENCE_LEAD_IN
) &&
215 ((map
== el
->el_map
.key
&&
216 el
->el_map
.alt
[(unsigned char)*in
] != ED_SEQUENCE_LEAD_IN
) ||
217 (map
== el
->el_map
.alt
&&
218 el
->el_map
.key
[(unsigned char)*in
] != ED_SEQUENCE_LEAD_IN
)))
219 (void) key_delete(el
, in
);
224 * Delete the key and all longer keys staring with key, if
228 key_delete(EditLine
*el
, const char *key
)
231 if (key
[0] == '\0') {
232 (void) fprintf(el
->el_errfile
,
233 "key_delete: Null extended-key not allowed.\n");
236 if (el
->el_key
.map
== NULL
)
239 (void) node__delete(el
, &el
->el_key
.map
, key
);
245 * Print the binding associated with key key.
246 * Print entire el->el_key.map if null
249 key_print(EditLine
*el
, const char *key
)
252 /* do nothing if el->el_key.map is empty and null key specified */
253 if (el
->el_key
.map
== NULL
&& *key
== 0)
256 el
->el_key
.buf
[0] = '"';
257 if (node_lookup(el
, key
, el
->el_key
.map
, 1) <= -1)
258 /* key is not bound */
259 (void) fprintf(el
->el_errfile
, "Unbound extended key \"%s\"\n",
266 * recursively traverses node in tree until match or mismatch is
267 * found. May read in more characters.
270 node_trav(EditLine
*el
, key_node_t
*ptr
, char *ch
, key_value_t
*val
)
273 if (ptr
->ch
== *ch
) {
276 /* key not complete so get next char */
277 if (el_getc(el
, ch
) != 1) { /* if EOF or error */
278 val
->cmd
= ED_END_OF_FILE
;
280 /* PWP: Pretend we just read an end-of-file */
282 return (node_trav(el
, ptr
->next
, ch
, val
));
285 if (ptr
->type
!= XK_CMD
)
290 /* no match found here */
292 /* try next sibling */
293 return (node_trav(el
, ptr
->sibling
, ch
, val
));
295 /* no next sibling -- mismatch */
304 * Find a node that matches *str or allocate a new one
307 node__try(EditLine
*el
, key_node_t
*ptr
, const char *str
, key_value_t
*val
, int ntype
)
310 if (ptr
->ch
!= *str
) {
313 for (xm
= ptr
; xm
->sibling
!= NULL
; xm
= xm
->sibling
)
314 if (xm
->sibling
->ch
== *str
)
316 if (xm
->sibling
== NULL
)
317 xm
->sibling
= node__get(*str
); /* setup new node */
320 if (*++str
== '\0') {
322 if (ptr
->next
!= NULL
) {
323 node__put(el
, ptr
->next
);
324 /* lose longer keys with this prefix */
334 el_free((ptr_t
) ptr
->val
.str
);
337 EL_ABORT((el
->el_errfile
, "Bad XK_ type %d\n",
342 switch (ptr
->type
= ntype
) {
348 if ((ptr
->val
.str
= el_strdup(val
->str
)) == NULL
)
352 EL_ABORT((el
->el_errfile
, "Bad XK_ type %d\n", ntype
));
356 /* still more chars to go */
357 if (ptr
->next
== NULL
)
358 ptr
->next
= node__get(*str
); /* setup new node */
359 (void) node__try(el
, ptr
->next
, str
, val
, ntype
);
366 * Delete node that matches str
369 node__delete(EditLine
*el
, key_node_t
**inptr
, const char *str
)
372 key_node_t
*prev_ptr
= NULL
;
376 if (ptr
->ch
!= *str
) {
379 for (xm
= ptr
; xm
->sibling
!= NULL
; xm
= xm
->sibling
)
380 if (xm
->sibling
->ch
== *str
)
382 if (xm
->sibling
== NULL
)
387 if (*++str
== '\0') {
389 if (prev_ptr
== NULL
)
390 *inptr
= ptr
->sibling
;
392 prev_ptr
->sibling
= ptr
->sibling
;
396 } else if (ptr
->next
!= NULL
&&
397 node__delete(el
, &ptr
->next
, str
) == 1) {
398 if (ptr
->next
!= NULL
)
400 if (prev_ptr
== NULL
)
401 *inptr
= ptr
->sibling
;
403 prev_ptr
->sibling
= ptr
->sibling
;
414 * Puts a tree of nodes onto free list using free(3).
417 node__put(EditLine
*el
, key_node_t
*ptr
)
422 if (ptr
->next
!= NULL
) {
423 node__put(el
, ptr
->next
);
426 node__put(el
, ptr
->sibling
);
434 if (ptr
->val
.str
!= NULL
)
435 el_free((ptr_t
) ptr
->val
.str
);
438 EL_ABORT((el
->el_errfile
, "Bad XK_ type %d\n", ptr
->type
));
441 el_free((ptr_t
) ptr
);
446 * Returns pointer to a key_node_t for ch.
453 ptr
= (key_node_t
*) el_malloc((size_t) sizeof(key_node_t
));
465 node__free(key_node_t
*k
)
469 node__free(k
->sibling
);
475 * look for the str starting at node ptr.
479 node_lookup(EditLine
*el
, const char *str
, key_node_t
*ptr
, int cnt
)
484 return (-1); /* cannot have null ptr */
487 /* no more chars in str. node_enum from here. */
488 (void) node_enum(el
, ptr
, cnt
);
491 /* If match put this char into el->el_key.buf. Recurse */
492 if (ptr
->ch
== *str
) {
494 ncnt
= key__decode_char(el
->el_key
.buf
, KEY_BUFSIZ
, cnt
,
495 (unsigned char) ptr
->ch
);
496 if (ptr
->next
!= NULL
)
497 /* not yet at leaf */
498 return (node_lookup(el
, str
+ 1, ptr
->next
,
501 /* next node is null so key should be complete */
503 el
->el_key
.buf
[ncnt
+ 1] = '"';
504 el
->el_key
.buf
[ncnt
+ 2] = '\0';
505 key_kprint(el
, el
->el_key
.buf
,
506 &ptr
->val
, ptr
->type
);
510 /* mismatch -- str still has chars */
513 /* no match found try sibling */
515 return (node_lookup(el
, str
, ptr
->sibling
,
525 * Traverse the node printing the characters it is bound in buffer
528 node_enum(EditLine
*el
, key_node_t
*ptr
, int cnt
)
532 if (cnt
>= KEY_BUFSIZ
- 5) { /* buffer too small */
533 el
->el_key
.buf
[++cnt
] = '"';
534 el
->el_key
.buf
[++cnt
] = '\0';
535 (void) fprintf(el
->el_errfile
,
536 "Some extended keys too long for internal print buffer");
537 (void) fprintf(el
->el_errfile
, " \"%s...\"\n", el
->el_key
.buf
);
542 (void) fprintf(el
->el_errfile
,
543 "node_enum: BUG!! Null ptr passed\n!");
547 /* put this char at end of str */
548 ncnt
= key__decode_char(el
->el_key
.buf
, KEY_BUFSIZ
, cnt
,
549 (unsigned char)ptr
->ch
);
550 if (ptr
->next
== NULL
) {
551 /* print this key and function */
552 el
->el_key
.buf
[ncnt
+ 1] = '"';
553 el
->el_key
.buf
[ncnt
+ 2] = '\0';
554 key_kprint(el
, el
->el_key
.buf
, &ptr
->val
, ptr
->type
);
556 (void) node_enum(el
, ptr
->next
, ncnt
+ 1);
558 /* go to sibling if there is one */
560 (void) node_enum(el
, ptr
->sibling
, cnt
);
566 * Print the specified key and its associated
567 * function specified by val
570 key_kprint(EditLine
*el
, const char *key
, key_value_t
*val
, int ntype
)
573 char unparsbuf
[EL_BUFSIZ
];
574 static const char fmt
[] = "%-15s-> %s\n";
580 (void) key__decode_str(val
->str
, unparsbuf
,
582 ntype
== XK_STR
? "\"\"" : "[]");
583 (void) fprintf(el
->el_outfile
, fmt
, key
, unparsbuf
);
586 for (fp
= el
->el_map
.help
; fp
->name
; fp
++)
587 if (val
->cmd
== fp
->func
) {
588 (void) fprintf(el
->el_outfile
, fmt
,
593 if (fp
->name
== NULL
)
594 (void) fprintf(el
->el_outfile
,
595 "BUG! Command not found.\n");
600 EL_ABORT((el
->el_errfile
, "Bad XK_ type %d\n", ntype
));
604 (void) fprintf(el
->el_outfile
, fmt
, key
, "no input");
613 /* key__decode_char():
614 * Put a printable form of char in buf.
617 key__decode_char(char *buf
, int cnt
, int off
, int ch
)
619 char *sb
= buf
+ off
;
620 char *eb
= buf
+ cnt
;
633 } else if (ch
== '^') {
636 } else if (ch
== '\\') {
639 } else if (ch
== ' ' || (isprint(ch
) && !isspace(ch
))) {
643 ADDC((((unsigned int) ch
>> 6) & 7) + '0');
644 ADDC((((unsigned int) ch
>> 3) & 7) + '0');
645 ADDC((ch
& 7) + '0');
651 /* key__decode_str():
652 * Make a printable version of the ey
655 key__decode_str(const char *str
, char *buf
, int len
, const char *sep
)
657 char *b
= buf
, *eb
= b
+ len
;
661 if (sep
[0] != '\0') {
667 if (sep
[0] != '\0' && sep
[1] != '\0') {
672 for (p
= str
; *p
!= 0; p
++) {
673 if (iscntrl((unsigned char) *p
)) {
680 } else if (*p
== '^' || *p
== '\\') {
683 } else if (*p
== ' ' || (isprint((unsigned char) *p
) &&
684 !isspace((unsigned char) *p
))) {
688 ADDC((((unsigned int) *p
>> 6) & 7) + '0');
689 ADDC((((unsigned int) *p
>> 3) & 7) + '0');
690 ADDC((*p
& 7) + '0');
693 if (sep
[0] != '\0' && sep
[1] != '\0') {