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