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