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