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