1 /* $OpenBSD: emacs.c,v 1.48 2013/12/17 16:37:05 deraadt Exp $ */ 2 3 /* 4 * Emacs-like command line editing and history 5 * 6 * created by Ron Natalie at BRL 7 * modified by Doug Kingston, Doug Gwyn, and Lou Salkind 8 * adapted to PD ksh by Eric Gisin 9 * 10 * partial rewrite by Marco Peereboom <marco@openbsd.org> 11 * under the same license 12 */ 13 14 #include "config.h" 15 #ifdef EMACS 16 17 #include "sh.h" 18 #include <sys/stat.h> 19 #include <sys/queue.h> 20 #include <ctype.h> 21 #include <locale.h> 22 #include "edit.h" 23 24 static Area aedit; 25 #define AEDIT &aedit /* area for kill ring and macro defns */ 26 27 #define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */ 28 #define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */ 29 #define META(x) ((x) & 0x7f) 30 #define ISMETA(x) (Flag(FEMACSUSEMETA) && ((x) & 0x80)) 31 32 33 /* values returned by keyboard functions */ 34 #define KSTD 0 35 #define KEOL 1 /* ^M, ^J */ 36 #define KINTR 2 /* ^G, ^C */ 37 38 struct x_ftab { 39 int (*xf_func)(int c); 40 const char *xf_name; 41 short xf_flags; 42 }; 43 44 #define XF_ARG 1 /* command takes number prefix */ 45 #define XF_NOBIND 2 /* not allowed to bind to function */ 46 #define XF_PREFIX 4 /* function sets prefix */ 47 48 /* Separator for completion */ 49 #define is_cfs(c) (c == ' ' || c == '\t' || c == '"' || c == '\'') 50 51 /* Separator for motion */ 52 #define is_mfs(c) (!(isalnum((unsigned char)c) || c == '_' || c == '$')) 53 54 /* Arguments for do_complete() 55 * 0 = enumerate M-= complete as much as possible and then list 56 * 1 = complete M-Esc 57 * 2 = list M-? 58 */ 59 typedef enum { 60 CT_LIST, /* list the possible completions */ 61 CT_COMPLETE, /* complete to longest prefix */ 62 CT_COMPLIST /* complete and then list (if non-exact) */ 63 } Comp_type; 64 65 /* keybindings */ 66 struct kb_entry { 67 TAILQ_ENTRY(kb_entry) entry; 68 unsigned char *seq; 69 int len; 70 struct x_ftab *ftab; 71 void *args; 72 }; 73 TAILQ_HEAD(kb_list, kb_entry); 74 struct kb_list kblist = TAILQ_HEAD_INITIALIZER(kblist); 75 76 /* { from 4.9 edit.h */ 77 /* 78 * The following are used for my horizontal scrolling stuff 79 */ 80 static char *xbuf; /* beg input buffer */ 81 static char *xend; /* end input buffer */ 82 static char *xcp; /* current position */ 83 static char *xep; /* current end */ 84 static char *xbp; /* start of visible portion of input buffer */ 85 static char *xlp; /* last char visible on screen */ 86 static int x_adj_ok; 87 /* 88 * we use x_adj_done so that functions can tell 89 * whether x_adjust() has been called while they are active. 90 */ 91 static int x_adj_done; 92 93 static int xx_cols; 94 static int x_col; 95 static int x_displen; 96 static int x_arg; /* general purpose arg */ 97 static int x_arg_defaulted;/* x_arg not explicitly set; defaulted to 1 */ 98 99 static int xlp_valid; 100 /* end from 4.9 edit.h } */ 101 static int x_tty; /* are we on a tty? */ 102 static int x_bind_quiet; /* be quiet when binding keys */ 103 static int (*x_last_command)(int); 104 105 static char **x_histp; /* history position */ 106 static int x_nextcmd; /* for newline-and-next */ 107 static char *xmp; /* mark pointer */ 108 #define KILLSIZE 20 109 static char *killstack[KILLSIZE]; 110 static int killsp, killtp; 111 static int x_literal_set; 112 static int x_arg_set; 113 static char *macro_args; 114 static int prompt_skip; 115 static int prompt_redraw; 116 117 static int x_ins(char *); 118 static void x_delete(int, int); 119 static int x_bword(void); 120 static int x_fword(void); 121 static void x_goto(char *); 122 static void x_bs(int); 123 static int x_size_str(char *); 124 static int x_size(int); 125 static void x_zots(char *); 126 static void x_zotc(int); 127 static void x_load_hist(char **); 128 static int x_search(char *, int, int); 129 static int x_match(char *, char *); 130 static void x_redraw(int); 131 static void x_push(int); 132 static void x_adjust(void); 133 static void x_e_ungetc(int); 134 static int x_e_getc(void); 135 static void x_e_putc(int); 136 static void x_e_puts(const char *); 137 static int x_comment(int); 138 static int x_fold_case(int); 139 static char *x_lastcp(void); 140 static void do_complete(int, Comp_type); 141 static int x_emacs_putbuf(const char *, size_t); 142 143 /* proto's for keybindings */ 144 static int x_abort(int); 145 static int x_beg_hist(int); 146 static int x_comp_comm(int); 147 static int x_comp_file(int); 148 static int x_complete(int); 149 static int x_del_back(int); 150 static int x_del_bword(int); 151 static int x_del_char(int); 152 static int x_del_fword(int); 153 static int x_del_line(int); 154 static int x_draw_line(int); 155 static int x_end_hist(int); 156 static int x_end_of_text(int); 157 static int x_enumerate(int); 158 static int x_eot_del(int); 159 static int x_error(int); 160 static int x_goto_hist(int); 161 static int x_ins_string(int); 162 static int x_insert(int); 163 static int x_kill(int); 164 static int x_kill_region(int); 165 static int x_list_comm(int); 166 static int x_list_file(int); 167 static int x_literal(int); 168 static int x_meta_yank(int); 169 static int x_mv_back(int); 170 static int x_mv_begin(int); 171 static int x_mv_bword(int); 172 static int x_mv_end(int); 173 static int x_mv_forw(int); 174 static int x_mv_fword(int); 175 static int x_newline(int); 176 static int x_next_com(int); 177 static int x_nl_next_com(int); 178 static int x_noop(int); 179 static int x_prev_com(int); 180 static int x_prev_histword(int); 181 static int x_search_char_forw(int); 182 static int x_search_char_back(int); 183 static int x_search_hist(int); 184 static int x_set_mark(int); 185 static int x_stuff(int); 186 static int x_stuffreset(int); 187 static int x_transpose(int); 188 static int x_version(int); 189 static int x_xchg_point_mark(int); 190 static int x_yank(int); 191 static int x_comp_list(int); 192 static int x_expand(int); 193 static int x_fold_capitalize(int); 194 static int x_fold_lower(int); 195 static int x_fold_upper(int); 196 static int x_set_arg(int); 197 static int x_comment(int); 198 #ifdef DEBUG 199 static int x_debug_info(int); 200 #endif 201 202 static const struct x_ftab x_ftab[] = { 203 { x_abort, "abort", 0 }, 204 { x_beg_hist, "beginning-of-history", 0 }, 205 { x_comp_comm, "complete-command", 0 }, 206 { x_comp_file, "complete-file", 0 }, 207 { x_complete, "complete", 0 }, 208 { x_del_back, "delete-char-backward", XF_ARG }, 209 { x_del_bword, "delete-word-backward", XF_ARG }, 210 { x_del_char, "delete-char-forward", XF_ARG }, 211 { x_del_fword, "delete-word-forward", XF_ARG }, 212 { x_del_line, "kill-line", 0 }, 213 { x_draw_line, "redraw", 0 }, 214 { x_end_hist, "end-of-history", 0 }, 215 { x_end_of_text, "eot", 0 }, 216 { x_enumerate, "list", 0 }, 217 { x_eot_del, "eot-or-delete", XF_ARG }, 218 { x_error, "error", 0 }, 219 { x_goto_hist, "goto-history", XF_ARG }, 220 { x_ins_string, "macro-string", XF_NOBIND }, 221 { x_insert, "auto-insert", XF_ARG }, 222 { x_kill, "kill-to-eol", XF_ARG }, 223 { x_kill_region, "kill-region", 0 }, 224 { x_list_comm, "list-command", 0 }, 225 { x_list_file, "list-file", 0 }, 226 { x_literal, "quote", 0 }, 227 { x_meta_yank, "yank-pop", 0 }, 228 { x_mv_back, "backward-char", XF_ARG }, 229 { x_mv_begin, "beginning-of-line", 0 }, 230 { x_mv_bword, "backward-word", XF_ARG }, 231 { x_mv_end, "end-of-line", 0 }, 232 { x_mv_forw, "forward-char", XF_ARG }, 233 { x_mv_fword, "forward-word", XF_ARG }, 234 { x_newline, "newline", 0 }, 235 { x_next_com, "down-history", XF_ARG }, 236 { x_nl_next_com, "newline-and-next", 0 }, 237 { x_noop, "no-op", 0 }, 238 { x_prev_com, "up-history", XF_ARG }, 239 { x_prev_histword, "prev-hist-word", XF_ARG }, 240 { x_search_char_forw, "search-character-forward", XF_ARG }, 241 { x_search_char_back, "search-character-backward", XF_ARG }, 242 { x_search_hist, "search-history", 0 }, 243 { x_set_mark, "set-mark-command", 0 }, 244 { x_stuff, "stuff", 0 }, 245 { x_stuffreset, "stuff-reset", 0 }, 246 { x_transpose, "transpose-chars", 0 }, 247 { x_version, "version", 0 }, 248 { x_xchg_point_mark, "exchange-point-and-mark", 0 }, 249 { x_yank, "yank", 0 }, 250 { x_comp_list, "complete-list", 0 }, 251 { x_expand, "expand-file", 0 }, 252 { x_fold_capitalize, "capitalize-word", XF_ARG }, 253 { x_fold_lower, "downcase-word", XF_ARG }, 254 { x_fold_upper, "upcase-word", XF_ARG }, 255 { x_set_arg, "set-arg", XF_NOBIND }, 256 { x_comment, "comment", 0 }, 257 { 0, 0, 0 }, 258 #ifdef DEBUG 259 { x_debug_info, "debug-info", 0 }, 260 #else 261 { 0, 0, 0 }, 262 #endif 263 { 0, 0, 0 }, 264 }; 265 266 int 267 x_emacs(char *buf, size_t len) 268 { 269 struct kb_entry *k, *kmatch = NULL; 270 char line[LINE + 1]; 271 int at = 0, submatch, ret, c; 272 const char *p; 273 274 xbp = xbuf = buf; xend = buf + len; 275 xlp = xcp = xep = buf; 276 *xcp = 0; 277 xlp_valid = true; 278 xmp = NULL; 279 x_histp = histptr + 1; 280 281 xx_cols = x_cols; 282 x_col = promptlen(prompt, &p); 283 prompt_skip = p - prompt; 284 x_adj_ok = 1; 285 prompt_redraw = 1; 286 if (x_col > xx_cols) 287 x_col = x_col - (x_col / xx_cols) * xx_cols; 288 x_displen = xx_cols - 2 - x_col; 289 x_adj_done = 0; 290 291 pprompt(prompt, 0); 292 if (x_displen < 1) { 293 x_col = 0; 294 x_displen = xx_cols - 2; 295 x_e_putc('\n'); 296 prompt_redraw = 0; 297 } 298 299 if (x_nextcmd >= 0) { 300 int off = source->line - x_nextcmd; 301 if (histptr - history >= off) 302 x_load_hist(histptr - off); 303 x_nextcmd = -1; 304 } 305 306 line[0] = '\0'; 307 x_literal_set = 0; 308 x_arg = -1; 309 x_last_command = NULL; 310 while (1) { 311 x_flush(); 312 if ((c = x_e_getc()) < 0) 313 return 0; 314 315 line[at++] = c; 316 line[at] = '\0'; 317 318 if (x_arg == -1) { 319 x_arg = 1; 320 x_arg_defaulted = 1; 321 } 322 323 if (x_literal_set) { 324 /* literal, so insert it */ 325 x_literal_set = 0; 326 submatch = 0; 327 } else { 328 submatch = 0; 329 kmatch = NULL; 330 TAILQ_FOREACH(k, &kblist, entry) { 331 if (at > k->len) 332 continue; 333 334 if (!bcmp(k->seq, line, at)) { 335 /* sub match */ 336 submatch++; 337 if (k->len == at) 338 kmatch = k; 339 } 340 341 /* see if we can abort search early */ 342 if (submatch > 1) 343 break; 344 } 345 } 346 347 if (submatch == 1 && kmatch) { 348 if (kmatch->ftab->xf_func == x_ins_string && 349 kmatch->args && !macro_args) { 350 /* treat macro string as input */ 351 macro_args = kmatch->args; 352 ret = KSTD; 353 } else 354 ret = kmatch->ftab->xf_func(c); 355 } else { 356 if (submatch) 357 continue; 358 if (at == 1) 359 ret = x_insert(c); 360 else 361 ret = x_error(c); /* not matched meta sequence */ 362 } 363 364 switch (ret) { 365 case KSTD: 366 if (kmatch) 367 x_last_command = kmatch->ftab->xf_func; 368 else 369 x_last_command = NULL; 370 break; 371 case KEOL: 372 ret = xep - xbuf; 373 return (ret); 374 break; 375 case KINTR: 376 trapsig(SIGINT); 377 x_mode(false); 378 unwind(LSHELL); 379 x_arg = -1; 380 break; 381 default: 382 bi_errorf("invalid return code"); /* can't happen */ 383 } 384 385 /* reset meta sequence */ 386 at = 0; 387 line[0] = '\0'; 388 if (x_arg_set) 389 x_arg_set = 0; /* reset args next time around */ 390 else 391 x_arg = -1; 392 } 393 } 394 395 static int 396 x_insert(int c) 397 { 398 char str[2]; 399 400 /* 401 * Should allow tab and control chars. 402 */ 403 if (c == 0) { 404 x_e_putc(BEL); 405 return KSTD; 406 } 407 str[0] = c; 408 str[1] = '\0'; 409 while (x_arg--) 410 x_ins(str); 411 return KSTD; 412 } 413 414 static int 415 x_ins_string(int c) 416 { 417 return x_insert(c); 418 } 419 420 static int x_do_ins(const char *cp, int len); 421 422 static int 423 x_do_ins(const char *cp, int len) 424 { 425 if (xep+len >= xend) { 426 x_e_putc(BEL); 427 return -1; 428 } 429 430 memmove(xcp+len, xcp, xep - xcp + 1); 431 memmove(xcp, cp, len); 432 xcp += len; 433 xep += len; 434 return 0; 435 } 436 437 static int 438 x_ins(char *s) 439 { 440 char *cp = xcp; 441 int adj = x_adj_done; 442 443 if (x_do_ins(s, strlen(s)) < 0) 444 return -1; 445 /* 446 * x_zots() may result in a call to x_adjust() 447 * we want xcp to reflect the new position. 448 */ 449 xlp_valid = false; 450 x_lastcp(); 451 x_adj_ok = (xcp >= xlp); 452 x_zots(cp); 453 if (adj == x_adj_done) { /* has x_adjust() been called? */ 454 /* no */ 455 for (cp = xlp; cp > xcp; ) 456 x_bs(*--cp); 457 } 458 459 x_adj_ok = 1; 460 return 0; 461 } 462 463 /* 464 * this is used for x_escape() in do_complete() 465 */ 466 static int 467 x_emacs_putbuf(const char *s, size_t len) 468 { 469 int rval; 470 471 if ((rval = x_do_ins(s, len)) != 0) 472 return (rval); 473 return (rval); 474 } 475 476 static int 477 x_del_back(int c) 478 { 479 int col = xcp - xbuf; 480 481 if (col == 0) { 482 x_e_putc(BEL); 483 return KSTD; 484 } 485 if (x_arg > col) 486 x_arg = col; 487 x_goto(xcp - x_arg); 488 x_delete(x_arg, false); 489 return KSTD; 490 } 491 492 static int 493 x_del_char(int c) 494 { 495 int nleft = xep - xcp; 496 497 if (!nleft) { 498 x_e_putc(BEL); 499 return KSTD; 500 } 501 if (x_arg > nleft) 502 x_arg = nleft; 503 x_delete(x_arg, false); 504 return KSTD; 505 } 506 507 /* Delete nc chars to the right of the cursor (including cursor position) */ 508 static void 509 x_delete(int nc, int push) 510 { 511 int i,j; 512 char *cp; 513 514 if (nc == 0) 515 return; 516 if (xmp != NULL && xmp > xcp) { 517 if (xcp + nc > xmp) 518 xmp = xcp; 519 else 520 xmp -= nc; 521 } 522 523 /* 524 * This lets us yank a word we have deleted. 525 */ 526 if (push) 527 x_push(nc); 528 529 xep -= nc; 530 cp = xcp; 531 j = 0; 532 i = nc; 533 while (i--) { 534 j += x_size((unsigned char)*cp++); 535 } 536 memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */ 537 x_adj_ok = 0; /* don't redraw */ 538 x_zots(xcp); 539 /* 540 * if we are already filling the line, 541 * there is no need to ' ','\b'. 542 * But if we must, make sure we do the minimum. 543 */ 544 if ((i = xx_cols - 2 - x_col) > 0) { 545 j = (j < i) ? j : i; 546 i = j; 547 while (i--) 548 x_e_putc(' '); 549 i = j; 550 while (i--) 551 x_e_putc('\b'); 552 } 553 /*x_goto(xcp);*/ 554 x_adj_ok = 1; 555 xlp_valid = false; 556 for (cp = x_lastcp(); cp > xcp; ) 557 x_bs(*--cp); 558 559 return; 560 } 561 562 static int 563 x_del_bword(int c) 564 { 565 x_delete(x_bword(), true); 566 return KSTD; 567 } 568 569 static int 570 x_mv_bword(int c) 571 { 572 (void)x_bword(); 573 return KSTD; 574 } 575 576 static int 577 x_mv_fword(int c) 578 { 579 x_goto(xcp + x_fword()); 580 return KSTD; 581 } 582 583 static int 584 x_del_fword(int c) 585 { 586 x_delete(x_fword(), true); 587 return KSTD; 588 } 589 590 static int 591 x_bword(void) 592 { 593 int nc = 0; 594 char *cp = xcp; 595 596 if (cp == xbuf) { 597 x_e_putc(BEL); 598 return 0; 599 } 600 while (x_arg--) { 601 while (cp != xbuf && is_mfs(cp[-1])) { 602 cp--; 603 nc++; 604 } 605 while (cp != xbuf && !is_mfs(cp[-1])) { 606 cp--; 607 nc++; 608 } 609 } 610 x_goto(cp); 611 return nc; 612 } 613 614 static int 615 x_fword(void) 616 { 617 int nc = 0; 618 char *cp = xcp; 619 620 if (cp == xep) { 621 x_e_putc(BEL); 622 return 0; 623 } 624 while (x_arg--) { 625 while (cp != xep && is_mfs(*cp)) { 626 cp++; 627 nc++; 628 } 629 while (cp != xep && !is_mfs(*cp)) { 630 cp++; 631 nc++; 632 } 633 } 634 return nc; 635 } 636 637 static void 638 x_goto(char *cp) 639 { 640 if (cp < xbp || cp >= (xbp + x_displen)) { 641 /* we are heading off screen */ 642 xcp = cp; 643 x_adjust(); 644 } else if (cp < xcp) { /* move back */ 645 while (cp < xcp) 646 x_bs((unsigned char)*--xcp); 647 } else if (cp > xcp) { /* move forward */ 648 while (cp > xcp) 649 x_zotc((unsigned char)*xcp++); 650 } 651 } 652 653 static void 654 x_bs(int c) 655 { 656 int i; 657 658 i = x_size(c); 659 while (i--) 660 x_e_putc('\b'); 661 } 662 663 static int 664 x_size_str(char *cp) 665 { 666 int size = 0; 667 while (*cp) 668 size += x_size(*cp++); 669 return size; 670 } 671 672 static int 673 x_size(int c) 674 { 675 if (c=='\t') 676 return 4; /* Kludge, tabs are always four spaces. */ 677 if (iscntrl(c)) /* control char */ 678 return 2; 679 return 1; 680 } 681 682 static void 683 x_zots(char *str) 684 { 685 int adj = x_adj_done; 686 687 x_lastcp(); 688 while (*str && str < xlp && adj == x_adj_done) 689 x_zotc(*str++); 690 } 691 692 static void 693 x_zotc(int c) 694 { 695 if (c == '\t') { 696 /* Kludge, tabs are always four spaces. */ 697 x_e_puts(" "); 698 } else if (iscntrl(c)) { 699 x_e_putc('^'); 700 x_e_putc(UNCTRL(c)); 701 } else 702 x_e_putc(c); 703 } 704 705 static int 706 x_mv_back(int c) 707 { 708 int col = xcp - xbuf; 709 710 if (col == 0) { 711 x_e_putc(BEL); 712 return KSTD; 713 } 714 if (x_arg > col) 715 x_arg = col; 716 x_goto(xcp - x_arg); 717 return KSTD; 718 } 719 720 static int 721 x_mv_forw(int c) 722 { 723 int nleft = xep - xcp; 724 725 if (!nleft) { 726 x_e_putc(BEL); 727 return KSTD; 728 } 729 if (x_arg > nleft) 730 x_arg = nleft; 731 x_goto(xcp + x_arg); 732 return KSTD; 733 } 734 735 static int 736 x_search_char_forw(int c) 737 { 738 char *cp = xcp; 739 740 *xep = '\0'; 741 c = x_e_getc(); 742 while (x_arg--) { 743 if (c < 0 || 744 ((cp = (cp == xep) ? NULL : strchr(cp + 1, c)) == NULL && 745 (cp = strchr(xbuf, c)) == NULL)) { 746 x_e_putc(BEL); 747 return KSTD; 748 } 749 } 750 x_goto(cp); 751 return KSTD; 752 } 753 754 static int 755 x_search_char_back(int c) 756 { 757 char *cp = xcp, *p; 758 759 c = x_e_getc(); 760 for (; x_arg--; cp = p) 761 for (p = cp; ; ) { 762 if (p-- == xbuf) 763 p = xep; 764 if (c < 0 || p == cp) { 765 x_e_putc(BEL); 766 return KSTD; 767 } 768 if (*p == c) 769 break; 770 } 771 x_goto(cp); 772 return KSTD; 773 } 774 775 static int 776 x_newline(int c) 777 { 778 x_e_putc('\r'); 779 x_e_putc('\n'); 780 x_flush(); 781 *xep++ = '\n'; 782 return KEOL; 783 } 784 785 static int 786 x_end_of_text(int c) 787 { 788 x_zotc(edchars.eof); 789 x_putc('\r'); 790 x_putc('\n'); 791 x_flush(); 792 return KEOL; 793 } 794 795 static int x_beg_hist(int c) { x_load_hist(history); return KSTD;} 796 797 static int x_end_hist(int c) { x_load_hist(histptr); return KSTD;} 798 799 static int x_prev_com(int c) { x_load_hist(x_histp - x_arg); return KSTD;} 800 801 static int x_next_com(int c) { x_load_hist(x_histp + x_arg); return KSTD;} 802 803 /* Goto a particular history number obtained from argument. 804 * If no argument is given history 1 is probably not what you 805 * want so we'll simply go to the oldest one. 806 */ 807 static int 808 x_goto_hist(int c) 809 { 810 if (x_arg_defaulted) 811 x_load_hist(history); 812 else 813 x_load_hist(histptr + x_arg - source->line); 814 return KSTD; 815 } 816 817 static void 818 x_load_hist(char **hp) 819 { 820 int oldsize; 821 822 if (hp < history || hp > histptr) { 823 x_e_putc(BEL); 824 return; 825 } 826 x_histp = hp; 827 oldsize = x_size_str(xbuf); 828 strlcpy(xbuf, *hp, xend - xbuf); 829 xbp = xbuf; 830 xep = xcp = xbuf + strlen(xbuf); 831 xlp_valid = false; 832 if (xep <= x_lastcp()) 833 x_redraw(oldsize); 834 x_goto(xep); 835 } 836 837 static int 838 x_nl_next_com(int c) 839 { 840 x_nextcmd = source->line - (histptr - x_histp) + 1; 841 return (x_newline(c)); 842 } 843 844 static int 845 x_eot_del(int c) 846 { 847 if (xep == xbuf && x_arg_defaulted) 848 return (x_end_of_text(c)); 849 else 850 return (x_del_char(c)); 851 } 852 853 static void * 854 kb_find_hist_func(char c) 855 { 856 struct kb_entry *k; 857 char line[LINE + 1]; 858 859 line[0] = c; 860 line[1] = '\0'; 861 TAILQ_FOREACH(k, &kblist, entry) 862 if (!strcmp(k->seq, line)) 863 return (k->ftab->xf_func); 864 865 return (x_insert); 866 } 867 868 /* reverse incremental history search */ 869 static int 870 x_search_hist(int c) 871 { 872 int offset = -1; /* offset of match in xbuf, else -1 */ 873 char pat [256+1]; /* pattern buffer */ 874 char *p = pat; 875 int (*f)(int); 876 877 *p = '\0'; 878 while (1) { 879 if (offset < 0) { 880 x_e_puts("\nI-search: "); 881 x_e_puts(pat); 882 } 883 x_flush(); 884 if ((c = x_e_getc()) < 0) 885 return KSTD; 886 f = kb_find_hist_func(c); 887 if (c == CTRL('[')) 888 break; 889 else if (f == x_search_hist) 890 offset = x_search(pat, 0, offset); 891 else if (f == x_del_back) { 892 if (p == pat) { 893 offset = -1; 894 break; 895 } 896 if (p > pat) 897 *--p = '\0'; 898 if (p == pat) 899 offset = -1; 900 else 901 offset = x_search(pat, 1, offset); 902 continue; 903 } else if (f == x_insert) { 904 /* add char to pattern */ 905 /* overflow check... */ 906 if (p >= &pat[sizeof(pat) - 1]) { 907 x_e_putc(BEL); 908 continue; 909 } 910 *p++ = c, *p = '\0'; 911 if (offset >= 0) { 912 /* already have partial match */ 913 offset = x_match(xbuf, pat); 914 if (offset >= 0) { 915 x_goto(xbuf + offset + (p - pat) - 916 (*pat == '^')); 917 continue; 918 } 919 } 920 offset = x_search(pat, 0, offset); 921 } else { /* other command */ 922 x_e_ungetc(c); 923 break; 924 } 925 } 926 if (offset < 0) 927 x_redraw(-1); 928 return KSTD; 929 } 930 931 /* search backward from current line */ 932 static int 933 x_search(char *pat, int sameline, int offset) 934 { 935 char **hp; 936 int i; 937 938 for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) { 939 i = x_match(*hp, pat); 940 if (i >= 0) { 941 if (offset < 0) 942 x_e_putc('\n'); 943 x_load_hist(hp); 944 x_goto(xbuf + i + strlen(pat) - (*pat == '^')); 945 return i; 946 } 947 } 948 x_e_putc(BEL); 949 x_histp = histptr; 950 return -1; 951 } 952 953 /* return position of first match of pattern in string, else -1 */ 954 static int 955 x_match(char *str, char *pat) 956 { 957 if (*pat == '^') { 958 return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1; 959 } else { 960 char *q = strstr(str, pat); 961 return (q == NULL) ? -1 : q - str; 962 } 963 } 964 965 static int 966 x_del_line(int c) 967 { 968 int i, j; 969 970 *xep = 0; 971 i = xep - xbuf; 972 j = x_size_str(xbuf); 973 xcp = xbuf; 974 x_push(i); 975 xlp = xbp = xep = xbuf; 976 xlp_valid = true; 977 *xcp = 0; 978 xmp = NULL; 979 x_redraw(j); 980 return KSTD; 981 } 982 983 static int 984 x_mv_end(int c) 985 { 986 x_goto(xep); 987 return KSTD; 988 } 989 990 static int 991 x_mv_begin(int c) 992 { 993 x_goto(xbuf); 994 return KSTD; 995 } 996 997 static int 998 x_draw_line(int c) 999 { 1000 x_redraw(-1); 1001 return KSTD; 1002 1003 } 1004 1005 /* Redraw (part of) the line. If limit is < 0, the everything is redrawn 1006 * on a NEW line, otherwise limit is the screen column up to which needs 1007 * redrawing. 1008 */ 1009 static void 1010 x_redraw(int limit) 1011 { 1012 int i, j, truncate = 0; 1013 char *cp; 1014 1015 x_adj_ok = 0; 1016 if (limit == -1) 1017 x_e_putc('\n'); 1018 else 1019 x_e_putc('\r'); 1020 x_flush(); 1021 if (xbp == xbuf) { 1022 x_col = promptlen(prompt, (const char **) 0); 1023 if (x_col > xx_cols) 1024 truncate = (x_col / xx_cols) * xx_cols; 1025 if (prompt_redraw) 1026 pprompt(prompt + prompt_skip, truncate); 1027 } 1028 if (x_col > xx_cols) 1029 x_col = x_col - (x_col / xx_cols) * xx_cols; 1030 x_displen = xx_cols - 2 - x_col; 1031 if (x_displen < 1) { 1032 x_col = 0; 1033 x_displen = xx_cols - 2; 1034 } 1035 xlp_valid = false; 1036 cp = x_lastcp(); 1037 x_zots(xbp); 1038 if (xbp != xbuf || xep > xlp) 1039 limit = xx_cols; 1040 if (limit >= 0) { 1041 if (xep > xlp) 1042 i = 0; /* we fill the line */ 1043 else 1044 i = limit - (xlp - xbp); 1045 1046 for (j = 0; j < i && x_col < (xx_cols - 2); j++) 1047 x_e_putc(' '); 1048 i = ' '; 1049 if (xep > xlp) { /* more off screen */ 1050 if (xbp > xbuf) 1051 i = '*'; 1052 else 1053 i = '>'; 1054 } else if (xbp > xbuf) 1055 i = '<'; 1056 x_e_putc(i); 1057 j++; 1058 while (j--) 1059 x_e_putc('\b'); 1060 } 1061 for (cp = xlp; cp > xcp; ) 1062 x_bs(*--cp); 1063 x_adj_ok = 1; 1064 D__(x_flush();) 1065 return; 1066 } 1067 1068 static int 1069 x_transpose(int c) 1070 { 1071 char tmp; 1072 1073 /* What transpose is meant to do seems to be up for debate. This 1074 * is a general summary of the options; the text is abcd with the 1075 * upper case character or underscore indicating the cursor position: 1076 * Who Before After Before After 1077 * at&t ksh in emacs mode: abCd abdC abcd_ (bell) 1078 * at&t ksh in gmacs mode: abCd baCd abcd_ abdc_ 1079 * gnu emacs: abCd acbD abcd_ abdc_ 1080 * Pdksh currently goes with GNU behavior since I believe this is the 1081 * most common version of emacs, unless in gmacs mode, in which case 1082 * it does the at&t ksh gmacs mode. 1083 * This should really be broken up into 3 functions so users can bind 1084 * to the one they want. 1085 */ 1086 if (xcp == xbuf) { 1087 x_e_putc(BEL); 1088 return KSTD; 1089 } else if (xcp == xep || Flag(FGMACS)) { 1090 if (xcp - xbuf == 1) { 1091 x_e_putc(BEL); 1092 return KSTD; 1093 } 1094 /* Gosling/Unipress emacs style: Swap two characters before the 1095 * cursor, do not change cursor position 1096 */ 1097 x_bs(xcp[-1]); 1098 x_bs(xcp[-2]); 1099 x_zotc(xcp[-1]); 1100 x_zotc(xcp[-2]); 1101 tmp = xcp[-1]; 1102 xcp[-1] = xcp[-2]; 1103 xcp[-2] = tmp; 1104 } else { 1105 /* GNU emacs style: Swap the characters before and under the 1106 * cursor, move cursor position along one. 1107 */ 1108 x_bs(xcp[-1]); 1109 x_zotc(xcp[0]); 1110 x_zotc(xcp[-1]); 1111 tmp = xcp[-1]; 1112 xcp[-1] = xcp[0]; 1113 xcp[0] = tmp; 1114 x_bs(xcp[0]); 1115 x_goto(xcp + 1); 1116 } 1117 return KSTD; 1118 } 1119 1120 static int 1121 x_literal(int c) 1122 { 1123 x_literal_set = 1; 1124 return KSTD; 1125 } 1126 1127 static int 1128 x_kill(int c) 1129 { 1130 int col = xcp - xbuf; 1131 int lastcol = xep - xbuf; 1132 int ndel; 1133 1134 if (x_arg_defaulted) 1135 x_arg = lastcol; 1136 else if (x_arg > lastcol) 1137 x_arg = lastcol; 1138 ndel = x_arg - col; 1139 if (ndel < 0) { 1140 x_goto(xbuf + x_arg); 1141 ndel = -ndel; 1142 } 1143 x_delete(ndel, true); 1144 return KSTD; 1145 } 1146 1147 static void 1148 x_push(int nchars) 1149 { 1150 char *cp = str_nsave(xcp, nchars, AEDIT); 1151 if (killstack[killsp]) 1152 afree((void *)killstack[killsp], AEDIT); 1153 killstack[killsp] = cp; 1154 killsp = (killsp + 1) % KILLSIZE; 1155 } 1156 1157 static int 1158 x_yank(int c) 1159 { 1160 if (killsp == 0) 1161 killtp = KILLSIZE; 1162 else 1163 killtp = killsp; 1164 killtp --; 1165 if (killstack[killtp] == 0) { 1166 x_e_puts("\nnothing to yank"); 1167 x_redraw(-1); 1168 return KSTD; 1169 } 1170 xmp = xcp; 1171 x_ins(killstack[killtp]); 1172 return KSTD; 1173 } 1174 1175 static int 1176 x_meta_yank(int c) 1177 { 1178 int len; 1179 if ((x_last_command != x_yank && x_last_command != x_meta_yank) || 1180 killstack[killtp] == 0) { 1181 killtp = killsp; 1182 x_e_puts("\nyank something first"); 1183 x_redraw(-1); 1184 return KSTD; 1185 } 1186 len = strlen(killstack[killtp]); 1187 x_goto(xcp - len); 1188 x_delete(len, false); 1189 do { 1190 if (killtp == 0) 1191 killtp = KILLSIZE - 1; 1192 else 1193 killtp--; 1194 } while (killstack[killtp] == 0); 1195 x_ins(killstack[killtp]); 1196 return KSTD; 1197 } 1198 1199 static int 1200 x_abort(int c) 1201 { 1202 /* x_zotc(c); */ 1203 xlp = xep = xcp = xbp = xbuf; 1204 xlp_valid = true; 1205 *xcp = 0; 1206 return KINTR; 1207 } 1208 1209 static int 1210 x_error(int c) 1211 { 1212 x_e_putc(BEL); 1213 return KSTD; 1214 } 1215 1216 static int 1217 x_stuffreset(int c) 1218 { 1219 #ifdef TIOCSTI 1220 (void)x_stuff(c); 1221 return KINTR; 1222 #else 1223 x_zotc(c); 1224 xlp = xcp = xep = xbp = xbuf; 1225 xlp_valid = true; 1226 *xcp = 0; 1227 x_redraw(-1); 1228 return KSTD; 1229 #endif 1230 } 1231 1232 static int 1233 x_stuff(int c) 1234 { 1235 #ifdef TIOCSTI 1236 char ch = c; 1237 bool savmode = x_mode(false); 1238 1239 (void)ioctl(TTY, TIOCSTI, &ch); 1240 (void)x_mode(savmode); 1241 x_redraw(-1); 1242 #endif 1243 return KSTD; 1244 } 1245 1246 static char * 1247 kb_encode(const char *s) 1248 { 1249 static char l[LINE + 1]; 1250 int at = 0; 1251 1252 l[at] = '\0'; 1253 while (*s) { 1254 if (*s == '^') { 1255 s++; 1256 if (*s >= '?') 1257 l[at++] = CTRL(*s); 1258 else { 1259 l[at++] = '^'; 1260 s--; 1261 } 1262 } else 1263 l[at++] = *s; 1264 l[at] = '\0'; 1265 s++; 1266 } 1267 return (l); 1268 } 1269 1270 static char * 1271 kb_decode(const char *s) 1272 { 1273 static char l[LINE + 1]; 1274 int i, at = 0; 1275 1276 l[0] = '\0'; 1277 for (i = 0; i < strlen(s); i++) { 1278 if (iscntrl(s[i])) { 1279 l[at++] = '^'; 1280 l[at++] = UNCTRL(s[i]); 1281 } else 1282 l[at++] = s[i]; 1283 l[at] = '\0'; 1284 } 1285 1286 return (l); 1287 } 1288 1289 static int 1290 kb_match(char *s) 1291 { 1292 int len = strlen(s); 1293 struct kb_entry *k; 1294 1295 TAILQ_FOREACH(k, &kblist, entry) { 1296 if (len > k->len) 1297 continue; 1298 1299 if (!bcmp(k->seq, s, len)) 1300 return (1); 1301 } 1302 1303 return (0); 1304 } 1305 1306 static void 1307 kb_del(struct kb_entry *k) 1308 { 1309 TAILQ_REMOVE(&kblist, k, entry); 1310 if (k->args) 1311 free(k->args); 1312 afree(k, AEDIT); 1313 } 1314 1315 static struct kb_entry * 1316 kb_add_string(void *func, void *args, char *str) 1317 { 1318 int i, count; 1319 struct kb_entry *k; 1320 struct x_ftab *xf = NULL; 1321 1322 for (i = 0; i < NELEM(x_ftab); i++) 1323 if (x_ftab[i].xf_func == func) { 1324 xf = (struct x_ftab *)&x_ftab[i]; 1325 break; 1326 } 1327 if (xf == NULL) 1328 return (NULL); 1329 1330 if (kb_match(str)) { 1331 if (x_bind_quiet == 0) 1332 bi_errorf("duplicate binding for %s", kb_decode(str)); 1333 return (NULL); 1334 } 1335 count = strlen(str); 1336 1337 k = alloc(sizeof *k + count + 1, AEDIT); 1338 k->seq = (unsigned char *)(k + 1); 1339 k->len = count; 1340 k->ftab = xf; 1341 k->args = args ? strdup(args) : NULL; 1342 1343 strlcpy(k->seq, str, count + 1); 1344 1345 TAILQ_INSERT_TAIL(&kblist, k, entry); 1346 1347 return (k); 1348 } 1349 1350 static struct kb_entry * 1351 kb_add(void *func, void *args, ...) 1352 { 1353 va_list ap; 1354 int i, count; 1355 char l[LINE + 1]; 1356 1357 va_start(ap, args); 1358 count = 0; 1359 while (va_arg(ap, unsigned int) != 0) 1360 count++; 1361 va_end(ap); 1362 1363 va_start(ap, args); 1364 for (i = 0; i <= count /* <= is correct */; i++) 1365 l[i] = (unsigned char)va_arg(ap, unsigned int); 1366 va_end(ap); 1367 1368 return (kb_add_string(func, args, l)); 1369 } 1370 1371 static void 1372 kb_print(struct kb_entry *k) 1373 { 1374 if (!(k->ftab->xf_flags & XF_NOBIND)) 1375 shprintf("%s = %s\n", 1376 kb_decode(k->seq), k->ftab->xf_name); 1377 else if (k->args) { 1378 shprintf("%s = ", kb_decode(k->seq)); 1379 shprintf("'%s'\n", kb_decode(k->args)); 1380 } 1381 } 1382 1383 int 1384 x_bind(const char *a1, const char *a2, 1385 int macro, /* bind -m */ 1386 int list) /* bind -l */ 1387 { 1388 int i; 1389 struct kb_entry *k, *kb; 1390 char in[LINE + 1]; 1391 1392 if (x_tty == 0) { 1393 bi_errorf("cannot bind, not a tty"); 1394 return (1); 1395 } 1396 1397 if (list) { 1398 /* show all function names */ 1399 for (i = 0; i < NELEM(x_ftab); i++) { 1400 if (x_ftab[i].xf_name == NULL) 1401 continue; 1402 if (x_ftab[i].xf_name && 1403 !(x_ftab[i].xf_flags & XF_NOBIND)) 1404 shprintf("%s\n", x_ftab[i].xf_name); 1405 } 1406 return (0); 1407 } 1408 1409 if (a1 == NULL) { 1410 /* show all bindings */ 1411 TAILQ_FOREACH(k, &kblist, entry) 1412 kb_print(k); 1413 return (0); 1414 } 1415 1416 snprintf(in, sizeof in, "%s", kb_encode(a1)); 1417 if (a2 == NULL) { 1418 /* print binding */ 1419 TAILQ_FOREACH(k, &kblist, entry) 1420 if (!strcmp(k->seq, in)) { 1421 kb_print(k); 1422 return (0); 1423 } 1424 shprintf("%s = %s\n", kb_decode(a1), "auto-insert"); 1425 return (0); 1426 } 1427 1428 if (strlen(a2) == 0) { 1429 /* clear binding */ 1430 TAILQ_FOREACH_SAFE(k, &kblist, entry, kb) 1431 if (!strcmp(k->seq, in)) { 1432 kb_del(k); 1433 break; 1434 } 1435 return (0); 1436 } 1437 1438 /* set binding */ 1439 if (macro) { 1440 /* delete old mapping */ 1441 TAILQ_FOREACH_SAFE(k, &kblist, entry, kb) 1442 if (!strcmp(k->seq, in)) { 1443 kb_del(k); 1444 break; 1445 } 1446 kb_add_string(x_ins_string, kb_encode(a2), in); 1447 return (0); 1448 } 1449 1450 /* set non macro binding */ 1451 for (i = 0; i < NELEM(x_ftab); i++) { 1452 if (x_ftab[i].xf_name == NULL) 1453 continue; 1454 if (!strcmp(x_ftab[i].xf_name, a2)) { 1455 /* delete old mapping */ 1456 TAILQ_FOREACH_SAFE(k, &kblist, entry, kb) 1457 if (!strcmp(k->seq, in)) { 1458 kb_del(k); 1459 break; 1460 } 1461 kb_add_string(x_ftab[i].xf_func, NULL, in); 1462 return (0); 1463 } 1464 } 1465 bi_errorf("%s: no such function", a2); 1466 return (1); 1467 } 1468 1469 void 1470 x_init_emacs(void) 1471 { 1472 char *locale; 1473 1474 x_tty = 1; 1475 ainit(AEDIT); 1476 x_nextcmd = -1; 1477 1478 /* Determine if we can translate meta key or use 8-bit AscII 1479 * XXX - It would be nice if there was a locale attribute to 1480 * determine if the locale is 7-bit or not. 1481 */ 1482 locale = setlocale(LC_CTYPE, NULL); 1483 if (locale == NULL || !strcmp(locale, "C") || !strcmp(locale, "POSIX")) 1484 Flag(FEMACSUSEMETA) = 1; 1485 1486 /* new keybinding stuff */ 1487 TAILQ_INIT(&kblist); 1488 1489 /* man page order */ 1490 kb_add(x_abort, NULL, CTRL('G'), 0); 1491 kb_add(x_mv_back, NULL, CTRL('B'), 0); 1492 kb_add(x_mv_back, NULL, CTRL('X'), CTRL('D'), 0); 1493 kb_add(x_mv_bword, NULL, CTRL('['), 'b', 0); 1494 kb_add(x_beg_hist, NULL, CTRL('['), '<', 0); 1495 kb_add(x_mv_begin, NULL, CTRL('A'), 0); 1496 kb_add(x_fold_capitalize, NULL, CTRL('['), 'C', 0); 1497 kb_add(x_fold_capitalize, NULL, CTRL('['), 'c', 0); 1498 kb_add(x_comment, NULL, CTRL('['), '#', 0); 1499 kb_add(x_complete, NULL, CTRL('['), CTRL('['), 0); 1500 kb_add(x_comp_comm, NULL, CTRL('X'), CTRL('['), 0); 1501 kb_add(x_comp_file, NULL, CTRL('['), CTRL('X'), 0); 1502 kb_add(x_comp_list, NULL, CTRL('I'), 0); 1503 kb_add(x_comp_list, NULL, CTRL('['), '=', 0); 1504 kb_add(x_del_back, NULL, CTRL('?'), 0); 1505 kb_add(x_del_back, NULL, CTRL('H'), 0); 1506 /* x_del_char not assigned by default */ 1507 kb_add(x_del_bword, NULL, CTRL('['), CTRL('?'), 0); 1508 kb_add(x_del_bword, NULL, CTRL('['), CTRL('H'), 0); 1509 kb_add(x_del_bword, NULL, CTRL('['), 'h', 0); 1510 kb_add(x_del_fword, NULL, CTRL('['), 'd', 0); 1511 kb_add(x_next_com, NULL, CTRL('N'), 0); 1512 kb_add(x_next_com, NULL, CTRL('X'), 'B', 0); 1513 kb_add(x_fold_lower, NULL, CTRL('['), 'L', 0); 1514 kb_add(x_fold_lower, NULL, CTRL('['), 'l', 0); 1515 kb_add(x_end_hist, NULL, CTRL('['), '>', 0); 1516 kb_add(x_mv_end, NULL, CTRL('E'), 0); 1517 /* how to handle: eot: ^_, underneath copied from original keybindings */ 1518 kb_add(x_end_of_text, NULL, CTRL('_'), 0); 1519 kb_add(x_eot_del, NULL, CTRL('D'), 0); 1520 /* error */ 1521 kb_add(x_xchg_point_mark, NULL, CTRL('X'), CTRL('X'), 0); 1522 kb_add(x_expand, NULL, CTRL('['), '*', 0); 1523 kb_add(x_mv_forw, NULL, CTRL('F'), 0); 1524 kb_add(x_mv_forw, NULL, CTRL('X'), 'C', 0); 1525 kb_add(x_mv_fword, NULL, CTRL('['), 'f', 0); 1526 kb_add(x_goto_hist, NULL, CTRL('['), 'g', 0); 1527 /* kill-line */ 1528 kb_add(x_del_bword, NULL, CTRL('W'), 0); /* not what man says */ 1529 kb_add(x_kill, NULL, CTRL('K'), 0); 1530 kb_add(x_enumerate, NULL, CTRL('['), '?', 0); 1531 kb_add(x_list_comm, NULL, CTRL('X'), '?', 0); 1532 kb_add(x_list_file, NULL, CTRL('X'), CTRL('Y'), 0); 1533 kb_add(x_newline, NULL, CTRL('J'), 0); 1534 kb_add(x_newline, NULL, CTRL('M'), 0); 1535 kb_add(x_nl_next_com, NULL, CTRL('O'), 0); 1536 /* no-op */ 1537 kb_add(x_prev_histword, NULL, CTRL('['), '.', 0); 1538 kb_add(x_prev_histword, NULL, CTRL('['), '_', 0); 1539 /* how to handle: quote: ^^ */ 1540 kb_add(x_draw_line, NULL, CTRL('L'), 0); 1541 kb_add(x_search_char_back, NULL, CTRL('['), CTRL(']'), 0); 1542 kb_add(x_search_char_forw, NULL, CTRL(']'), 0); 1543 kb_add(x_search_hist, NULL, CTRL('R'), 0); 1544 kb_add(x_set_mark, NULL, CTRL('['), ' ', 0); 1545 #if defined(TIOCSTI) 1546 kb_add(x_stuff, NULL, CTRL('T'), 0); 1547 /* stuff-reset */ 1548 #else 1549 kb_add(x_transpose, NULL, CTRL('T'), 0); 1550 #endif 1551 kb_add(x_prev_com, NULL, CTRL('P'), 0); 1552 kb_add(x_prev_com, NULL, CTRL('X'), 'A', 0); 1553 kb_add(x_fold_upper, NULL, CTRL('['), 'U', 0); 1554 kb_add(x_fold_upper, NULL, CTRL('['), 'u', 0); 1555 kb_add(x_literal, NULL, CTRL('V'), 0); 1556 kb_add(x_literal, NULL, CTRL('^'), 0); 1557 kb_add(x_yank, NULL, CTRL('Y'), 0); 1558 kb_add(x_meta_yank, NULL, CTRL('['), 'y', 0); 1559 /* man page ends here */ 1560 1561 /* arrow keys */ 1562 kb_add(x_prev_com, NULL, CTRL('['), '[', 'A', 0); /* up */ 1563 kb_add(x_next_com, NULL, CTRL('['), '[', 'B', 0); /* down */ 1564 kb_add(x_mv_forw, NULL, CTRL('['), '[', 'C', 0); /* right */ 1565 kb_add(x_mv_back, NULL, CTRL('['), '[', 'D', 0); /* left */ 1566 kb_add(x_prev_com, NULL, CTRL('['), 'O', 'A', 0); /* up */ 1567 kb_add(x_next_com, NULL, CTRL('['), 'O', 'B', 0); /* down */ 1568 kb_add(x_mv_forw, NULL, CTRL('['), 'O', 'C', 0); /* right */ 1569 kb_add(x_mv_back, NULL, CTRL('['), 'O', 'D', 0); /* left */ 1570 1571 /* more navigation keys */ 1572 kb_add(x_mv_begin, NULL, CTRL('['), '[', 'H', 0); /* home */ 1573 kb_add(x_mv_end, NULL, CTRL('['), '[', 'F', 0); /* end */ 1574 kb_add(x_mv_begin, NULL, CTRL('['), 'O', 'H', 0); /* home */ 1575 kb_add(x_mv_end, NULL, CTRL('['), 'O', 'F', 0); /* end */ 1576 1577 /* can't be bound */ 1578 kb_add(x_set_arg, NULL, CTRL('['), '0', 0); 1579 kb_add(x_set_arg, NULL, CTRL('['), '1', 0); 1580 kb_add(x_set_arg, NULL, CTRL('['), '2', 0); 1581 kb_add(x_set_arg, NULL, CTRL('['), '3', 0); 1582 kb_add(x_set_arg, NULL, CTRL('['), '4', 0); 1583 kb_add(x_set_arg, NULL, CTRL('['), '5', 0); 1584 kb_add(x_set_arg, NULL, CTRL('['), '6', 0); 1585 kb_add(x_set_arg, NULL, CTRL('['), '7', 0); 1586 kb_add(x_set_arg, NULL, CTRL('['), '8', 0); 1587 kb_add(x_set_arg, NULL, CTRL('['), '9', 0); 1588 1589 /* ctrl arrow keys */ 1590 kb_add(x_mv_end, NULL, CTRL('['), '[', '1', ';', '5', 'A', 0); /* ctrl up */ 1591 kb_add(x_mv_begin, NULL, CTRL('['), '[', '1', ';', '5', 'B', 0); /* ctrl down */ 1592 kb_add(x_mv_fword, NULL, CTRL('['), '[', '1', ';', '5', 'C', 0); /* ctrl right */ 1593 kb_add(x_mv_bword, NULL, CTRL('['), '[', '1', ';', '5', 'D', 0); /* ctrl left */ 1594 } 1595 1596 void 1597 x_emacs_keys(X_chars *ec) 1598 { 1599 x_bind_quiet = 1; 1600 if (ec->erase >= 0) { 1601 kb_add(x_del_back, NULL, ec->erase, 0); 1602 kb_add(x_del_bword, NULL, CTRL('['), ec->erase, 0); 1603 } 1604 if (ec->kill >= 0) 1605 kb_add(x_del_line, NULL, ec->kill, 0); 1606 if (ec->werase >= 0) 1607 kb_add(x_del_bword, NULL, ec->werase, 0); 1608 if (ec->intr >= 0) 1609 kb_add(x_abort, NULL, ec->intr, 0); 1610 if (ec->quit >= 0) 1611 kb_add(x_noop, NULL, ec->quit, 0); 1612 x_bind_quiet = 0; 1613 } 1614 1615 static int 1616 x_set_mark(int c) 1617 { 1618 xmp = xcp; 1619 return KSTD; 1620 } 1621 1622 static int 1623 x_kill_region(int c) 1624 { 1625 int rsize; 1626 char *xr; 1627 1628 if (xmp == NULL) { 1629 x_e_putc(BEL); 1630 return KSTD; 1631 } 1632 if (xmp > xcp) { 1633 rsize = xmp - xcp; 1634 xr = xcp; 1635 } else { 1636 rsize = xcp - xmp; 1637 xr = xmp; 1638 } 1639 x_goto(xr); 1640 x_delete(rsize, true); 1641 xmp = xr; 1642 return KSTD; 1643 } 1644 1645 static int 1646 x_xchg_point_mark(int c) 1647 { 1648 char *tmp; 1649 1650 if (xmp == NULL) { 1651 x_e_putc(BEL); 1652 return KSTD; 1653 } 1654 tmp = xmp; 1655 xmp = xcp; 1656 x_goto( tmp ); 1657 return KSTD; 1658 } 1659 1660 static int 1661 x_version(int c) 1662 { 1663 char *o_xbuf = xbuf, *o_xend = xend; 1664 char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp; 1665 int lim = x_lastcp() - xbp; 1666 1667 xbuf = xbp = xcp = (char *) ksh_version + 4; 1668 xend = xep = (char *) ksh_version + 4 + strlen(ksh_version + 4); 1669 x_redraw(lim); 1670 x_flush(); 1671 1672 c = x_e_getc(); 1673 xbuf = o_xbuf; 1674 xend = o_xend; 1675 xbp = o_xbp; 1676 xep = o_xep; 1677 xcp = o_xcp; 1678 x_redraw(strlen(ksh_version)); 1679 1680 if (c < 0) 1681 return KSTD; 1682 /* This is what at&t ksh seems to do... Very bizarre */ 1683 if (c != ' ') 1684 x_e_ungetc(c); 1685 1686 return KSTD; 1687 } 1688 1689 static int 1690 x_noop(int c) 1691 { 1692 return KSTD; 1693 } 1694 1695 /* 1696 * File/command name completion routines 1697 */ 1698 1699 static int 1700 x_comp_comm(int c) 1701 { 1702 do_complete(XCF_COMMAND, CT_COMPLETE); 1703 return KSTD; 1704 } 1705 static int 1706 x_list_comm(int c) 1707 { 1708 do_complete(XCF_COMMAND, CT_LIST); 1709 return KSTD; 1710 } 1711 static int 1712 x_complete(int c) 1713 { 1714 do_complete(XCF_COMMAND_FILE, CT_COMPLETE); 1715 return KSTD; 1716 } 1717 static int 1718 x_enumerate(int c) 1719 { 1720 do_complete(XCF_COMMAND_FILE, CT_LIST); 1721 return KSTD; 1722 } 1723 static int 1724 x_comp_file(int c) 1725 { 1726 do_complete(XCF_FILE, CT_COMPLETE); 1727 return KSTD; 1728 } 1729 static int 1730 x_list_file(int c) 1731 { 1732 do_complete(XCF_FILE, CT_LIST); 1733 return KSTD; 1734 } 1735 static int 1736 x_comp_list(int c) 1737 { 1738 do_complete(XCF_COMMAND_FILE, CT_COMPLIST); 1739 return KSTD; 1740 } 1741 static int 1742 x_expand(int c) 1743 { 1744 char **words; 1745 int nwords = 0; 1746 int start, end; 1747 int is_command; 1748 int i; 1749 1750 nwords = x_cf_glob(XCF_FILE, xbuf, xep - xbuf, xcp - xbuf, 1751 &start, &end, &words, &is_command); 1752 1753 if (nwords == 0) { 1754 x_e_putc(BEL); 1755 return KSTD; 1756 } 1757 1758 x_goto(xbuf + start); 1759 x_delete(end - start, false); 1760 for (i = 0; i < nwords;) { 1761 if (x_escape(words[i], strlen(words[i]), x_emacs_putbuf) < 0 || 1762 (++i < nwords && x_ins(space) < 0)) { 1763 x_e_putc(BEL); 1764 return KSTD; 1765 } 1766 } 1767 x_adjust(); 1768 1769 return KSTD; 1770 } 1771 1772 /* type == 0 for list, 1 for complete and 2 for complete-list */ 1773 static void 1774 do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */ 1775 Comp_type type) 1776 { 1777 char **words; 1778 int nwords; 1779 int start, end, nlen, olen; 1780 int is_command; 1781 int completed = 0; 1782 1783 nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf, 1784 &start, &end, &words, &is_command); 1785 /* no match */ 1786 if (nwords == 0) { 1787 x_e_putc(BEL); 1788 return; 1789 } 1790 1791 if (type == CT_LIST) { 1792 x_print_expansions(nwords, words, is_command); 1793 x_redraw(0); 1794 x_free_words(nwords, words); 1795 return; 1796 } 1797 1798 olen = end - start; 1799 nlen = x_longest_prefix(nwords, words); 1800 /* complete */ 1801 if (nwords == 1 || nlen > olen) { 1802 x_goto(xbuf + start); 1803 x_delete(olen, false); 1804 x_escape(words[0], nlen, x_emacs_putbuf); 1805 x_adjust(); 1806 completed = 1; 1807 } 1808 /* add space if single non-dir match */ 1809 if (nwords == 1 && words[0][nlen - 1] != '/') { 1810 x_ins(space); 1811 completed = 1; 1812 } 1813 1814 if (type == CT_COMPLIST && !completed) { 1815 x_print_expansions(nwords, words, is_command); 1816 completed = 1; 1817 } 1818 1819 if (completed) 1820 x_redraw(0); 1821 1822 x_free_words(nwords, words); 1823 } 1824 1825 /* NAME: 1826 * x_adjust - redraw the line adjusting starting point etc. 1827 * 1828 * DESCRIPTION: 1829 * This function is called when we have exceeded the bounds 1830 * of the edit window. It increments x_adj_done so that 1831 * functions like x_ins and x_delete know that we have been 1832 * called and can skip the x_bs() stuff which has already 1833 * been done by x_redraw. 1834 * 1835 * RETURN VALUE: 1836 * None 1837 */ 1838 1839 static void 1840 x_adjust(void) 1841 { 1842 x_adj_done++; /* flag the fact that we were called. */ 1843 /* 1844 * we had a problem if the prompt length > xx_cols / 2 1845 */ 1846 if ((xbp = xcp - (x_displen / 2)) < xbuf) 1847 xbp = xbuf; 1848 xlp_valid = false; 1849 x_redraw(xx_cols); 1850 x_flush(); 1851 } 1852 1853 static int unget_char = -1; 1854 1855 static void 1856 x_e_ungetc(int c) 1857 { 1858 unget_char = c; 1859 } 1860 1861 static int 1862 x_e_getc(void) 1863 { 1864 int c; 1865 1866 if (unget_char >= 0) { 1867 c = unget_char; 1868 unget_char = -1; 1869 } else if (macro_args) { 1870 c = *macro_args++; 1871 if (!c) { 1872 macro_args = NULL; 1873 c = x_getc(); 1874 } 1875 } else 1876 c = x_getc(); 1877 1878 return c; 1879 } 1880 1881 static void 1882 x_e_putc(int c) 1883 { 1884 if (c == '\r' || c == '\n') 1885 x_col = 0; 1886 if (x_col < xx_cols) { 1887 x_putc(c); 1888 switch (c) { 1889 case BEL: 1890 break; 1891 case '\r': 1892 case '\n': 1893 break; 1894 case '\b': 1895 x_col--; 1896 break; 1897 default: 1898 x_col++; 1899 break; 1900 } 1901 } 1902 if (x_adj_ok && (x_col < 0 || x_col >= (xx_cols - 2))) 1903 x_adjust(); 1904 } 1905 1906 #ifdef DEBUG 1907 static int 1908 x_debug_info(int c) 1909 { 1910 x_flush(); 1911 shellf("\nksh debug:\n"); 1912 shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n", 1913 x_col, xx_cols, x_displen); 1914 shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp, (long) xep); 1915 shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp, (long) xbuf); 1916 shellf("\txlp == 0x%lx\n", (long) xlp); 1917 shellf("\txlp == 0x%lx\n", (long) x_lastcp()); 1918 shellf(newline); 1919 x_redraw(-1); 1920 return 0; 1921 } 1922 #endif 1923 1924 static void 1925 x_e_puts(const char *s) 1926 { 1927 int adj = x_adj_done; 1928 1929 while (*s && adj == x_adj_done) 1930 x_e_putc(*s++); 1931 } 1932 1933 /* NAME: 1934 * x_set_arg - set an arg value for next function 1935 * 1936 * DESCRIPTION: 1937 * This is a simple implementation of M-[0-9]. 1938 * 1939 * RETURN VALUE: 1940 * KSTD 1941 */ 1942 1943 static int 1944 x_set_arg(int c) 1945 { 1946 int n = 0; 1947 int first = 1; 1948 1949 for (; c >= 0 && isdigit(c); c = x_e_getc(), first = 0) 1950 n = n * 10 + (c - '0'); 1951 if (c < 0 || first) { 1952 x_e_putc(BEL); 1953 x_arg = 1; 1954 x_arg_defaulted = 1; 1955 } else { 1956 x_e_ungetc(c); 1957 x_arg = n; 1958 x_arg_defaulted = 0; 1959 x_arg_set = 1; 1960 } 1961 return KSTD; 1962 } 1963 1964 1965 /* Comment or uncomment the current line. */ 1966 static int 1967 x_comment(int c) 1968 { 1969 int oldsize = x_size_str(xbuf); 1970 int len = xep - xbuf; 1971 int ret = x_do_comment(xbuf, xend - xbuf, &len); 1972 1973 if (ret < 0) 1974 x_e_putc(BEL); 1975 else { 1976 xep = xbuf + len; 1977 *xep = '\0'; 1978 xcp = xbp = xbuf; 1979 x_redraw(oldsize); 1980 if (ret > 0) 1981 return x_newline('\n'); 1982 } 1983 return KSTD; 1984 } 1985 1986 1987 /* NAME: 1988 * x_prev_histword - recover word from prev command 1989 * 1990 * DESCRIPTION: 1991 * This function recovers the last word from the previous 1992 * command and inserts it into the current edit line. If a 1993 * numeric arg is supplied then the n'th word from the 1994 * start of the previous command is used. 1995 * 1996 * Bound to M-. 1997 * 1998 * RETURN VALUE: 1999 * KSTD 2000 */ 2001 2002 static int 2003 x_prev_histword(int c) 2004 { 2005 char *rcp; 2006 char *cp; 2007 2008 cp = *histptr; 2009 if (!cp) 2010 x_e_putc(BEL); 2011 else if (x_arg_defaulted) { 2012 rcp = &cp[strlen(cp) - 1]; 2013 /* 2014 * ignore white-space after the last word 2015 */ 2016 while (rcp > cp && is_cfs(*rcp)) 2017 rcp--; 2018 while (rcp > cp && !is_cfs(*rcp)) 2019 rcp--; 2020 if (is_cfs(*rcp)) 2021 rcp++; 2022 x_ins(rcp); 2023 } else { 2024 int c; 2025 2026 rcp = cp; 2027 /* 2028 * ignore white-space at start of line 2029 */ 2030 while (*rcp && is_cfs(*rcp)) 2031 rcp++; 2032 while (x_arg-- > 1) { 2033 while (*rcp && !is_cfs(*rcp)) 2034 rcp++; 2035 while (*rcp && is_cfs(*rcp)) 2036 rcp++; 2037 } 2038 cp = rcp; 2039 while (*rcp && !is_cfs(*rcp)) 2040 rcp++; 2041 c = *rcp; 2042 *rcp = '\0'; 2043 x_ins(cp); 2044 *rcp = c; 2045 } 2046 return KSTD; 2047 } 2048 2049 /* Uppercase N(1) words */ 2050 static int 2051 x_fold_upper(int c) 2052 { 2053 return x_fold_case('U'); 2054 } 2055 2056 /* Lowercase N(1) words */ 2057 static int 2058 x_fold_lower(int c) 2059 { 2060 return x_fold_case('L'); 2061 } 2062 2063 /* Lowercase N(1) words */ 2064 static int 2065 x_fold_capitalize(int c) 2066 { 2067 return x_fold_case('C'); 2068 } 2069 2070 /* NAME: 2071 * x_fold_case - convert word to UPPER/lower/Capital case 2072 * 2073 * DESCRIPTION: 2074 * This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c 2075 * to UPPER case, lower case or Capitalize words. 2076 * 2077 * RETURN VALUE: 2078 * None 2079 */ 2080 2081 static int 2082 x_fold_case(int c) 2083 { 2084 char *cp = xcp; 2085 2086 if (cp == xep) { 2087 x_e_putc(BEL); 2088 return KSTD; 2089 } 2090 while (x_arg--) { 2091 /* 2092 * first skip over any white-space 2093 */ 2094 while (cp != xep && is_mfs(*cp)) 2095 cp++; 2096 /* 2097 * do the first char on its own since it may be 2098 * a different action than for the rest. 2099 */ 2100 if (cp != xep) { 2101 if (c == 'L') { /* lowercase */ 2102 if (isupper((unsigned char)*cp)) 2103 *cp = tolower((unsigned char)*cp); 2104 } else { /* uppercase, capitalize */ 2105 if (islower((unsigned char)*cp)) 2106 *cp = toupper((unsigned char)*cp); 2107 } 2108 cp++; 2109 } 2110 /* 2111 * now for the rest of the word 2112 */ 2113 while (cp != xep && !is_mfs(*cp)) { 2114 if (c == 'U') { /* uppercase */ 2115 if (islower((unsigned char)*cp)) 2116 *cp = toupper((unsigned char)*cp); 2117 } else { /* lowercase, capitalize */ 2118 if (isupper((unsigned char)*cp)) 2119 *cp = tolower((unsigned char)*cp); 2120 } 2121 cp++; 2122 } 2123 } 2124 x_goto(cp); 2125 return KSTD; 2126 } 2127 2128 /* NAME: 2129 * x_lastcp - last visible char 2130 * 2131 * SYNOPSIS: 2132 * x_lastcp() 2133 * 2134 * DESCRIPTION: 2135 * This function returns a pointer to that char in the 2136 * edit buffer that will be the last displayed on the 2137 * screen. The sequence: 2138 * 2139 * for (cp = x_lastcp(); cp > xcp; cp) 2140 * x_bs(*--cp); 2141 * 2142 * Will position the cursor correctly on the screen. 2143 * 2144 * RETURN VALUE: 2145 * cp or NULL 2146 */ 2147 2148 static char * 2149 x_lastcp(void) 2150 { 2151 char *rcp; 2152 int i; 2153 2154 if (!xlp_valid) { 2155 for (i = 0, rcp = xbp; rcp < xep && i < x_displen; rcp++) 2156 i += x_size((unsigned char)*rcp); 2157 xlp = rcp; 2158 } 2159 xlp_valid = true; 2160 return (xlp); 2161 } 2162 2163 #endif /* EDIT */ 2164