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