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