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