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