keymacro.c revision 84260
11558Srgrimes/*- 292058Sobrien * Copyright (c) 1992, 1993 392058Sobrien * The Regents of the University of California. All rights reserved. 492058Sobrien * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Christos Zoulas of Cornell University. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 3. All advertising materials mentioning features or use of this software 171558Srgrimes * must display the following acknowledgement: 181558Srgrimes * This product includes software developed by the University of 191558Srgrimes * California, Berkeley and its contributors. 201558Srgrimes * 4. Neither the name of the University nor the names of its contributors 211558Srgrimes * may be used to endorse or promote products derived from this software 221558Srgrimes * without specific prior written permission. 2392058Sobrien * 241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341558Srgrimes * SUCH DAMAGE. 351558Srgrimes * 361558Srgrimes * $NetBSD: key.c,v 1.11 2001/01/23 15:55:30 jdolecek Exp $ 371558Srgrimes */ 381558Srgrimes 3992058Sobrien#include <sys/cdefs.h> 4092058Sobrien__FBSDID("$FreeBSD: head/lib/libedit/key.c 84260 2001-10-01 08:41:27Z obrien $"); 411558Srgrimes#if !defined(lint) && !defined(SCCSID) 421558Srgrimesstatic char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; 43115449Sobrien#endif /* not lint && not SCCSID */ 441558Srgrimes#include <sys/cdefs.h> 4536632Scharnier__FBSDID("$FreeBSD: head/lib/libedit/key.c 84260 2001-10-01 08:41:27Z obrien $"); 461558Srgrimes 471558Srgrimes/* 481558Srgrimes * key.c: This module contains the procedures for maintaining 491558Srgrimes * the extended-key map. 501558Srgrimes * 511558Srgrimes * An extended-key (key) is a sequence of keystrokes introduced 521558Srgrimes * with an sequence introducer and consisting of an arbitrary 53115449Sobrien * number of characters. This module maintains a map (the el->el_key.map) 5436632Scharnier * to convert these extended-key sequences into input strs 5599365Smarkm * (XK_STR), editor functions (XK_CMD), or unix commands (XK_EXE). 5699365Smarkm * 5799365Smarkm * Warning: 581558Srgrimes * If key is a substr of some other keys, then the longer 59114552Sphk * keys are lost!! That is, if the keys "abcd" and "abcef" 601558Srgrimes * are in el->el_key.map, adding the key "abc" will cause the first two 611558Srgrimes * definitions to be lost. 6213544Sjoerg * 63103669Sphk * Restrictions: 641558Srgrimes * ------------- 65101994Sbmilekic * 1) It is not possible to have one key that is a 66227231Sae * substr of another. 671558Srgrimes */ 68112307Sru#include "sys.h" 691558Srgrimes#include <string.h> 701558Srgrimes#include <stdlib.h> 711558Srgrimes 72114569Sphk#include "el.h" 7313544Sjoerg 7413544Sjoerg/* 7513544Sjoerg * The Nodes of the el->el_key.map. The el->el_key.map is a linked list 761558Srgrimes * of these node elements 7726542Scharnier */ 7859216Simpstruct key_node_t { 7999365Smarkm char ch; /* single character of key */ 801558Srgrimes int type; /* node type */ 811558Srgrimes key_value_t val; /* command code or pointer to str, */ 82114571Sphk /* if this is a leaf */ 83227270Sae struct key_node_t *next; /* ptr to next char of this key */ 84114571Sphk struct key_node_t *sibling; /* ptr to another key with same prefix*/ 85133347Sdes}; 86114571Sphk 87133347Sdesprivate int node_trav(EditLine *, key_node_t *, char *, 88114571Sphk key_value_t *); 89121222Sphkprivate int node__try(EditLine *, key_node_t *, const char *, 90114571Sphk key_value_t *, int); 91114571Sphkprivate key_node_t *node__get(int); 92114571Sphkprivate void node__put(EditLine *, key_node_t *); 93114571Sphkprivate int node__delete(EditLine *, key_node_t **, char *); 94114571Sphkprivate int node_lookup(EditLine *, char *, key_node_t *, int); 95114571Sphkprivate int node_enum(EditLine *, key_node_t *, int); 96114571Sphkprivate int key__decode_char(char *, int, int); 9713544Sjoerg 981558Srgrimes#define KEY_BUFSIZ EL_BUFSIZ 99174501Smarcel 1001558Srgrimes 101114571Sphk/* key_init(): 102183143Slulf * Initialize the key maps 103114571Sphk */ 1041558Srgrimesprotected int 105114571Sphkkey_init(EditLine *el) 106114571Sphk{ 107114574Sphk 108219449Suqs el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ); 109114571Sphk if (el->el_key.buf == NULL) 110114571Sphk return (-1); 1111558Srgrimes el->el_key.map = NULL; 11273034Sjwd key_reset(el); 11373034Sjwd return (0); 114114571Sphk} 115114571Sphk 116114571Sphk 11773034Sjwd/* key_end(): 118114571Sphk * Free the key maps 119114574Sphk */ 120114571Sphkprotected void 1211558Srgrimeskey_end(EditLine *el) 122196383Smarcel{ 123115995Sphk 124115995Sphk el_free((ptr_t) el->el_key.buf); 125115995Sphk el->el_key.buf = NULL; 126115995Sphk /* XXX: provide a function to clear the keys */ 127115995Sphk el->el_key.map = NULL; 128115995Sphk} 129115696Sphk 130115696Sphk 131114551Sphk/* key_map_cmd(): 132114550Sphk * Associate cmd with a key value 133228417Sed */ 134109872Sphkprotected key_value_t * 1351558Srgrimeskey_map_cmd(EditLine *el, int cmd) 1361558Srgrimes{ 137112307Sru 138114571Sphk el->el_key.val.cmd = (el_action_t) cmd; 139127650Sluigi return (&el->el_key.val); 1401558Srgrimes} 14113544Sjoerg 14292541Simp 1431558Srgrimes/* key_map_str(): 1441558Srgrimes * Associate str with a key value 145183143Slulf */ 146183143Slulfprotected key_value_t * 147183143Slulfkey_map_str(EditLine *el, char *str) 148183143Slulf{ 149183143Slulf 1501558Srgrimes el->el_key.val.str = str; 151163539Smaxim return (&el->el_key.val); 1521558Srgrimes} 153114574Sphk 154114574Sphk 155114574Sphk/* key_reset(): 1561558Srgrimes * Takes all nodes on el->el_key.map and puts them on free list. Then 1571558Srgrimes * initializes el->el_key.map with arrow keys 1581558Srgrimes * [Always bind the ansi arrow keys?] 1591558Srgrimes */ 1601558Srgrimesprotected void 1611558Srgrimeskey_reset(EditLine *el) 162127650Sluigi{ 163127650Sluigi 164127650Sluigi node__put(el, el->el_key.map); 165112307Sru el->el_key.map = NULL; 166115948Sphk return; 167115948Sphk} 168115948Sphk 169115948Sphk 170115696Sphk/* key_get(): 171115696Sphk * Calls the recursive function with entry point el->el_key.map 172114550Sphk * Looks up *ch in map and then reads characters until a 173114571Sphk * complete match is found or a mismatch occurs. Returns the 174114571Sphk * type of the match found (XK_STR, XK_CMD, or XK_EXE). 175114550Sphk * Returns NULL in val.str and XK_STR for no match. 176112307Sru * The last character read is returned in *ch. 17773034Sjwd */ 17873034Sjwdprotected int 17973034Sjwdkey_get(EditLine *el, char *ch, key_value_t *val) 1801558Srgrimes{ 1811558Srgrimes 1821558Srgrimes return (node_trav(el, el->el_key.map, ch, val)); 1831558Srgrimes} 1841558Srgrimes 1851558Srgrimes 1861558Srgrimes/* key_add(): 1871558Srgrimes * Adds key to the el->el_key.map and associates the value in val with it. 1881558Srgrimes * If key is already is in el->el_key.map, the new code is applied to the 1891558Srgrimes * existing key. Ntype specifies if code is a command, an 1901558Srgrimes * out str or a unix command. 191114571Sphk */ 192114571Sphkprotected void 193114571Sphkkey_add(EditLine *el, const char *key, key_value_t *val, int ntype) 194114571Sphk{ 1951558Srgrimes 1961558Srgrimes if (key[0] == '\0') { 1971558Srgrimes (void) fprintf(el->el_errfile, 1981558Srgrimes "key_add: Null extended-key not allowed.\n"); 1991558Srgrimes return; 2001558Srgrimes } 2011558Srgrimes if (ntype == XK_CMD && val->cmd == ED_SEQUENCE_LEAD_IN) { 2021558Srgrimes (void) fprintf(el->el_errfile, 2031558Srgrimes "key_add: sequence-lead-in command not allowed\n"); 2041558Srgrimes return; 2051558Srgrimes } 2061558Srgrimes if (el->el_key.map == NULL) 207114571Sphk /* tree is initially empty. Set up new node to match key[0] */ 2081558Srgrimes el->el_key.map = node__get(key[0]); 2091558Srgrimes /* it is properly initialized */ 210115995Sphk 211115995Sphk /* Now recurse through el->el_key.map */ 2121558Srgrimes (void) node__try(el, el->el_key.map, key, val, ntype); 213114569Sphk return; 214127650Sluigi} 215139856Srse 216114569Sphk 217183143Slulf/* key_clear(): 218183143Slulf * 219183143Slulf */ 220183143Slulfprotected void 221183143Slulfkey_clear(EditLine *el, el_action_t *map, char *in) 222183143Slulf{ 223183143Slulf 224183143Slulf if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && 225183143Slulf ((map == el->el_map.key && 226183143Slulf el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) || 227183143Slulf (map == el->el_map.alt && 228183143Slulf el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN))) 229183487Slulf (void) key_delete(el, in); 230183496Slulf} 231183143Slulf 232183143Slulf 233183496Slulf/* key_delete(): 2341558Srgrimes * Delete the key and all longer keys staring with key, if 2351558Srgrimes * they exists. 236114571Sphk */ 237114571Sphkprotected int 238114571Sphkkey_delete(EditLine *el, char *key) 239114571Sphk{ 240114571Sphk 2411558Srgrimes if (key[0] == '\0') { 2421558Srgrimes (void) fprintf(el->el_errfile, 24348957Sbillf "key_delete: Null extended-key not allowed.\n"); 24448957Sbillf return (-1); 24548957Sbillf } 2461558Srgrimes if (el->el_key.map == NULL) 2471558Srgrimes return (0); 2481558Srgrimes 249114571Sphk (void) node__delete(el, &el->el_key.map, key); 250121222Sphk return (0); 251114571Sphk} 2521558Srgrimes 2531558Srgrimes 2541558Srgrimes/* key_print(): 2551558Srgrimes * Print the binding associated with key key. 2561558Srgrimes * Print entire el->el_key.map if null 257114571Sphk */ 258114571Sphkprotected void 259114571Sphkkey_print(EditLine *el, char *key) 2601558Srgrimes{ 2611558Srgrimes 2621558Srgrimes /* do nothing if el->el_key.map is empty and null key specified */ 2631558Srgrimes if (el->el_key.map == NULL && *key == 0) 2641558Srgrimes return; 2651558Srgrimes 266114569Sphk el->el_key.buf[0] = '"'; 267114571Sphk if (node_lookup(el, key, el->el_key.map, 1) <= -1) 26837865Sbde /* key is not bound */ 26937865Sbde (void) fprintf(el->el_errfile, "Unbound extended key \"%s\"\n", 270114571Sphk key); 2711558Srgrimes return; 2721558Srgrimes} 2731558Srgrimes 274114571Sphk 275114571Sphk/* node_trav(): 276114571Sphk * recursively traverses node in tree until match or mismatch is 277114571Sphk * found. May read in more characters. 278114571Sphk */ 2791558Srgrimesprivate int 280114571Sphknode_trav(EditLine *el, key_node_t *ptr, char *ch, key_value_t *val) 281114571Sphk{ 282121222Sphk 283114571Sphk if (ptr->ch == *ch) { 284114571Sphk /* match found */ 2851558Srgrimes if (ptr->next) { 2861558Srgrimes /* key not complete so get next char */ 2871558Srgrimes if (el_getc(el, ch) != 1) { /* if EOF or error */ 2881558Srgrimes val->cmd = ED_END_OF_FILE; 289114571Sphk return (XK_CMD); 290121222Sphk /* PWP: Pretend we just read an end-of-file */ 2911558Srgrimes } 292114571Sphk return (node_trav(el, ptr->next, ch, val)); 293114571Sphk } else { 294114571Sphk *val = ptr->val; 2951558Srgrimes if (ptr->type != XK_CMD) 2961558Srgrimes *ch = '\0'; 2971558Srgrimes return (ptr->type); 2981558Srgrimes } 2991558Srgrimes } else { 300121222Sphk /* no match found here */ 301121222Sphk if (ptr->sibling) { 302121222Sphk /* try next sibling */ 303121222Sphk return (node_trav(el, ptr->sibling, ch, val)); 304121222Sphk } else { 305121222Sphk /* no next sibling -- mismatch */ 306174501Smarcel val->str = NULL; 307121222Sphk return (XK_STR); 308121222Sphk } 309121222Sphk } 310121222Sphk} 311121222Sphk 312121222Sphk 313121222Sphk/* node__try(): 314121222Sphk * Find a node that matches *str or allocate a new one 315121222Sphk */ 316121222Sphkprivate int 317121222Sphknode__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int ntype) 3181558Srgrimes{ 319111286Sru 3201558Srgrimes if (ptr->ch != *str) { 321114571Sphk key_node_t *xm; 322114571Sphk 3231558Srgrimes for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 32492541Simp if (xm->sibling->ch == *str) 32513550Sjoerg break; 32613550Sjoerg if (xm->sibling == NULL) 32713550Sjoerg xm->sibling = node__get(*str); /* setup new node */ 32813550Sjoerg ptr = xm->sibling; 32913544Sjoerg } 33036632Scharnier if (*++str == '\0') { 33136632Scharnier /* we're there */ 3321558Srgrimes if (ptr->next != NULL) { 3331558Srgrimes node__put(el, ptr->next); 3341558Srgrimes /* lose longer keys with this prefix */ 3351558Srgrimes ptr->next = NULL; 336114571Sphk } 337114571Sphk switch (ptr->type) { 3381558Srgrimes case XK_CMD: 339209614Sjh case XK_NOD: 340114571Sphk break; 341114571Sphk case XK_STR: 342114571Sphk case XK_EXE: 343114571Sphk if (ptr->val.str) 344114571Sphk el_free((ptr_t) ptr->val.str); 345114571Sphk break; 346114571Sphk default: 347114571Sphk EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", 348219448Suqs ptr->type)); 349209614Sjh break; 350114571Sphk } 351216095Skevlo 352114571Sphk switch (ptr->type = ntype) { 353133347Sdes case XK_CMD: 354114571Sphk ptr->val = *val; 355114571Sphk break; 356114571Sphk case XK_STR: 357114571Sphk case XK_EXE: 358227270Sae ptr->val.str = strdup(val->str); 359211873Sjh break; 360211873Sjh default: 361211873Sjh EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); 362211873Sjh break; 363211873Sjh } 364211873Sjh } else { 365211873Sjh /* still more chars to go */ 366211873Sjh if (ptr->next == NULL) 367211873Sjh ptr->next = node__get(*str); /* setup new node */ 368211873Sjh (void) node__try(el, ptr->next, str, val, ntype); 369227270Sae } 370211873Sjh return (0); 371211873Sjh} 372211873Sjh 373211873Sjh 374211873Sjh/* node__delete(): 375211873Sjh * Delete node that matches str 376211873Sjh */ 377211873Sjhprivate int 378211873Sjhnode__delete(EditLine *el, key_node_t **inptr, char *str) 379211873Sjh{ 380211873Sjh key_node_t *ptr; 381114571Sphk key_node_t *prev_ptr = NULL; 382114571Sphk 383211873Sjh ptr = *inptr; 384114569Sphk 385114569Sphk if (ptr->ch != *str) { 386114571Sphk key_node_t *xm; 38738384Sdfr 38873034Sjwd for (xm = ptr; xm->sibling != NULL; xm = xm->sibling) 389114574Sphk if (xm->sibling->ch == *str) 390114571Sphk break; 39173034Sjwd if (xm->sibling == NULL) 392109878Sphk return (0); 393109878Sphk prev_ptr = xm; 394109878Sphk ptr = xm->sibling; 395109878Sphk } 396109878Sphk if (*++str == '\0') { 397109878Sphk /* we're there */ 398114571Sphk if (prev_ptr == NULL) 399114571Sphk *inptr = ptr->sibling; 400114673Sphk else 401114673Sphk prev_ptr->sibling = ptr->sibling; 402196383Smarcel ptr->sibling = NULL; 403229049Ssobomax node__put(el, ptr); 404115696Sphk return (1); 405114569Sphk } else if (ptr->next != NULL && 406114569Sphk node__delete(el, &ptr->next, str) == 1) { 407114569Sphk if (ptr->next != NULL) 408127650Sluigi return (0); 409127650Sluigi if (prev_ptr == NULL) 410127650Sluigi *inptr = ptr->sibling; 411211873Sjh else 412211873Sjh prev_ptr->sibling = ptr->sibling; 413211873Sjh ptr->sibling = NULL; 414227270Sae node__put(el, ptr); 415227296Sae return (1); 416227296Sae } else { 417227270Sae return (0); 418227270Sae } 419227270Sae} 420227270Sae 421227270Sae 422227270Sae/* node__put(): 423227270Sae * Puts a tree of nodes onto free list using free(3). 424227270Sae */ 425227270Saeprivate void 426211873Sjhnode__put(EditLine *el, key_node_t *ptr) 427227270Sae{ 428211873Sjh if (ptr == NULL) 429211873Sjh return; 430127650Sluigi 431183143Slulf if (ptr->next != NULL) { 432115624Sphk node__put(el, ptr->next); 433115624Sphk ptr->next = NULL; 434114569Sphk } 435183143Slulf node__put(el, ptr->sibling); 436133347Sdes 437229049Ssobomax switch (ptr->type) { 438114569Sphk case XK_CMD: 439114571Sphk case XK_NOD: 440114571Sphk break; 441114571Sphk case XK_EXE: 442114571Sphk case XK_STR: 443114571Sphk if (ptr->val.str != NULL) 444114569Sphk el_free((ptr_t) ptr->val.str); 445114569Sphk break; 446115624Sphk default: 447115624Sphk EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ptr->type)); 448114569Sphk break; 449183143Slulf } 450114571Sphk el_free((ptr_t) ptr); 451114569Sphk} 452114571Sphk 453114571Sphk 454114571Sphk/* node__get(): 455114571Sphk * Returns pointer to an key_node_t for ch. 456114571Sphk */ 457114569Sphkprivate key_node_t * 458114569Sphknode__get(int ch) 459114569Sphk{ 460114571Sphk key_node_t *ptr; 461114569Sphk 462114569Sphk ptr = (key_node_t *) el_malloc((size_t) sizeof(key_node_t)); 463114569Sphk if (ptr == NULL) 464114569Sphk return NULL; 465114569Sphk ptr->ch = ch; 466109878Sphk ptr->type = XK_NOD; 4671558Srgrimes ptr->val.str = NULL; 4681558Srgrimes ptr->next = NULL; 4691558Srgrimes ptr->sibling = NULL; 470127650Sluigi return (ptr); 471127650Sluigi} 472127650Sluigi 473127650Sluigi 474127650Sluigi 475127650Sluigi/* node_lookup(): 476127650Sluigi * look for the str starting at node ptr. 477127650Sluigi * Print if last node 478127650Sluigi */ 479127650Sluigiprivate int 480127650Sluiginode_lookup(EditLine *el, char *str, key_node_t *ptr, int cnt) 481127650Sluigi{ 482127650Sluigi int ncnt; 483127650Sluigi 484127650Sluigi if (ptr == NULL) 4851558Srgrimes return (-1); /* cannot have null ptr */ 4861558Srgrimes 4871558Srgrimes if (*str == 0) { 488114571Sphk /* no more chars in str. node_enum from here. */ 489114571Sphk (void) node_enum(el, ptr, cnt); 4901558Srgrimes return (0); 491209614Sjh } else { 492196383Smarcel /* If match put this char into el->el_key.buf. Recurse */ 493114673Sphk if (ptr->ch == *str) { 494114569Sphk /* match found */ 4951558Srgrimes ncnt = key__decode_char(el->el_key.buf, cnt, 496114569Sphk (unsigned char) ptr->ch); 497114569Sphk if (ptr->next != NULL) 498215704Sbrucec /* not yet at leaf */ 499127650Sluigi return (node_lookup(el, str + 1, ptr->next, 500127650Sluigi ncnt + 1)); 501183143Slulf else { 502183143Slulf /* next node is null so key should be complete */ 503183143Slulf if (str[1] == 0) { 504183143Slulf el->el_key.buf[ncnt + 1] = '"'; 505183143Slulf el->el_key.buf[ncnt + 2] = '\0'; 506115696Sphk key_kprint(el, el->el_key.buf, 507134973Sbrooks &ptr->val, ptr->type); 508134973Sbrooks return (0); 509134973Sbrooks } else 510114550Sphk return (-1); 511209614Sjh /* mismatch -- str still has chars */ 512209614Sjh } 513114569Sphk } else { 514209614Sjh /* no match found try sibling */ 515209614Sjh if (ptr->sibling) 516114569Sphk return (node_lookup(el, str, ptr->sibling, 517115696Sphk cnt)); 518115696Sphk else 519115696Sphk return (-1); 520114571Sphk } 521114571Sphk } 522114673Sphk} 523183143Slulf 524183143Slulf 525196383Smarcel/* node_enum(): 526196383Smarcel * Traverse the node printing the characters it is bound in buffer 527196383Smarcel */ 528196383Smarcelprivate int 529196383Smarcelnode_enum(EditLine *el, key_node_t *ptr, int cnt) 530196383Smarcel{ 531196383Smarcel int ncnt; 532196383Smarcel 533196383Smarcel if (cnt >= KEY_BUFSIZ - 5) { /* buffer too small */ 534196383Smarcel el->el_key.buf[++cnt] = '"'; 535114673Sphk el->el_key.buf[++cnt] = '\0'; 536196383Smarcel (void) fprintf(el->el_errfile, 537196383Smarcel "Some extended keys too long for internal print buffer"); 538114673Sphk (void) fprintf(el->el_errfile, " \"%s...\"\n", el->el_key.buf); 539196383Smarcel return (0); 540196383Smarcel } 541196383Smarcel if (ptr == NULL) { 542196383Smarcel#ifdef DEBUG_EDIT 543196383Smarcel (void) fprintf(el->el_errfile, 544196383Smarcel "node_enum: BUG!! Null ptr passed\n!"); 545196383Smarcel#endif 546196383Smarcel return (-1); 547114571Sphk } 5481558Srgrimes /* put this char at end of str */ 5491558Srgrimes ncnt = key__decode_char(el->el_key.buf, cnt, (unsigned char) ptr->ch); 5501558Srgrimes if (ptr->next == NULL) { 551114571Sphk /* print this key and function */ 55292541Simp el->el_key.buf[ncnt + 1] = '"'; 5531558Srgrimes el->el_key.buf[ncnt + 2] = '\0'; 55492541Simp key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); 55592541Simp } else 5561558Srgrimes (void) node_enum(el, ptr->next, ncnt + 1); 557114571Sphk 558114571Sphk /* go to sibling if there is one */ 559114571Sphk if (ptr->sibling) 5601558Srgrimes (void) node_enum(el, ptr->sibling, cnt); 561114574Sphk return (0); 562114574Sphk} 563114574Sphk 564114574Sphk 565114574Sphk/* key_kprint(): 566114574Sphk * Print the specified key and its associated 567114574Sphk * function specified by val 568114574Sphk */ 569114574Sphkprotected void 570114574Sphkkey_kprint(EditLine *el, char *key, key_value_t *val, int ntype) 571114574Sphk{ 572114574Sphk el_bindings_t *fp; 573114574Sphk char unparsbuf[EL_BUFSIZ]; 574114574Sphk static const char fmt[] = "%-15s-> %s\n"; 575114574Sphk 576114574Sphk if (val != NULL) 577114574Sphk switch (ntype) { 578114574Sphk case XK_STR: 579114574Sphk case XK_EXE: 580114574Sphk (void) fprintf(el->el_outfile, fmt, key, 581114574Sphk key__decode_str(val->str, unparsbuf, 582114574Sphk ntype == XK_STR ? "\"\"" : "[]")); 583114574Sphk break; 584114574Sphk case XK_CMD: 585114574Sphk for (fp = el->el_map.help; fp->name; fp++) 586114574Sphk if (val->cmd == fp->func) { 587114574Sphk (void) fprintf(el->el_outfile, fmt, 588114574Sphk key, fp->name); 589114574Sphk break; 590114574Sphk } 591114574Sphk#ifdef DEBUG_KEY 592114574Sphk if (fp->name == NULL) 593114574Sphk (void) fprintf(el->el_outfile, 594114574Sphk "BUG! Command not found.\n"); 595114574Sphk#endif 596114574Sphk 597114574Sphk break; 598114574Sphk default: 599114574Sphk EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); 600114574Sphk break; 601114574Sphk } 602114574Sphk else 6031558Srgrimes (void) fprintf(el->el_outfile, fmt, key, "no input"); 604219449Suqs} 6051558Srgrimes 6061558Srgrimes 6071558Srgrimes/* key__decode_char(): 608219449Suqs * Put a printable form of char in buf. 60937234Sbde */ 610107041Sjulianprivate int 6111558Srgrimeskey__decode_char(char *buf, int cnt, int ch) 6121558Srgrimes{ 6131558Srgrimes ch = (unsigned char)ch; 6141558Srgrimes 6151558Srgrimes if (ch == 0) { 6161558Srgrimes buf[cnt++] = '^'; 617219449Suqs buf[cnt] = '@'; 61837234Sbde return (cnt); 61937234Sbde } 6201558Srgrimes if (iscntrl(ch)) { 6211558Srgrimes buf[cnt++] = '^'; 6221558Srgrimes if (ch == 0177) 623219449Suqs buf[cnt] = '?'; 62437234Sbde else 62537234Sbde buf[cnt] = toascii(ch) | 0100; 6261558Srgrimes } else if (ch == '^') { 6271558Srgrimes buf[cnt++] = '\\'; 6281558Srgrimes buf[cnt] = '^'; 6295393Sgibbs } else if (ch == '\\') { 63037234Sbde buf[cnt++] = '\\'; 63137234Sbde buf[cnt] = '\\'; 63237234Sbde } else if (ch == ' ' || (isprint(ch) && !isspace(ch))) { 6335393Sgibbs buf[cnt] = ch; 6345393Sgibbs } else { 6355393Sgibbs buf[cnt++] = '\\'; 6361558Srgrimes buf[cnt++] = (((unsigned int) ch >> 6) & 7) + '0'; 6371558Srgrimes buf[cnt++] = (((unsigned int) ch >> 3) & 7) + '0'; 6381558Srgrimes buf[cnt] = (ch & 7) + '0'; 6391558Srgrimes } 640114574Sphk return (cnt); 641114574Sphk} 642114574Sphk 643114571Sphk/* key__decode_str(): 6441558Srgrimes * Make a printable version of the ey 6451558Srgrimes */ 6461558Srgrimesprotected char * 6471558Srgrimeskey__decode_str(char *str, char *buf, char *sep) 6481558Srgrimes{ 649114571Sphk char *b, *p; 650114571Sphk 6511558Srgrimes b = buf; 65292541Simp if (sep[0] != '\0') 6531558Srgrimes *b++ = sep[0]; 65424180Simp if (*str == 0) { 6551558Srgrimes *b++ = '^'; 65624180Simp *b++ = '@'; 65724180Simp if (sep[0] != '\0' && sep[1] != '\0') 65836632Scharnier *b++ = sep[1]; 6591558Srgrimes *b++ = 0; 6601558Srgrimes return (buf); 661114571Sphk } 66224180Simp for (p = str; *p != 0; p++) { 6631558Srgrimes if (iscntrl((unsigned char) *p)) { 6641558Srgrimes *b++ = '^'; 6651558Srgrimes if (*p == '\177') 66624180Simp *b++ = '?'; 66724180Simp else 66836632Scharnier *b++ = toascii(*p) | 0100; 6691558Srgrimes } else if (*p == '^' || *p == '\\') { 6701558Srgrimes *b++ = '\\'; 6711558Srgrimes *b++ = *p; 672114571Sphk } else if (*p == ' ' || (isprint((unsigned char) *p) && 673114571Sphk !isspace((unsigned char) *p))) { 674114571Sphk *b++ = *p; 675114571Sphk } else { 676114571Sphk *b++ = '\\'; 6771558Srgrimes *b++ = (((unsigned int) *p >> 6) & 7) + '0'; 6781558Srgrimes *b++ = (((unsigned int) *p >> 3) & 7) + '0'; 6791558Srgrimes *b++ = (*p & 7) + '0'; 6801558Srgrimes } 681114571Sphk } 682114571Sphk if (sep[0] != '\0' && sep[1] != '\0') 6831558Srgrimes *b++ = sep[1]; 6841558Srgrimes *b++ = 0; 6851558Srgrimes return (buf); /* should check for overflow */ 6861558Srgrimes} 6871558Srgrimes