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