Changeset View
Changeset View
Standalone View
Standalone View
lib/libedit/keymacro.c
/* $NetBSD: keymacro.c,v 1.14 2016/02/24 14:25:38 christos Exp $ */ | /* $NetBSD: keymacro.c,v 1.24 2019/07/23 10:18:52 christos Exp $ */ | ||||
/*- | /*- | ||||
* Copyright (c) 1992, 1993 | * Copyright (c) 1992, 1993 | ||||
* The Regents of the University of California. All rights reserved. | * The Regents of the University of California. All rights reserved. | ||||
* | * | ||||
* This code is derived from software contributed to Berkeley by | * This code is derived from software contributed to Berkeley by | ||||
* Christos Zoulas of Cornell University. | * Christos Zoulas of Cornell University. | ||||
* | * | ||||
Show All 22 Lines | |||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include "config.h" | #include "config.h" | ||||
#if !defined(lint) && !defined(SCCSID) | #if !defined(lint) && !defined(SCCSID) | ||||
#if 0 | #if 0 | ||||
static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; | static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; | ||||
#else | #else | ||||
__RCSID("$NetBSD: keymacro.c,v 1.14 2016/02/24 14:25:38 christos Exp $"); | __RCSID("$NetBSD: keymacro.c,v 1.24 2019/07/23 10:18:52 christos Exp $"); | ||||
#endif | #endif | ||||
#endif /* not lint && not SCCSID */ | #endif /* not lint && not SCCSID */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | /* | ||||
* keymacro.c: This module contains the procedures for maintaining | * keymacro.c: This module contains the procedures for maintaining | ||||
* the extended-key map. | * the extended-key map. | ||||
* | * | ||||
* An extended-key (key) is a sequence of keystrokes introduced | * An extended-key (key) is a sequence of keystrokes introduced | ||||
* with a sequence introducer and consisting of an arbitrary | * with a sequence introducer and consisting of an arbitrary | ||||
* number of characters. This module maintains a map (the | * number of characters. This module maintains a map (the | ||||
* el->el_keymacro.map) | * el->el_keymacro.map) | ||||
* to convert these extended-key sequences into input strs | * to convert these extended-key sequences into input strs | ||||
* (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE). | * (XK_STR) or editor functions (XK_CMD). | ||||
* | * | ||||
* Warning: | * Warning: | ||||
* If key is a substr of some other keys, then the longer | * If key is a substr of some other keys, then the longer | ||||
* keys are lost!! That is, if the keys "abcd" and "abcef" | * keys are lost!! That is, if the keys "abcd" and "abcef" | ||||
* are in el->el_keymacro.map, adding the key "abc" will cause | * are in el->el_keymacro.map, adding the key "abc" will cause | ||||
* the first two definitions to be lost. | * the first two definitions to be lost. | ||||
* | * | ||||
* Restrictions: | * Restrictions: | ||||
* ------------- | * ------------- | ||||
* 1) It is not possible to have one key that is a | * 1) It is not possible to have one key that is a | ||||
* substr of another. | * substr of another. | ||||
*/ | */ | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include "el.h" | #include "el.h" | ||||
#include "fcns.h" | |||||
/* | /* | ||||
* The Nodes of the el->el_keymacro.map. The el->el_keymacro.map is a | * The Nodes of the el->el_keymacro.map. The el->el_keymacro.map is a | ||||
* linked list of these node elements | * linked list of these node elements | ||||
*/ | */ | ||||
struct keymacro_node_t { | struct keymacro_node_t { | ||||
Char ch; /* single character of key */ | wchar_t ch; /* single character of key */ | ||||
int type; /* node type */ | int type; /* node type */ | ||||
keymacro_value_t val; /* command code or pointer to str, */ | keymacro_value_t val; /* command code or pointer to str, */ | ||||
/* if this is a leaf */ | /* if this is a leaf */ | ||||
struct keymacro_node_t *next; /* ptr to next char of this key */ | struct keymacro_node_t *next; /* ptr to next char of this key */ | ||||
struct keymacro_node_t *sibling;/* ptr to another key with same prefix*/ | struct keymacro_node_t *sibling;/* ptr to another key with same prefix*/ | ||||
}; | }; | ||||
private int node_trav(EditLine *, keymacro_node_t *, Char *, | static int node_trav(EditLine *, keymacro_node_t *, wchar_t *, | ||||
keymacro_value_t *); | keymacro_value_t *); | ||||
private int node__try(EditLine *, keymacro_node_t *, const Char *, | static int node__try(EditLine *, keymacro_node_t *, | ||||
keymacro_value_t *, int); | const wchar_t *, keymacro_value_t *, int); | ||||
private keymacro_node_t *node__get(wint_t); | static keymacro_node_t *node__get(wint_t); | ||||
private void node__free(keymacro_node_t *); | static void node__free(keymacro_node_t *); | ||||
private void node__put(EditLine *, keymacro_node_t *); | static void node__put(EditLine *, keymacro_node_t *); | ||||
private int node__delete(EditLine *, keymacro_node_t **, | static int node__delete(EditLine *, keymacro_node_t **, | ||||
const Char *); | const wchar_t *); | ||||
private int node_lookup(EditLine *, const Char *, | static int node_lookup(EditLine *, const wchar_t *, | ||||
keymacro_node_t *, size_t); | keymacro_node_t *, size_t); | ||||
private int node_enum(EditLine *, keymacro_node_t *, size_t); | static int node_enum(EditLine *, keymacro_node_t *, size_t); | ||||
#define KEY_BUFSIZ EL_BUFSIZ | #define KEY_BUFSIZ EL_BUFSIZ | ||||
/* keymacro_init(): | /* keymacro_init(): | ||||
* Initialize the key maps | * Initialize the key maps | ||||
*/ | */ | ||||
protected int | libedit_private int | ||||
keymacro_init(EditLine *el) | keymacro_init(EditLine *el) | ||||
{ | { | ||||
el->el_keymacro.buf = el_malloc(KEY_BUFSIZ * | el->el_keymacro.buf = el_calloc(KEY_BUFSIZ, | ||||
sizeof(*el->el_keymacro.buf)); | sizeof(*el->el_keymacro.buf)); | ||||
if (el->el_keymacro.buf == NULL) | if (el->el_keymacro.buf == NULL) | ||||
return -1; | return -1; | ||||
el->el_keymacro.map = NULL; | el->el_keymacro.map = NULL; | ||||
keymacro_reset(el); | keymacro_reset(el); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* keymacro_end(): | /* keymacro_end(): | ||||
* Free the key maps | * Free the key maps | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
keymacro_end(EditLine *el) | keymacro_end(EditLine *el) | ||||
{ | { | ||||
el_free(el->el_keymacro.buf); | el_free(el->el_keymacro.buf); | ||||
el->el_keymacro.buf = NULL; | el->el_keymacro.buf = NULL; | ||||
node__free(el->el_keymacro.map); | node__free(el->el_keymacro.map); | ||||
} | } | ||||
/* keymacro_map_cmd(): | /* keymacro_map_cmd(): | ||||
* Associate cmd with a key value | * Associate cmd with a key value | ||||
*/ | */ | ||||
protected keymacro_value_t * | libedit_private keymacro_value_t * | ||||
keymacro_map_cmd(EditLine *el, int cmd) | keymacro_map_cmd(EditLine *el, int cmd) | ||||
{ | { | ||||
el->el_keymacro.val.cmd = (el_action_t) cmd; | el->el_keymacro.val.cmd = (el_action_t) cmd; | ||||
return &el->el_keymacro.val; | return &el->el_keymacro.val; | ||||
} | } | ||||
/* keymacro_map_str(): | /* keymacro_map_str(): | ||||
* Associate str with a key value | * Associate str with a key value | ||||
*/ | */ | ||||
protected keymacro_value_t * | libedit_private keymacro_value_t * | ||||
keymacro_map_str(EditLine *el, Char *str) | keymacro_map_str(EditLine *el, wchar_t *str) | ||||
{ | { | ||||
el->el_keymacro.val.str = str; | el->el_keymacro.val.str = str; | ||||
return &el->el_keymacro.val; | return &el->el_keymacro.val; | ||||
} | } | ||||
/* keymacro_reset(): | /* keymacro_reset(): | ||||
* Takes all nodes on el->el_keymacro.map and puts them on free list. | * Takes all nodes on el->el_keymacro.map and puts them on free list. | ||||
* Then initializes el->el_keymacro.map with arrow keys | * Then initializes el->el_keymacro.map with arrow keys | ||||
* [Always bind the ansi arrow keys?] | * [Always bind the ansi arrow keys?] | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
keymacro_reset(EditLine *el) | keymacro_reset(EditLine *el) | ||||
{ | { | ||||
node__put(el, el->el_keymacro.map); | node__put(el, el->el_keymacro.map); | ||||
el->el_keymacro.map = NULL; | el->el_keymacro.map = NULL; | ||||
return; | return; | ||||
} | } | ||||
/* keymacro_get(): | /* keymacro_get(): | ||||
* Calls the recursive function with entry point el->el_keymacro.map | * Calls the recursive function with entry point el->el_keymacro.map | ||||
* Looks up *ch in map and then reads characters until a | * Looks up *ch in map and then reads characters until a | ||||
* complete match is found or a mismatch occurs. Returns the | * complete match is found or a mismatch occurs. Returns the | ||||
* type of the match found (XK_STR, XK_CMD, or XK_EXE). | * type of the match found (XK_STR or XK_CMD). | ||||
* Returns NULL in val.str and XK_STR for no match. | * Returns NULL in val.str and XK_STR for no match. | ||||
* Returns XK_NOD for end of file or read error. | |||||
* The last character read is returned in *ch. | * The last character read is returned in *ch. | ||||
*/ | */ | ||||
protected int | libedit_private int | ||||
keymacro_get(EditLine *el, Char *ch, keymacro_value_t *val) | keymacro_get(EditLine *el, wchar_t *ch, keymacro_value_t *val) | ||||
{ | { | ||||
return node_trav(el, el->el_keymacro.map, ch, val); | return node_trav(el, el->el_keymacro.map, ch, val); | ||||
} | } | ||||
/* keymacro_add(): | /* keymacro_add(): | ||||
* Adds key to the el->el_keymacro.map and associates the value in | * Adds key to the el->el_keymacro.map and associates the value in | ||||
* val with it. If key is already is in el->el_keymacro.map, the new | * val with it. If key is already is in el->el_keymacro.map, the new | ||||
* code is applied to the existing key. Ntype specifies if code is a | * code is applied to the existing key. Ntype specifies if code is a | ||||
* command, an out str or a unix command. | * command, an out str or a unix command. | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
keymacro_add(EditLine *el, const Char *key, keymacro_value_t *val, int ntype) | keymacro_add(EditLine *el, const wchar_t *key, keymacro_value_t *val, | ||||
int ntype) | |||||
{ | { | ||||
if (key[0] == '\0') { | if (key[0] == '\0') { | ||||
(void) fprintf(el->el_errfile, | (void) fprintf(el->el_errfile, | ||||
"keymacro_add: Null extended-key not allowed.\n"); | "keymacro_add: Null extended-key not allowed.\n"); | ||||
return; | return; | ||||
} | } | ||||
if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) { | if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) { | ||||
Show All 10 Lines | keymacro_add(EditLine *el, const wchar_t *key, keymacro_value_t *val, | ||||
(void) node__try(el, el->el_keymacro.map, key, val, ntype); | (void) node__try(el, el->el_keymacro.map, key, val, ntype); | ||||
return; | return; | ||||
} | } | ||||
/* keymacro_clear(): | /* keymacro_clear(): | ||||
* | * | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
keymacro_clear(EditLine *el, el_action_t *map, const Char *in) | keymacro_clear(EditLine *el, el_action_t *map, const wchar_t *in) | ||||
{ | { | ||||
#ifdef WIDECHAR | |||||
if (*in > N_KEYS) /* can't be in the map */ | if (*in > N_KEYS) /* can't be in the map */ | ||||
return; | return; | ||||
#endif | |||||
if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && | if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && | ||||
((map == el->el_map.key && | ((map == el->el_map.key && | ||||
el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) || | el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) || | ||||
(map == el->el_map.alt && | (map == el->el_map.alt && | ||||
el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN))) | el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN))) | ||||
(void) keymacro_delete(el, in); | (void) keymacro_delete(el, in); | ||||
} | } | ||||
/* keymacro_delete(): | /* keymacro_delete(): | ||||
* Delete the key and all longer keys staring with key, if | * Delete the key and all longer keys staring with key, if | ||||
* they exists. | * they exists. | ||||
*/ | */ | ||||
protected int | libedit_private int | ||||
keymacro_delete(EditLine *el, const Char *key) | keymacro_delete(EditLine *el, const wchar_t *key) | ||||
{ | { | ||||
if (key[0] == '\0') { | if (key[0] == '\0') { | ||||
(void) fprintf(el->el_errfile, | (void) fprintf(el->el_errfile, | ||||
"keymacro_delete: Null extended-key not allowed.\n"); | "keymacro_delete: Null extended-key not allowed.\n"); | ||||
return -1; | return -1; | ||||
} | } | ||||
if (el->el_keymacro.map == NULL) | if (el->el_keymacro.map == NULL) | ||||
return 0; | return 0; | ||||
(void) node__delete(el, &el->el_keymacro.map, key); | (void) node__delete(el, &el->el_keymacro.map, key); | ||||
return 0; | return 0; | ||||
} | } | ||||
/* keymacro_print(): | /* keymacro_print(): | ||||
* Print the binding associated with key key. | * Print the binding associated with key key. | ||||
* Print entire el->el_keymacro.map if null | * Print entire el->el_keymacro.map if null | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
keymacro_print(EditLine *el, const Char *key) | keymacro_print(EditLine *el, const wchar_t *key) | ||||
{ | { | ||||
/* do nothing if el->el_keymacro.map is empty and null key specified */ | /* do nothing if el->el_keymacro.map is empty and null key specified */ | ||||
if (el->el_keymacro.map == NULL && *key == 0) | if (el->el_keymacro.map == NULL && *key == 0) | ||||
return; | return; | ||||
el->el_keymacro.buf[0] = '"'; | el->el_keymacro.buf[0] = '"'; | ||||
if (node_lookup(el, key, el->el_keymacro.map, (size_t)1) <= -1) | if (node_lookup(el, key, el->el_keymacro.map, (size_t)1) <= -1) | ||||
/* key is not bound */ | /* key is not bound */ | ||||
(void) fprintf(el->el_errfile, "Unbound extended key \"" FSTR | (void) fprintf(el->el_errfile, "Unbound extended key \"%ls" | ||||
"\"\n", key); | "\"\n", key); | ||||
return; | return; | ||||
} | } | ||||
/* node_trav(): | /* node_trav(): | ||||
* recursively traverses node in tree until match or mismatch is | * recursively traverses node in tree until match or mismatch is | ||||
* found. May read in more characters. | * found. May read in more characters. | ||||
*/ | */ | ||||
private int | static int | ||||
node_trav(EditLine *el, keymacro_node_t *ptr, Char *ch, keymacro_value_t *val) | node_trav(EditLine *el, keymacro_node_t *ptr, wchar_t *ch, | ||||
keymacro_value_t *val) | |||||
{ | { | ||||
wchar_t wc; | |||||
if (ptr->ch == *ch) { | if (ptr->ch == *ch) { | ||||
/* match found */ | /* match found */ | ||||
if (ptr->next) { | if (ptr->next) { | ||||
/* key not complete so get next char */ | /* key not complete so get next char */ | ||||
if (el_wgetc(el, &wc) != 1) {/* if EOF or error */ | if (el_wgetc(el, ch) != 1) | ||||
val->cmd = ED_END_OF_FILE; | return XK_NOD; | ||||
return XK_CMD; | |||||
/* PWP: Pretend we just read an end-of-file */ | |||||
} | |||||
*ch = (Char)wc; | |||||
return node_trav(el, ptr->next, ch, val); | return node_trav(el, ptr->next, ch, val); | ||||
} else { | } else { | ||||
*val = ptr->val; | *val = ptr->val; | ||||
if (ptr->type != XK_CMD) | if (ptr->type != XK_CMD) | ||||
*ch = '\0'; | *ch = '\0'; | ||||
return ptr->type; | return ptr->type; | ||||
} | } | ||||
} else { | } else { | ||||
/* no match found here */ | /* no match found here */ | ||||
if (ptr->sibling) { | if (ptr->sibling) { | ||||
/* try next sibling */ | /* try next sibling */ | ||||
return node_trav(el, ptr->sibling, ch, val); | return node_trav(el, ptr->sibling, ch, val); | ||||
} else { | } else { | ||||
/* no next sibling -- mismatch */ | /* no next sibling -- mismatch */ | ||||
val->str = NULL; | val->str = NULL; | ||||
return XK_STR; | return XK_STR; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* node__try(): | /* node__try(): | ||||
* Find a node that matches *str or allocate a new one | * Find a node that matches *str or allocate a new one | ||||
*/ | */ | ||||
private int | static int | ||||
node__try(EditLine *el, keymacro_node_t *ptr, const Char *str, | node__try(EditLine *el, keymacro_node_t *ptr, const wchar_t *str, | ||||
keymacro_value_t *val, int ntype) | keymacro_value_t *val, int ntype) | ||||
{ | { | ||||
if (ptr->ch != *str) { | if (ptr->ch != *str) { | ||||
keymacro_node_t *xm; | keymacro_node_t *xm; | ||||
for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) | for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) | ||||
if (xm->sibling->ch == *str) | if (xm->sibling->ch == *str) | ||||
Show All 9 Lines | if (ptr->next != NULL) { | ||||
/* lose longer keys with this prefix */ | /* lose longer keys with this prefix */ | ||||
ptr->next = NULL; | ptr->next = NULL; | ||||
} | } | ||||
switch (ptr->type) { | switch (ptr->type) { | ||||
case XK_CMD: | case XK_CMD: | ||||
case XK_NOD: | case XK_NOD: | ||||
break; | break; | ||||
case XK_STR: | case XK_STR: | ||||
case XK_EXE: | |||||
if (ptr->val.str) | if (ptr->val.str) | ||||
el_free(ptr->val.str); | el_free(ptr->val.str); | ||||
break; | break; | ||||
default: | default: | ||||
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", | EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", | ||||
ptr->type)); | ptr->type)); | ||||
break; | break; | ||||
} | } | ||||
switch (ptr->type = ntype) { | switch (ptr->type = ntype) { | ||||
case XK_CMD: | case XK_CMD: | ||||
ptr->val = *val; | ptr->val = *val; | ||||
break; | break; | ||||
case XK_STR: | case XK_STR: | ||||
case XK_EXE: | if ((ptr->val.str = wcsdup(val->str)) == NULL) | ||||
if ((ptr->val.str = Strdup(val->str)) == NULL) | |||||
return -1; | return -1; | ||||
break; | break; | ||||
default: | default: | ||||
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); | EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); | ||||
break; | break; | ||||
} | } | ||||
} else { | } else { | ||||
/* still more chars to go */ | /* still more chars to go */ | ||||
if (ptr->next == NULL) | if (ptr->next == NULL) | ||||
ptr->next = node__get(*str); /* setup new node */ | ptr->next = node__get(*str); /* setup new node */ | ||||
(void) node__try(el, ptr->next, str, val, ntype); | (void) node__try(el, ptr->next, str, val, ntype); | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
/* node__delete(): | /* node__delete(): | ||||
* Delete node that matches str | * Delete node that matches str | ||||
*/ | */ | ||||
private int | static int | ||||
node__delete(EditLine *el, keymacro_node_t **inptr, const Char *str) | node__delete(EditLine *el, keymacro_node_t **inptr, const wchar_t *str) | ||||
{ | { | ||||
keymacro_node_t *ptr; | keymacro_node_t *ptr; | ||||
keymacro_node_t *prev_ptr = NULL; | keymacro_node_t *prev_ptr = NULL; | ||||
ptr = *inptr; | ptr = *inptr; | ||||
if (ptr->ch != *str) { | if (ptr->ch != *str) { | ||||
keymacro_node_t *xm; | keymacro_node_t *xm; | ||||
Show All 30 Lines | if (*++str == '\0') { | ||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
/* node__put(): | /* node__put(): | ||||
* Puts a tree of nodes onto free list using free(3). | * Puts a tree of nodes onto free list using free(3). | ||||
*/ | */ | ||||
private void | static void | ||||
node__put(EditLine *el, keymacro_node_t *ptr) | node__put(EditLine *el, keymacro_node_t *ptr) | ||||
{ | { | ||||
if (ptr == NULL) | if (ptr == NULL) | ||||
return; | return; | ||||
if (ptr->next != NULL) { | if (ptr->next != NULL) { | ||||
node__put(el, ptr->next); | node__put(el, ptr->next); | ||||
ptr->next = NULL; | ptr->next = NULL; | ||||
} | } | ||||
node__put(el, ptr->sibling); | node__put(el, ptr->sibling); | ||||
switch (ptr->type) { | switch (ptr->type) { | ||||
case XK_CMD: | case XK_CMD: | ||||
case XK_NOD: | case XK_NOD: | ||||
break; | break; | ||||
case XK_EXE: | |||||
case XK_STR: | case XK_STR: | ||||
if (ptr->val.str != NULL) | if (ptr->val.str != NULL) | ||||
el_free(ptr->val.str); | el_free(ptr->val.str); | ||||
break; | break; | ||||
default: | default: | ||||
EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type)); | EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type)); | ||||
break; | break; | ||||
} | } | ||||
el_free(ptr); | el_free(ptr); | ||||
} | } | ||||
/* node__get(): | /* node__get(): | ||||
* Returns pointer to a keymacro_node_t for ch. | * Returns pointer to a keymacro_node_t for ch. | ||||
*/ | */ | ||||
private keymacro_node_t * | static keymacro_node_t * | ||||
node__get(wint_t ch) | node__get(wint_t ch) | ||||
{ | { | ||||
keymacro_node_t *ptr; | keymacro_node_t *ptr; | ||||
ptr = el_malloc(sizeof(*ptr)); | ptr = el_malloc(sizeof(*ptr)); | ||||
if (ptr == NULL) | if (ptr == NULL) | ||||
return NULL; | return NULL; | ||||
ptr->ch = (Char)ch; | ptr->ch = ch; | ||||
ptr->type = XK_NOD; | ptr->type = XK_NOD; | ||||
ptr->val.str = NULL; | ptr->val.str = NULL; | ||||
ptr->next = NULL; | ptr->next = NULL; | ||||
ptr->sibling = NULL; | ptr->sibling = NULL; | ||||
return ptr; | return ptr; | ||||
} | } | ||||
private void | static void | ||||
node__free(keymacro_node_t *k) | node__free(keymacro_node_t *k) | ||||
{ | { | ||||
if (k == NULL) | if (k == NULL) | ||||
return; | return; | ||||
node__free(k->sibling); | node__free(k->sibling); | ||||
node__free(k->next); | node__free(k->next); | ||||
el_free(k); | el_free(k); | ||||
} | } | ||||
/* node_lookup(): | /* node_lookup(): | ||||
* look for the str starting at node ptr. | * look for the str starting at node ptr. | ||||
* Print if last node | * Print if last node | ||||
*/ | */ | ||||
private int | static int | ||||
node_lookup(EditLine *el, const Char *str, keymacro_node_t *ptr, size_t cnt) | node_lookup(EditLine *el, const wchar_t *str, keymacro_node_t *ptr, | ||||
size_t cnt) | |||||
{ | { | ||||
ssize_t used; | ssize_t used; | ||||
if (ptr == NULL) | if (ptr == NULL) | ||||
return -1; /* cannot have null ptr */ | return -1; /* cannot have null ptr */ | ||||
if (!str || *str == 0) { | if (!str || *str == 0) { | ||||
/* no more chars in str. node_enum from here. */ | /* no more chars in str. node_enum from here. */ | ||||
Show All 34 Lines | if (!str || *str == 0) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* node_enum(): | /* node_enum(): | ||||
* Traverse the node printing the characters it is bound in buffer | * Traverse the node printing the characters it is bound in buffer | ||||
*/ | */ | ||||
private int | static int | ||||
node_enum(EditLine *el, keymacro_node_t *ptr, size_t cnt) | node_enum(EditLine *el, keymacro_node_t *ptr, size_t cnt) | ||||
{ | { | ||||
ssize_t used; | ssize_t used; | ||||
if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */ | if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */ | ||||
el->el_keymacro.buf[++cnt] = '"'; | el->el_keymacro.buf[++cnt] = '"'; | ||||
el->el_keymacro.buf[++cnt] = '\0'; | el->el_keymacro.buf[++cnt] = '\0'; | ||||
(void) fprintf(el->el_errfile, | (void) fprintf(el->el_errfile, | ||||
"Some extended keys too long for internal print buffer"); | "Some extended keys too long for internal print buffer"); | ||||
(void) fprintf(el->el_errfile, " \"" FSTR "...\"\n", | (void) fprintf(el->el_errfile, " \"%ls...\"\n", | ||||
el->el_keymacro.buf); | el->el_keymacro.buf); | ||||
return 0; | return 0; | ||||
} | } | ||||
if (ptr == NULL) { | if (ptr == NULL) { | ||||
#ifdef DEBUG_EDIT | #ifdef DEBUG_EDIT | ||||
(void) fprintf(el->el_errfile, | (void) fprintf(el->el_errfile, | ||||
"node_enum: BUG!! Null ptr passed\n!"); | "node_enum: BUG!! Null ptr passed\n!"); | ||||
#endif | #endif | ||||
Show All 16 Lines | #endif | ||||
return 0; | return 0; | ||||
} | } | ||||
/* keymacro_kprint(): | /* keymacro_kprint(): | ||||
* Print the specified key and its associated | * Print the specified key and its associated | ||||
* function specified by val | * function specified by val | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
keymacro_kprint(EditLine *el, const Char *key, keymacro_value_t *val, int ntype) | keymacro_kprint(EditLine *el, const wchar_t *key, keymacro_value_t *val, | ||||
int ntype) | |||||
{ | { | ||||
el_bindings_t *fp; | el_bindings_t *fp; | ||||
char unparsbuf[EL_BUFSIZ]; | char unparsbuf[EL_BUFSIZ]; | ||||
static const char fmt[] = "%-15s-> %s\n"; | static const char fmt[] = "%-15s-> %s\n"; | ||||
if (val != NULL) | if (val != NULL) | ||||
switch (ntype) { | switch (ntype) { | ||||
case XK_STR: | case XK_STR: | ||||
case XK_EXE: | |||||
(void) keymacro__decode_str(val->str, unparsbuf, | (void) keymacro__decode_str(val->str, unparsbuf, | ||||
sizeof(unparsbuf), | sizeof(unparsbuf), | ||||
ntype == XK_STR ? "\"\"" : "[]"); | ntype == XK_STR ? "\"\"" : "[]"); | ||||
(void) fprintf(el->el_outfile, fmt, | (void) fprintf(el->el_outfile, fmt, | ||||
ct_encode_string(key, &el->el_scratch), unparsbuf); | ct_encode_string(key, &el->el_scratch), unparsbuf); | ||||
break; | break; | ||||
case XK_CMD: | case XK_CMD: | ||||
for (fp = el->el_map.help; fp->name; fp++) | for (fp = el->el_map.help; fp->name; fp++) | ||||
if (val->cmd == fp->func) { | if (val->cmd == fp->func) { | ||||
ct_wcstombs(unparsbuf, fp->name, sizeof(unparsbuf)); | wcstombs(unparsbuf, fp->name, sizeof(unparsbuf)); | ||||
unparsbuf[sizeof(unparsbuf) -1] = '\0'; | unparsbuf[sizeof(unparsbuf) -1] = '\0'; | ||||
(void) fprintf(el->el_outfile, fmt, | (void) fprintf(el->el_outfile, fmt, | ||||
ct_encode_string(key, &el->el_scratch), unparsbuf); | ct_encode_string(key, &el->el_scratch), unparsbuf); | ||||
break; | break; | ||||
} | } | ||||
#ifdef DEBUG_KEY | #ifdef DEBUG_KEY | ||||
if (fp->name == NULL) | if (fp->name == NULL) | ||||
(void) fprintf(el->el_outfile, | (void) fprintf(el->el_outfile, | ||||
Show All 14 Lines | |||||
#define ADDC(c) \ | #define ADDC(c) \ | ||||
if (b < eb) \ | if (b < eb) \ | ||||
*b++ = c; \ | *b++ = c; \ | ||||
else \ | else \ | ||||
b++ | b++ | ||||
/* keymacro__decode_str(): | /* keymacro__decode_str(): | ||||
* Make a printable version of the ey | * Make a printable version of the ey | ||||
*/ | */ | ||||
protected size_t | libedit_private size_t | ||||
keymacro__decode_str(const Char *str, char *buf, size_t len, const char *sep) | keymacro__decode_str(const wchar_t *str, char *buf, size_t len, | ||||
const char *sep) | |||||
{ | { | ||||
char *b = buf, *eb = b + len; | char *b = buf, *eb = b + len; | ||||
const Char *p; | const wchar_t *p; | ||||
b = buf; | b = buf; | ||||
if (sep[0] != '\0') { | if (sep[0] != '\0') { | ||||
ADDC(sep[0]); | ADDC(sep[0]); | ||||
} | } | ||||
if (*str == '\0') { | if (*str == '\0') { | ||||
ADDC('^'); | ADDC('^'); | ||||
ADDC('@'); | ADDC('@'); | ||||
goto add_endsep; | goto add_endsep; | ||||
} | } | ||||
for (p = str; *p != 0; p++) { | for (p = str; *p != 0; p++) { | ||||
Char dbuf[VISUAL_WIDTH_MAX]; | wchar_t dbuf[VISUAL_WIDTH_MAX]; | ||||
Char *p2 = dbuf; | wchar_t *p2 = dbuf; | ||||
ssize_t l = ct_visual_char(dbuf, VISUAL_WIDTH_MAX, *p); | ssize_t l = ct_visual_char(dbuf, VISUAL_WIDTH_MAX, *p); | ||||
while (l-- > 0) { | while (l-- > 0) { | ||||
ssize_t n = ct_encode_char(b, (size_t)(eb - b), *p2++); | ssize_t n = ct_encode_char(b, (size_t)(eb - b), *p2++); | ||||
if (n == -1) /* ran out of space */ | if (n == -1) /* ran out of space */ | ||||
goto add_endsep; | goto add_endsep; | ||||
else | else | ||||
b += n; | b += n; | ||||
} | } | ||||
Show All 10 Lines |