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