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