|
|
1.1 ! root 1: /* ! 2: * EDIT.C -- Emacs-like command line editing and history ! 3: * ! 4: * created by Ron Natalie at BRL ! 5: * modified by Doug Kingston, Doug Gwyn, and Lou Salkind ! 6: * adapted to PD ksh by Eric Gisin ! 7: */ ! 8: ! 9: #if EDIT ! 10: ! 11: static char *RCSid = "$Header: /newbits/usr/bin/korn/RCS/edit.c,v 1.2 91/08/01 12:39:10 bin Exp Locker: bin $"; ! 12: ! 13: #include <stddef.h> ! 14: #include <stdlib.h> ! 15: #include <string.h> ! 16: #include <stdio.h> ! 17: #include <unistd.h> ! 18: #include <signal.h> ! 19: #if !COHERENT ! 20: #include <sys/types.h> ! 21: #endif ! 22: #include <sys/stat.h> ! 23: #include "dirent.h" ! 24: #include <sys/fcntl.h> ! 25: #include <ctype.h> ! 26: #include <errno.h> ! 27: #include <setjmp.h> ! 28: #include "sh.h" ! 29: #include "lex.h" ! 30: #include "tree.h" /* DOTILDE */ ! 31: #include "tty.h" ! 32: #include "table.h" ! 33: #include "expand.h" ! 34: ! 35: #if COHERENT ! 36: struct dirent *readdir(); /* missing from headers */ ! 37: DIR *opendir(); ! 38: #endif ! 39: ! 40: Area aedit; ! 41: #define AEDIT &aedit /* area for kill ring and macro defns */ ! 42: ! 43: #undef CTRL /* _BSD brain damage */ ! 44: #define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */ ! 45: #define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */ ! 46: ! 47: #if ! defined S_ISDIR ! 48: #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) ! 49: #endif ! 50: ! 51: #if ! defined S_ISREG ! 52: #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) ! 53: #endif ! 54: ! 55: #if defined _CRAY2 ! 56: extern unsigned sleep(); ! 57: #endif ! 58: ! 59: /* values returned by keyboard functions */ ! 60: #define KSTD 0 ! 61: #define KPREF 1 /* ^[, ^X */ ! 62: #define KEOL 2 /* ^M, ^J */ ! 63: #define KINTR 3 /* ^G, ^C */ ! 64: ! 65: struct x_ftab { ! 66: int (*xf_func)(); ! 67: char *xf_name; ! 68: char xf_db_tab; ! 69: char xf_db_char; ! 70: short xf_flags; ! 71: }; ! 72: ! 73: #define XF_NINPUT 1 ! 74: #define XF_ALLOC 2 ! 75: #define XF_NOBIND 4 ! 76: ! 77: #define isfs(c) (c == ' ' || c == '\t') ! 78: #define BEL 0x07 ! 79: #define CMASK 0x7F /* 7-bit ASCII character mask */ ! 80: ! 81: static bool_t x_mode = FALSE; ! 82: static int x_prefix1 = CTRL('['), x_prefix2 = CTRL('X'); ! 83: static char **x_histp; /* history position */ ! 84: static char *xbuf; /* beg input buffer */ ! 85: static char *xend; /* end input buffer */ ! 86: static char *xcp; ! 87: static char *xep; ! 88: static int (*x_last_command)(); ! 89: /*static struct x_ftab *x_tab[3][128];*/ ! 90: static struct x_ftab Const *(*x_tab)[128] = NULL; /* key definition */ ! 91: static char *(*x_atab)[128] = NULL; /* macro definitions */ ! 92: #define KILLSIZE 20 ! 93: static char *killstack[KILLSIZE]; ! 94: static int killsp, killtp; ! 95: static int x_curprefix; ! 96: static char *macroptr; ! 97: static int first_time = 1; ! 98: static int x_maxlen; /* to determine column width */ ! 99: static int x_cols = 80; /* todo: $COLUMNS */ ! 100: ! 101: static void x_flush(), x_putc(), x_puts(); ! 102: static void x_goto(), x_bs(), x_delete(), x_ins(), x_mapin(); ! 103: static int x_fword(), x_bword(), x_size(), x_size_str(); ! 104: static void x_zotc(), x_zots(), x_push(), x_redraw(), x_load_hist(); ! 105: static void compl_command(), compl_dec(), compl_file(); ! 106: static int x_insert(), x_ins_string(), x_del_back(); ! 107: static int x_del_char(), x_del_bword(), x_mv_bword(), x_mv_fword(); ! 108: static int x_del_fword(), x_mv_back(), x_mv_forw(), x_search_char(); ! 109: static int x_newline(), x_end_of_text(), x_abort(), x_error(); ! 110: static int x_beg_hist(), x_end_hist(), x_prev_com(), x_next_com(); ! 111: static int x_search_hist(), x_del_line(), x_mv_end(), x_mv_begin(); ! 112: static int x_draw_line(), x_transpose(), x_meta1(), x_meta2(); ! 113: static int x_kill(), x_yank(), x_meta_yank(), x_literal(); ! 114: static int x_stuffreset(), x_stuff(), x_complete(), x_enumerate(); ! 115: #if SILLY ! 116: static int x_game_of_life(); ! 117: #endif ! 118: static int x_comp_file(), x_comp_comm(); ! 119: static int x_list_file(), x_list_comm(); ! 120: static int strmatch(); ! 121: ! 122: static struct x_ftab Const x_ftab[] = { ! 123: {x_insert, "auto-insert", 0, 0, 0 }, ! 124: {x_error, "error", 0, 0, 0 }, ! 125: {x_ins_string, "macro-string", 0, 0, XF_NOBIND|XF_ALLOC}, ! 126: /* Do not move the above! */ ! 127: {x_del_back, "delete-char-backward", 0, CTRL('H'), 0 }, ! 128: {x_del_char, "delete-char-forward", 0, CTRL('D'), 0 }, ! 129: {x_del_bword, "delete-word-backward", 0, CTRL('W'), 0 }, ! 130: {x_mv_bword, "backward-word", 1, 'b', 0 }, ! 131: {x_mv_fword, "forward-word", 1, 'f', 0 }, ! 132: {x_del_fword, "delete-word-forward", 1, 'd', 0 }, ! 133: {x_mv_back, "backward-char", 0, CTRL('B'), 0 }, ! 134: {x_mv_forw, "forward-char", 0, CTRL('F'), 0 }, ! 135: {x_search_char, "search-character", 0, CTRL(']'), 0 }, ! 136: {x_newline, "newline", 0, CTRL('M'), 0 }, ! 137: {x_newline, "newline", 0, CTRL('J'), 0 }, ! 138: {x_end_of_text, "eot", 0, CTRL('_'), 0 }, ! 139: {x_abort, "abort", 0, CTRL('G'), 0 }, ! 140: {x_prev_com, "up-history", 0, CTRL('P'), XF_NINPUT}, ! 141: {x_next_com, "down-history", 0, CTRL('N'), XF_NINPUT}, ! 142: {x_search_hist, "search-history", 0, CTRL('R'), XF_NINPUT}, ! 143: {x_beg_hist, "beginning-of-history", 1, '<', XF_NINPUT}, ! 144: {x_end_hist, "end-of-history", 1, '>', XF_NINPUT}, ! 145: {x_del_line, "kill-line", 0, CTRL('U'), 0 }, ! 146: {x_mv_end, "end-of-line", 0, CTRL('E'), 0 }, ! 147: {x_mv_begin, "beginning-of-line", 0, CTRL('A'), 0 }, ! 148: {x_draw_line, "redraw", 0, CTRL('L'), 0 }, ! 149: {x_meta1, "prefix-1", 0, CTRL('['), 0 }, ! 150: {x_meta2, "prefix-2", 0, CTRL('X'), 0 }, ! 151: {x_kill, "kill-to-eol", 0, CTRL('K'), 0 }, ! 152: {x_yank, "yank", 0, CTRL('Y'), 0 }, ! 153: {x_meta_yank, "yank-pop", 1, 'y', 0 }, ! 154: {x_literal, "quote", 0, CTRL('^'), 0 }, ! 155: {x_stuffreset, "stuff-reset", 0, 0, 0 }, ! 156: #if BRL && defined(TIOCSTI) ! 157: {x_stuff, "stuff", 0, CTRL('T'), 0 }, ! 158: {x_transpose, "transpose-chars", 0, 0, 0 }, ! 159: #else ! 160: {x_stuff, "stuff", 0, 0, 0 }, ! 161: {x_transpose, "transpose-chars", 0, CTRL('T'), 0 }, ! 162: #endif ! 163: {x_complete, "complete", 1, CTRL('['), 0 }, ! 164: {x_enumerate, "list", 1, '?', 0 }, ! 165: {x_comp_file, "complete-file", 2, CTRL('X'), 0 }, ! 166: {x_comp_comm, "complete-command", 2, CTRL('['), 0 }, ! 167: {x_list_file, "list-file", 0, 0, 0 }, ! 168: {x_list_comm, "list-command", 2, '?', 0 }, ! 169: #if SILLY ! 170: {x_game_of_life, "play-game-of-life", 0, 0, 0 }, ! 171: #endif ! 172: { 0 } ! 173: }; ! 174: ! 175: #define xft_insert &x_ftab[0] ! 176: #define xft_error &x_ftab[1] ! 177: #define xft_ins_string &x_ftab[2] ! 178: ! 179: int ! 180: x_read(fd, buf, len) ! 181: int fd; /* not used */ ! 182: char *buf; ! 183: size_t len; ! 184: { ! 185: char c; ! 186: int i; ! 187: int (*func)(); ! 188: extern x_insert(); ! 189: ! 190: (void)set_xmode(TRUE); ! 191: xbuf = buf; xend = buf + len; ! 192: xcp = xep = buf; ! 193: *xcp = 0; ! 194: x_curprefix = 0; ! 195: macroptr = null; ! 196: x_histp = histptr + 1; ! 197: ! 198: while (1) { ! 199: x_flush(); ! 200: if (*macroptr) { ! 201: c = *macroptr++; ! 202: if (*macroptr == 0) ! 203: macroptr = null; ! 204: } else { ! 205: i = read(ttyfd, &c, 1); ! 206: if (i != 1) ! 207: goto Exit; ! 208: } ! 209: ! 210: if (x_curprefix == -1) ! 211: func = x_insert; ! 212: else ! 213: func = x_tab[x_curprefix][c&CMASK]->xf_func; ! 214: if (func == NULL) ! 215: func = x_error; ! 216: i = c | (x_curprefix << 8); ! 217: x_curprefix = 0; ! 218: switch (i = (*func)(i)) { ! 219: case KSTD: ! 220: x_last_command = func; ! 221: case KPREF: ! 222: break; ! 223: case KEOL: ! 224: i = xep - xbuf; ! 225: x_last_command = 0; ! 226: /* XXX -- doesn't get them all */ ! 227: if (strncmp(xbuf, "stty", 4) == 0) ! 228: first_time = 1; ! 229: goto Exit; ! 230: case KINTR: /* special case for interrupt */ ! 231: i = -1; ! 232: errno = EINTR; ! 233: *xbuf = '\0'; ! 234: goto Exit; ! 235: } ! 236: } ! 237: Exit: ! 238: (void)set_xmode(FALSE); ! 239: if (i < 0 && errno == EINTR) ! 240: trapsig(SIGINT); ! 241: return i; ! 242: } ! 243: ! 244: static int ! 245: x_insert(c) { ! 246: char str[2]; ! 247: ! 248: /* ! 249: * Should allow tab and control chars. ! 250: */ ! 251: if (c == 0) { ! 252: x_putc(BEL); ! 253: return KSTD; ! 254: } ! 255: str[0] = c; ! 256: str[1] = 0; ! 257: x_ins(str); ! 258: return KSTD; ! 259: } ! 260: ! 261: static int ! 262: x_ins_string(c) ! 263: { ! 264: if (*macroptr) { ! 265: x_putc(BEL); ! 266: return KSTD; ! 267: } ! 268: macroptr = x_atab[c>>8][c & CMASK]; ! 269: return KSTD; ! 270: } ! 271: ! 272: static void ! 273: x_ins(cp) ! 274: char *cp; ! 275: { ! 276: int count, i; ! 277: ! 278: count = strlen(cp); ! 279: if (xep+count >= xend) { ! 280: x_putc(BEL); ! 281: return; ! 282: } ! 283: ! 284: if (xcp != xep) ! 285: memmove(xcp+count, xcp, xep - xcp + 1); ! 286: else ! 287: xcp[count] = 0; ! 288: memmove(xcp, cp, count); ! 289: x_zots(xcp); ! 290: xcp += count; ! 291: xep += count; ! 292: i = xep - xcp; ! 293: cp = xep; ! 294: while (i--) ! 295: x_bs(*--cp); ! 296: return; ! 297: } ! 298: ! 299: static int ! 300: x_del_back(c) { ! 301: if (xcp == xbuf) { ! 302: x_putc(BEL); ! 303: return KSTD; ! 304: } ! 305: x_goto(xcp - 1); ! 306: x_delete(1); ! 307: return KSTD; ! 308: } ! 309: ! 310: static int ! 311: x_del_char(c) { ! 312: if (xcp == xep) { ! 313: x_putc(BEL); ! 314: return KSTD; ! 315: } ! 316: x_delete(1); ! 317: return KSTD; ! 318: } ! 319: ! 320: static void ! 321: x_delete(nc) { ! 322: int i,j; ! 323: char *cp; ! 324: ! 325: if (nc == 0) ! 326: return; ! 327: xep -= nc; ! 328: cp = xcp; ! 329: j = 0; ! 330: i = nc; ! 331: while (i--) { ! 332: j += x_size(*cp++); ! 333: } ! 334: memmove(xcp, xcp+nc, xep - xcp + 1); /* Copies the null */ ! 335: x_zots(xcp); ! 336: i = j; ! 337: while (i--) ! 338: x_putc(' '); ! 339: i = j; ! 340: while (i--) ! 341: x_putc('\b'); ! 342: /*x_goto(xcp);*/ ! 343: i = xep - xcp; ! 344: cp = xep; ! 345: while (i--) ! 346: x_bs(*--cp); ! 347: return; ! 348: } ! 349: ! 350: static int ! 351: x_del_bword(c) { ! 352: x_delete(x_bword()); ! 353: return KSTD; ! 354: } ! 355: ! 356: static int ! 357: x_mv_bword(c) { ! 358: (void)x_bword(); ! 359: return KSTD; ! 360: } ! 361: ! 362: static int ! 363: x_mv_fword(c) { ! 364: x_goto(xcp + x_fword()); ! 365: return KSTD; ! 366: } ! 367: ! 368: static int ! 369: x_del_fword(c) { ! 370: x_delete(x_fword()); ! 371: return KSTD; ! 372: } ! 373: ! 374: static int ! 375: x_bword() { ! 376: int nc = 0; ! 377: register char *cp = xcp; ! 378: ! 379: if (cp == xbuf) { ! 380: x_putc(BEL); ! 381: return 0; ! 382: } ! 383: while (cp != xbuf && isfs(cp[-1])) { ! 384: cp--; ! 385: nc++; ! 386: } ! 387: while (cp != xbuf && !isfs(cp[-1])) { ! 388: cp--; ! 389: nc++; ! 390: } ! 391: x_goto(cp); ! 392: return nc; ! 393: } ! 394: ! 395: static int ! 396: x_fword() { ! 397: int nc = 0; ! 398: char *cp = xcp; ! 399: ! 400: if (cp == xep) { ! 401: x_putc(BEL); ! 402: return 0; ! 403: } ! 404: while (cp != xep && !isfs(*cp)) { ! 405: cp++; ! 406: nc++; ! 407: } ! 408: while (cp != xep && isfs(*cp)) { ! 409: cp++; ! 410: nc++; ! 411: } ! 412: return nc; ! 413: } ! 414: ! 415: static void ! 416: x_goto(cp) ! 417: register char *cp; ! 418: { ! 419: if (cp < xcp) { /* move back */ ! 420: while (cp < xcp) ! 421: x_bs(*--xcp); ! 422: } else ! 423: if (cp > xcp) { /* move forward */ ! 424: while (cp > xcp) ! 425: x_zotc(*xcp++); ! 426: } ! 427: } ! 428: ! 429: static void ! 430: x_bs(c) { ! 431: register i; ! 432: i = x_size(c); ! 433: while (i--) ! 434: x_putc('\b'); ! 435: } ! 436: ! 437: static int ! 438: x_size_str(cp) ! 439: register char *cp; ! 440: { ! 441: register size = 0; ! 442: while (*cp) ! 443: size += x_size(*cp++); ! 444: return size; ! 445: } ! 446: ! 447: static int ! 448: x_size(c) { ! 449: if (c=='\t') ! 450: return 4; /* Kludge, tabs are always four spaces. */ ! 451: if (c < ' ' || c == 0x7F) /* ASCII control char */ ! 452: return 2; ! 453: return 1; ! 454: } ! 455: ! 456: static void ! 457: x_zots(str) ! 458: register char *str; ! 459: { ! 460: while (*str) ! 461: x_zotc(*str++); ! 462: } ! 463: ! 464: static void ! 465: x_zotc(c) ! 466: int c; ! 467: { ! 468: if (c == '\t') { ! 469: /* Kludge, tabs are always four spaces. */ ! 470: x_puts(" "); ! 471: } else if (c < ' ' || c == 0x7F) { /* ASCII */ ! 472: x_putc('^'); ! 473: x_putc(UNCTRL(c)); ! 474: } else ! 475: x_putc(c); ! 476: } ! 477: ! 478: /* tty output */ ! 479: ! 480: void ! 481: x_flush() ! 482: { ! 483: fflush(stdout); ! 484: } ! 485: ! 486: void ! 487: x_putc(c) ! 488: int c; ! 489: { ! 490: putc(c, stdout); ! 491: } ! 492: ! 493: void ! 494: x_puts(s) ! 495: register char *s; ! 496: { ! 497: while (*s != 0) ! 498: putc(*s++, stdout); ! 499: } ! 500: ! 501: static int ! 502: x_mv_back(c) { ! 503: if (xcp == xbuf) { ! 504: x_putc(BEL); ! 505: return KSTD; ! 506: } ! 507: x_goto(xcp-1); ! 508: return KSTD; ! 509: } ! 510: ! 511: static int ! 512: x_mv_forw(c) { ! 513: if (xcp == xep) { ! 514: x_putc(BEL); ! 515: return KSTD; ! 516: } ! 517: x_goto(xcp+1); ! 518: return KSTD; ! 519: } ! 520: ! 521: static int ! 522: x_search_char(c) { ! 523: char ci, *cp; ! 524: ! 525: *xep = '\0'; ! 526: if (read(ttyfd, &ci, 1) != 1 || ! 527: /* we search forward, I don't know what Korn does */ ! 528: (cp = (xcp == xep) ? NULL : strchr(xcp+1, ci)) == NULL && ! 529: (cp = strchr(xbuf, ci)) == NULL) { ! 530: x_putc(BEL); ! 531: return KSTD; ! 532: } ! 533: x_goto(cp); ! 534: return KSTD; ! 535: } ! 536: ! 537: static int ! 538: x_newline(c) { ! 539: x_putc('\n'); ! 540: x_flush(); ! 541: *xep++ = '\n'; ! 542: return KEOL; ! 543: } ! 544: ! 545: static int ! 546: x_end_of_text(c) { ! 547: #if 0 ! 548: x_store_hist(); ! 549: #endif ! 550: return KEOL; ! 551: } ! 552: ! 553: static int x_beg_hist(c) {x_load_hist(history); return KSTD;} ! 554: ! 555: static int x_end_hist(c) {x_load_hist(histptr); return KSTD;} ! 556: ! 557: static int x_prev_com(c) {x_load_hist(x_histp-1); return KSTD;} ! 558: ! 559: static int x_next_com(c) {x_load_hist(x_histp+1); return KSTD;} ! 560: ! 561: static void ! 562: x_load_hist(hp) ! 563: register char **hp; ! 564: { ! 565: int oldsize; ! 566: ! 567: if (hp < history || hp > histptr) { ! 568: x_putc(BEL); ! 569: return; ! 570: } ! 571: x_histp = hp; ! 572: oldsize = x_size_str(xbuf); ! 573: (void)strcpy(xbuf, *hp); ! 574: xep = xcp = xbuf + strlen(*hp); ! 575: x_redraw(oldsize); ! 576: } ! 577: ! 578: static int x_search(), x_match(); ! 579: ! 580: /* reverse incremental history search */ ! 581: static int ! 582: x_search_hist(ci) ! 583: { ! 584: int offset = -1; /* offset of match in xbuf, else -1 */ ! 585: static char c[2]; /* input buffer */ ! 586: char pat [256+1]; /* pattern buffer */ ! 587: register char *p = pat; ! 588: int (*func)(); ! 589: ! 590: *p = 0; ! 591: while (1) { ! 592: if (offset < 0) { ! 593: x_puts("\nI-search: "); ! 594: x_zots(pat); ! 595: } ! 596: x_flush(); ! 597: if (read(ttyfd, c, 1) < 1) ! 598: return KSTD; ! 599: func = x_tab[0][*c&CMASK]->xf_func; ! 600: if (*c == CTRL('[')) ! 601: break; ! 602: else if (func == x_search_hist) ! 603: offset = x_search(pat, offset); ! 604: else if (func == x_del_back) ! 605: continue; /* todo */ ! 606: else if (func == x_insert) { ! 607: /* add char to pattern */ ! 608: *p++ = *c, *p = 0; ! 609: if (offset >= 0) { ! 610: /* already have partial match */ ! 611: offset = x_match(xbuf, pat); ! 612: if (offset >= 0) { ! 613: x_goto(xbuf + offset + (p - pat) - (*pat == '^')); ! 614: continue; ! 615: } ! 616: } ! 617: offset = x_search(pat, offset); ! 618: } else { /* other command */ ! 619: macroptr = c; /* push command */ ! 620: break; ! 621: } ! 622: } ! 623: if (offset < 0) ! 624: x_redraw(-1); ! 625: return KSTD; ! 626: } ! 627: ! 628: /* search backward from current line */ ! 629: static int ! 630: x_search(pat, offset) ! 631: char *pat; ! 632: int offset; ! 633: { ! 634: register char **hp; ! 635: int i; ! 636: ! 637: for (hp = x_histp; --hp >= history; ) { ! 638: i = x_match(*hp, pat); ! 639: if (i >= 0) { ! 640: if (offset < 0) ! 641: x_putc('\n'); ! 642: x_load_hist(hp); ! 643: x_goto(xbuf + i + strlen(pat) - (*pat == '^')); ! 644: return i; ! 645: } ! 646: } ! 647: x_putc(BEL); ! 648: x_histp = histptr; ! 649: return -1; ! 650: } ! 651: ! 652: /* return position of first match of pattern in string, else -1 */ ! 653: static int ! 654: x_match(str, pat) ! 655: char *str, *pat; ! 656: { ! 657: if (*pat == '^') { ! 658: return (strncmp(str, pat+1, strlen(pat+1)) == 0) ? 0 : -1; ! 659: } else { ! 660: char *q = strstr(str, pat); ! 661: return (q == NULL) ? -1 : q - str; ! 662: } ! 663: } ! 664: ! 665: static int ! 666: x_del_line(c) { ! 667: int i, j; ! 668: ! 669: *xep = 0; ! 670: i = xep- xbuf; ! 671: j = x_size_str(xbuf); ! 672: xcp = xbuf; ! 673: x_push(i); ! 674: xep = xbuf; ! 675: *xcp = 0; ! 676: x_redraw(j); ! 677: return KSTD; ! 678: } ! 679: ! 680: static int ! 681: x_mv_end(c) { ! 682: x_goto(xep); ! 683: return KSTD; ! 684: } ! 685: ! 686: static int ! 687: x_mv_begin(c) { ! 688: x_goto(xbuf); ! 689: return KSTD; ! 690: } ! 691: ! 692: static int ! 693: x_draw_line(c) ! 694: { ! 695: x_redraw(-1); ! 696: return KSTD; ! 697: ! 698: } ! 699: ! 700: static void ! 701: x_redraw(limit) { ! 702: int i, j; ! 703: char *cp; ! 704: ! 705: if (limit == -1) ! 706: x_putc('\n'); ! 707: else ! 708: x_putc('\r'); ! 709: x_flush(); ! 710: pprompt(prompt); ! 711: x_zots(xbuf); ! 712: if (limit != -1) { ! 713: i = limit - x_size_str(xbuf); ! 714: j = 0; ! 715: while (j < i) { ! 716: x_putc(' '); ! 717: j++; ! 718: } ! 719: while (j--) ! 720: x_putc('\b'); ! 721: } ! 722: i = xep - xcp; ! 723: cp = xep; ! 724: while (i--) ! 725: x_bs(*--cp); ! 726: return; ! 727: } ! 728: ! 729: static int ! 730: x_transpose(c) { ! 731: char tmp; ! 732: if (xcp == xbuf || xcp == xep) { ! 733: x_putc(BEL); ! 734: return KSTD; ! 735: } ! 736: x_bs(xcp[-1]); ! 737: x_zotc(xcp[0]); ! 738: x_zotc(xcp[-1]); ! 739: tmp = xcp[-1]; ! 740: xcp[-1] = xcp[0]; ! 741: xcp[0] = tmp; ! 742: x_bs(xcp[0]); ! 743: return KSTD; ! 744: } ! 745: ! 746: static int ! 747: x_literal(c) { ! 748: x_curprefix = -1; ! 749: return KSTD; ! 750: } ! 751: ! 752: static int ! 753: x_meta1(c) { ! 754: x_curprefix = 1; ! 755: return KPREF; ! 756: } ! 757: ! 758: static int ! 759: x_meta2(c) { ! 760: x_curprefix = 2; ! 761: return KPREF; ! 762: } ! 763: ! 764: static int ! 765: x_kill(c) { ! 766: int i; ! 767: ! 768: i = xep - xcp; ! 769: x_push(i); ! 770: x_delete(i); ! 771: return KSTD; ! 772: } ! 773: ! 774: static void ! 775: x_push(nchars) { ! 776: char *cp; ! 777: cp = alloc((size_t)(nchars+1), AEDIT); ! 778: memmove(cp, xcp, nchars); ! 779: cp[nchars] = 0; ! 780: if (killstack[killsp]) ! 781: afree((Void *)killstack[killsp], AEDIT); ! 782: killstack[killsp] = cp; ! 783: killsp = (killsp + 1) % KILLSIZE; ! 784: } ! 785: ! 786: static int ! 787: x_yank(c) { ! 788: if (killsp == 0) ! 789: killtp = KILLSIZE; ! 790: else ! 791: killtp = killsp; ! 792: killtp --; ! 793: if (killstack[killtp] == 0) { ! 794: x_puts("\nnothing to yank"); ! 795: x_redraw(-1); ! 796: return KSTD; ! 797: } ! 798: x_ins(killstack[killtp]); ! 799: return KSTD; ! 800: } ! 801: ! 802: static int ! 803: x_meta_yank(c) { ! 804: int len; ! 805: if (x_last_command != x_yank && x_last_command != x_meta_yank) { ! 806: x_puts("\nyank something first"); ! 807: x_redraw(-1); ! 808: return KSTD; ! 809: } ! 810: len = strlen(killstack[killtp]); ! 811: x_goto(xcp - len); ! 812: x_delete(len); ! 813: do { ! 814: if (killtp == 0) ! 815: killtp = KILLSIZE - 1; ! 816: else ! 817: killtp--; ! 818: } while (killstack[killtp] == 0); ! 819: x_ins(killstack[killtp]); ! 820: return KSTD; ! 821: } ! 822: ! 823: static int ! 824: x_abort(c) { ! 825: /* x_zotc(c); */ ! 826: return KINTR; ! 827: } ! 828: ! 829: static int ! 830: x_error(c) { ! 831: x_putc(BEL); ! 832: return KSTD; ! 833: } ! 834: ! 835: #if _BSD ! 836: #if defined TIOCGATC ! 837: static struct ttychars lchars, lcharsorig; ! 838: #else ! 839: static struct tchars tchars, tcharsorig; ! 840: static struct ltchars ltchars, ltcharsorig; ! 841: #endif ! 842: #endif ! 843: ! 844: #if _BSD || (COHERENT && !MWC_HP) ! 845: bool_t ! 846: set_xmode(onoff) ! 847: bool_t onoff; ! 848: { ! 849: bool_t prev; ! 850: typedef struct sgttyb Sgttyb; ! 851: static Sgttyb cb; ! 852: static Sgttyb orig; ! 853: ! 854: if (x_mode == onoff) return x_mode; ! 855: prev = x_mode; ! 856: x_mode = onoff; ! 857: if (onoff) { ! 858: if (first_time) { ! 859: (void)ioctl(0, TIOCGETP, &cb); ! 860: orig = cb; ! 861: cb.sg_flags &= ~ECHO; ! 862: cb.sg_flags |= CBREAK; ! 863: #if defined TIOCGATC ! 864: (void)ioctl(0, TIOCGATC, &lcharsorig); ! 865: lchars = lcharsorig; ! 866: lchars.tc_suspc = -1; ! 867: lchars.tc_dsuspc = -1; ! 868: lchars.tc_lnextc = -1; ! 869: lchars.tc_statc = -1; ! 870: lchars.tc_intrc = -1; ! 871: lchars.tc_quitc = -1; ! 872: lchars.tc_rprntc = -1; ! 873: #else ! 874: #if !COHERENT ! 875: (void)ioctl(0, TIOCGETC, &tcharsorig); ! 876: (void)ioctl(0, TIOCGLTC, <charsorig); ! 877: tchars = tcharsorig; ! 878: ltchars = ltcharsorig; ! 879: ltchars.t_suspc = -1; ! 880: ltchars.t_dsuspc = -1; ! 881: ltchars.t_lnextc = -1; ! 882: tchars.t_intrc = -1; ! 883: tchars.t_quitc = -1; ! 884: ltchars.t_rprntc = -1; ! 885: #endif ! 886: #endif ! 887: first_time = 0; ! 888: } ! 889: (void)ioctl(0, TIOCSETN, &cb); ! 890: #if defined TIOCGATC ! 891: (void)ioctl(0, TIOCSATC, &lchars); ! 892: #else ! 893: #if !COHERENT ! 894: (void)ioctl(0, TIOCSETC, &tchars); ! 895: (void)ioctl(0, TIOCSLTC, <chars); ! 896: #endif ! 897: #endif ! 898: } ! 899: else { ! 900: (void)ioctl(0, TIOCSETN, &orig); ! 901: #if defined TIOCGATC ! 902: (void)ioctl(0, TIOCSATC, &lcharsorig); ! 903: #else ! 904: #if !COHERENT ! 905: (void)ioctl(0, TIOCSETC, &tcharsorig); ! 906: (void)ioctl(0, TIOCSLTC, <charsorig); ! 907: #endif ! 908: #endif ! 909: } ! 910: return prev; ! 911: } ! 912: ! 913: #else /* !_BSD */ ! 914: ! 915: bool_t ! 916: set_xmode(onoff) ! 917: bool_t onoff; ! 918: { ! 919: bool_t prev; ! 920: static struct termio cb, orig; ! 921: ! 922: if (x_mode == onoff) return x_mode; ! 923: prev = x_mode; ! 924: x_mode = onoff; ! 925: ! 926: if (onoff) { ! 927: if (first_time) { ! 928: (void)ioctl(0, TCGETA, &cb); ! 929: orig = cb; ! 930: #if defined _CRAY2 /* brain-damaged terminal handler */ ! 931: cb.c_lflag &= ~(ICANON|ECHO); ! 932: /* rely on print routine to map '\n' to CR,LF */ ! 933: #else ! 934: cb.c_iflag &= ~(INLCR|ICRNL); ! 935: #if _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */ ! 936: cb.c_lflag &= ~(ICANON|ECHO); ! 937: #else ! 938: cb.c_lflag &= ~(ISIG|ICANON|ECHO); ! 939: #endif ! 940: cb.c_cc[VTIME] = 0; ! 941: cb.c_cc[VMIN] = 1; ! 942: #endif /* _CRAY2 */ ! 943: first_time = 0; ! 944: } ! 945: #if ! defined TCSETAW /* e.g. Cray-2 */ ! 946: /* first wait for output to drain */ ! 947: #if defined TCSBRK ! 948: (void)ioctl(0, TCSBRK, 1); ! 949: #else /* the following kludge is minimally intrusive, but sometimes fails */ ! 950: (void)sleep((unsigned)1); /* fake it */ ! 951: #endif ! 952: #endif ! 953: #if _BSD_SYSV || !defined(TCSETAW) ! 954: /* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */ ! 955: (void)ioctl(0, TCSETA, &cb); ! 956: #else ! 957: (void)ioctl(0, TCSETAW, &cb); ! 958: #endif ! 959: } ! 960: else { ! 961: #if ! defined TCSETAW /* e.g. Cray-2 */ ! 962: /* first wait for output to drain */ ! 963: #if defined TCSBRK ! 964: (void)ioctl(0, TCSBRK, 1); ! 965: #else ! 966: /* doesn't seem to be necessary when leaving xmode */ ! 967: /* (void)sleep((unsigned)1); */ ! 968: #endif ! 969: #endif ! 970: #if _BSD_SYSV || !defined(TCSETAW) ! 971: /* _BSD_SYSV needs to force TIOCSETN instead of TIOCSETP (preserve type-ahead) */ ! 972: (void)ioctl(0, TCSETA, &orig); ! 973: #else ! 974: (void)ioctl(0, TCSETAW, &orig); ! 975: #endif ! 976: } ! 977: return prev; ! 978: } ! 979: #endif /* _BSD */ ! 980: ! 981: static int ! 982: x_stuffreset(c) ! 983: { ! 984: #if defined TIOCSTI ! 985: (void)x_stuff(c); ! 986: return KINTR; ! 987: #else ! 988: x_zotc(c); ! 989: xcp = xep = xbuf; ! 990: *xcp = 0; ! 991: x_redraw(-1); ! 992: return KSTD; ! 993: #endif ! 994: } ! 995: ! 996: static int ! 997: x_stuff(c) ! 998: { ! 999: #if defined TIOCSTI ! 1000: char ch = c; ! 1001: bool_t savmode = set_xmode(FALSE); ! 1002: ! 1003: (void)ioctl(0, TIOCSTI, &ch); ! 1004: (void)set_xmode(savmode); ! 1005: x_redraw(-1); ! 1006: #endif ! 1007: return KSTD; ! 1008: } ! 1009: ! 1010: static void ! 1011: x_mapin(cp) ! 1012: char *cp; ! 1013: { ! 1014: char *op; ! 1015: ! 1016: op = cp; ! 1017: while (*cp) { ! 1018: /* XXX -- should handle \^ escape? */ ! 1019: if (*cp == '^') { ! 1020: cp++; ! 1021: if (*cp >= '?') /* includes '?'; ASCII */ ! 1022: *op++ = CTRL(*cp); ! 1023: else { ! 1024: *op++ = '^'; ! 1025: cp--; ! 1026: } ! 1027: } else ! 1028: *op++ = *cp; ! 1029: cp++; ! 1030: } ! 1031: *op = 0; ! 1032: } ! 1033: ! 1034: static char * ! 1035: x_mapout(c) ! 1036: int c; ! 1037: { ! 1038: static char buf[8]; ! 1039: register char *p = buf; ! 1040: ! 1041: if (c < ' ' || c == 0x7F) { /* ASCII */ ! 1042: *p++ = '^'; ! 1043: *p++ = (c == 0x7F) ? '?' : (c | 0x40); ! 1044: } else ! 1045: *p++ = c; ! 1046: *p = 0; ! 1047: return buf; ! 1048: } ! 1049: ! 1050: static void ! 1051: x_print(prefix, key) ! 1052: int prefix, key; ! 1053: { ! 1054: if (prefix == 1) ! 1055: shellf("%s", x_mapout(x_prefix1)); ! 1056: if (prefix == 2) ! 1057: shellf("%s", x_mapout(x_prefix2)); ! 1058: shellf("%s = ", x_mapout(key)); ! 1059: if (x_tab[prefix][key]->xf_func != x_ins_string) ! 1060: shellf("%s\n", x_tab[prefix][key]->xf_name); ! 1061: else ! 1062: shellf("'%s'\n", x_atab[prefix][key]); ! 1063: } ! 1064: ! 1065: void ! 1066: x_bind(a1, a2, macro) ! 1067: char *a1, *a2; ! 1068: int macro; /* bind -m */ ! 1069: { ! 1070: struct x_ftab Const *fp; ! 1071: int prefix, key; ! 1072: char *sp = NULL; ! 1073: ! 1074: if (x_tab == NULL) ! 1075: errorf("cannot bind, not a tty\n"); ! 1076: ! 1077: if (a1 == NULL) { ! 1078: for (prefix = 0; prefix < 3; prefix++) ! 1079: for (key = 0; key < 0x80; key++) { ! 1080: fp = x_tab[prefix][key]; ! 1081: if (fp == NULL || ! 1082: fp->xf_func == x_insert || fp->xf_func == x_error) ! 1083: continue; ! 1084: x_print(prefix, key); ! 1085: } ! 1086: return; ! 1087: } ! 1088: ! 1089: x_mapin(a1); ! 1090: prefix = key = 0; ! 1091: for (;; a1++) { ! 1092: key = *a1; ! 1093: if (x_tab[prefix][key]->xf_func == x_meta1) ! 1094: prefix = 1; ! 1095: else ! 1096: if (x_tab[prefix][key]->xf_func == x_meta2) ! 1097: prefix = 2; ! 1098: else ! 1099: break; ! 1100: } ! 1101: ! 1102: if (a2 == NULL) { ! 1103: x_print(prefix, key); ! 1104: return; ! 1105: } ! 1106: ! 1107: if (*a2 == 0) ! 1108: fp = xft_insert; ! 1109: else if (!macro) { ! 1110: for (fp = x_ftab; fp->xf_func; fp++) ! 1111: if (strcmp(fp->xf_name, a2) == 0) ! 1112: break; ! 1113: if (fp->xf_func == NULL || (fp->xf_flags & XF_NOBIND)) ! 1114: errorf("%s: no such function\n", a2); ! 1115: if (fp->xf_func == x_meta1) ! 1116: x_prefix1 = key; ! 1117: if (fp->xf_func == x_meta2) ! 1118: x_prefix2 = key; ! 1119: } else { ! 1120: fp = xft_ins_string; ! 1121: x_mapin(a2); ! 1122: sp = strsave(a2, AEDIT); ! 1123: } ! 1124: ! 1125: if ((x_tab[prefix][key]->xf_flags & XF_ALLOC) && x_atab[prefix][key]) ! 1126: afree((Void *)x_atab[prefix][key], AEDIT); ! 1127: x_tab[prefix][key] = fp; ! 1128: x_atab[prefix][key] = sp; ! 1129: } ! 1130: ! 1131: void ! 1132: x_init() ! 1133: { ! 1134: register int i, j; ! 1135: struct x_ftab Const *fp; ! 1136: ! 1137: ainit(AEDIT); ! 1138: ! 1139: x_tab = alloc(sizeofN(*x_tab, 3), AEDIT); ! 1140: for (j = 0; j < 128; j++) ! 1141: x_tab[0][j] = xft_insert; ! 1142: for (i = 1; i < 3; i++) ! 1143: for (j = 0; j < 128; j++) ! 1144: x_tab[i][j] = xft_error; ! 1145: for (fp = x_ftab; fp->xf_func; fp++) ! 1146: if (fp->xf_db_char || fp->xf_db_tab) ! 1147: x_tab[fp->xf_db_tab][fp->xf_db_char] = fp; ! 1148: ! 1149: x_atab = alloc(sizeofN(*x_atab, 3), AEDIT); ! 1150: for (i = 1; i < 3; i++) ! 1151: for (j = 0; j < 128; j++) ! 1152: x_atab[i][j] = NULL; ! 1153: } ! 1154: ! 1155: #if SILLY ! 1156: static int ! 1157: x_game_of_life(c) { ! 1158: char newbuf [256+1]; ! 1159: register char *ip, *op; ! 1160: int i, len; ! 1161: ! 1162: i = xep - xbuf; ! 1163: *xep = 0; ! 1164: len = x_size_str(xbuf); ! 1165: xcp = xbuf; ! 1166: memmove(newbuf+1, xbuf, i); ! 1167: newbuf[0] = 'A'; ! 1168: newbuf[i] = 'A'; ! 1169: for (ip = newbuf+1, op = xbuf; --i >= 0; ip++, op++) { ! 1170: /* Empty space */ ! 1171: if (*ip < '@' || *ip == '_' || *ip == 0x7F) { ! 1172: /* Two adults, make whoopee */ ! 1173: if (ip[-1] < '_' && ip[1] < '_') { ! 1174: /* Make kid look like parents. */ ! 1175: *op = '`' + ((ip[-1] + ip[1])/2)%32; ! 1176: if (*op == 0x7F) /* Birth defect */ ! 1177: *op = '`'; ! 1178: } ! 1179: else ! 1180: *op = ' '; /* nothing happens */ ! 1181: continue; ! 1182: } ! 1183: /* Child */ ! 1184: if (*ip > '`') { ! 1185: /* All alone, dies */ ! 1186: if (ip[-1] == ' ' && ip[1] == ' ') ! 1187: *op = ' '; ! 1188: else /* Gets older */ ! 1189: *op = *ip-'`'+'@'; ! 1190: continue; ! 1191: } ! 1192: /* Adult */ ! 1193: /* Overcrowded, dies */ ! 1194: if (ip[-1] >= '@' && ip[1] >= '@') { ! 1195: *op = ' '; ! 1196: continue; ! 1197: } ! 1198: *op = *ip; ! 1199: } ! 1200: *op = 0; ! 1201: x_redraw(len); ! 1202: return KSTD; ! 1203: } ! 1204: #endif ! 1205: ! 1206: /* ! 1207: * File/command name completion routines ! 1208: */ ! 1209: ! 1210: /* type: 0 for list, 1 for completion */ ! 1211: ! 1212: static XPtrV words; ! 1213: ! 1214: static void ! 1215: add_stash(dirnam, name) ! 1216: char *dirnam; /* directory name, if file */ ! 1217: char *name; ! 1218: { ! 1219: char *cp; ! 1220: register int type = 0; /* '*' if executable, '/' if directory, else 0 */ ! 1221: register int len = strlen(name); ! 1222: ! 1223: /* determine file type */ ! 1224: if (dirnam) { ! 1225: struct stat statb; ! 1226: char *buf = alloc((size_t)(strlen(dirnam)+len+2), ATEMP); ! 1227: ! 1228: if (strcmp(dirnam, ".") == 0) ! 1229: *buf = '\0'; ! 1230: else if (strcmp(dirnam, "/") == 0) ! 1231: (void)strcpy(buf, "/"); ! 1232: else ! 1233: (void)strcat(strcpy(buf, dirnam), "/"); ! 1234: (void)strcat(buf, name); ! 1235: if (stat(buf, &statb)==0) ! 1236: if (S_ISDIR(statb.st_mode)) ! 1237: type = '/'; ! 1238: else if (S_ISREG(statb.st_mode) && eaccess(buf, 01)==0) ! 1239: type = '*'; ! 1240: if (type) ! 1241: ++len; ! 1242: afree((Void *)buf, ATEMP); ! 1243: } ! 1244: ! 1245: if (len > x_maxlen) ! 1246: x_maxlen = len; ! 1247: ! 1248: /* stash name for later sorting */ ! 1249: cp = alloc((size_t)(len+1), ATEMP); ! 1250: (void)strcpy(cp = alloc((size_t)(len+1), ATEMP), name); ! 1251: if (dirnam && type) { /* append file type indicator */ ! 1252: cp[len-1] = type; ! 1253: cp[len] = '\0'; ! 1254: } ! 1255: XPput(words, cp); ! 1256: } ! 1257: ! 1258: static void ! 1259: list_stash() ! 1260: { ! 1261: register char **array, **record; ! 1262: int items = 0, tabstop, loc, nrows, jump, offset; ! 1263: ! 1264: items = XPsize(words); ! 1265: array = (char**) XPptrv(words); ! 1266: if (items == 0) ! 1267: return; ! 1268: qsortp(XPptrv(words), (size_t)XPsize(words), xstrcmp); ! 1269: ! 1270: /* print names */ ! 1271: x_maxlen = (x_maxlen/8 + 1) * 8; /* column width */ ! 1272: nrows = (items-1) / (x_cols/x_maxlen) + 1; ! 1273: for (offset = 0; offset < nrows; ++offset) { ! 1274: tabstop = loc = 0; ! 1275: x_putc('\n'); ! 1276: for (jump = 0; offset+jump < items; jump += nrows) { ! 1277: if (jump) ! 1278: while (loc < tabstop) { ! 1279: x_putc('\t'); ! 1280: loc = (loc/8 + 1) * 8; ! 1281: } ! 1282: record = array + (offset + jump); ! 1283: x_puts(*record); ! 1284: afree((Void *)*record, ATEMP); ! 1285: loc += strlen(*record); ! 1286: tabstop += x_maxlen; /* next tab stop */ ! 1287: } ! 1288: } ! 1289: ! 1290: afree((Void*)array, ATEMP); ! 1291: x_redraw(-1); ! 1292: } ! 1293: ! 1294: static int ! 1295: x_comp_comm(c) { ! 1296: compl_command(1); ! 1297: return KSTD; ! 1298: } ! 1299: static int ! 1300: x_list_comm(c) { ! 1301: compl_command(0); ! 1302: return KSTD; ! 1303: } ! 1304: static int ! 1305: x_complete(c) { ! 1306: compl_dec(1); ! 1307: return KSTD; ! 1308: } ! 1309: static int ! 1310: x_enumerate(c) { ! 1311: compl_dec(0); ! 1312: return KSTD; ! 1313: } ! 1314: static int ! 1315: x_comp_file(c) { ! 1316: compl_file(1); ! 1317: return KSTD; ! 1318: } ! 1319: static int ! 1320: x_list_file(c) { ! 1321: compl_file(0); ! 1322: return KSTD; ! 1323: } ! 1324: ! 1325: static void ! 1326: compl_dec(type) ! 1327: { ! 1328: char *cp; ! 1329: cp = xcp; ! 1330: ! 1331: while (cp != xbuf && !isfs(*cp)) ! 1332: cp--; ! 1333: if (cp == xbuf && strchr(cp, '/') == NULL) ! 1334: compl_command(type); ! 1335: else ! 1336: compl_file(type); ! 1337: } ! 1338: ! 1339: static void ! 1340: compl_file(type) ! 1341: { ! 1342: char *str; ! 1343: register char *cp, *xp; ! 1344: char *lastp; ! 1345: char *dirnam; ! 1346: char buf [256+1]; ! 1347: char bug [256+1]; ! 1348: DIR *dirp; ! 1349: struct dirent *dp; ! 1350: long loc = -1; ! 1351: int len; ! 1352: int multi = 0; ! 1353: ! 1354: str = xcp; ! 1355: cp = buf; ! 1356: xp = str; ! 1357: while (xp != xbuf) { ! 1358: --xp; ! 1359: if (isfs(*xp)) { ! 1360: xp++; ! 1361: break; ! 1362: } ! 1363: } ! 1364: if (digit(*xp) && (xp[1] == '<' || xp[1] == '>')) ! 1365: xp++; ! 1366: while (*xp == '<' || *xp == '>') ! 1367: xp++; ! 1368: if (type) ! 1369: while (*xcp && !isfs(*xcp)) ! 1370: x_zotc(*xcp++); ! 1371: else { ! 1372: x_maxlen = 0; ! 1373: XPinit(words, 16); ! 1374: } ! 1375: while (*xp && !isfs(*xp)) ! 1376: *cp++ = *xp++; ! 1377: ! 1378: *cp = 0; ! 1379: strcpy(buf, cp = substitute(buf, DOTILDE)); ! 1380: afree((Void*)cp, ATEMP); ! 1381: lastp = strrchr(buf, '/'); ! 1382: if (lastp) ! 1383: *lastp = 0; ! 1384: ! 1385: dirnam = (lastp == NULL) ? "." : (lastp == buf) ? "/" : buf; ! 1386: dirp = opendir(dirnam); ! 1387: if (dirp == NULL) { ! 1388: x_putc(BEL); ! 1389: return; ! 1390: } ! 1391: ! 1392: if (lastp == NULL) ! 1393: lastp = buf; ! 1394: else ! 1395: lastp++; ! 1396: len = strlen(lastp); ! 1397: ! 1398: while ((dp = readdir(dirp)) != NULL) { ! 1399: cp = dp->d_name; ! 1400: if (cp[0] == '.' && ! 1401: (cp[1] == '\0' || cp[1] == '.' && cp[2] == '\0')) ! 1402: continue; /* always ignore . and .. */ ! 1403: if (strncmp(lastp, cp, len) == 0) ! 1404: if (type) { ! 1405: if (loc == -1) { ! 1406: (void)strcpy(bug, cp); ! 1407: loc = strlen(cp); ! 1408: } else { ! 1409: multi = 1; ! 1410: loc = strmatch(bug, cp); ! 1411: bug[loc] = 0; ! 1412: } ! 1413: } else ! 1414: add_stash(dirnam, cp); ! 1415: } ! 1416: (void)closedir(dirp); ! 1417: ! 1418: if (type) { ! 1419: if (loc <= 0) { ! 1420: x_putc(BEL); ! 1421: return; ! 1422: } ! 1423: cp = bug + len; ! 1424: x_ins(cp); ! 1425: if (!multi) { ! 1426: struct stat statb; ! 1427: if (lastp == buf) ! 1428: buf[0] = 0; ! 1429: else if (lastp == buf + 1) { ! 1430: buf[1] = 0; ! 1431: buf[0] = '/'; ! 1432: } else ! 1433: (void)strcat(buf, "/"); ! 1434: (void)strcat(buf, bug); ! 1435: if (stat(buf, &statb) == 0 && S_ISDIR(statb.st_mode)) ! 1436: x_ins("/"); ! 1437: else ! 1438: x_ins(" "); ! 1439: } ! 1440: } else ! 1441: list_stash(); ! 1442: } ! 1443: ! 1444: static void ! 1445: compl_command(type) ! 1446: { ! 1447: register struct tbl *tp; ! 1448: char *str; ! 1449: char buf [256+1]; ! 1450: char bug [256+1]; ! 1451: char *xp; ! 1452: char *cp; ! 1453: int len; ! 1454: int multi; ! 1455: int loc; ! 1456: ! 1457: str = xcp; ! 1458: cp = buf; ! 1459: xp = str; ! 1460: while (xp != xbuf) { ! 1461: --xp; ! 1462: if (isfs(*xp)) { ! 1463: xp++; ! 1464: break; ! 1465: } ! 1466: } ! 1467: if (type) ! 1468: while (*xcp && !isfs(*xcp)) ! 1469: x_zotc(*xcp++); ! 1470: else { ! 1471: x_maxlen = 0; ! 1472: XPinit(words, 16); ! 1473: } ! 1474: while (*xp && !isfs(*xp)) ! 1475: *cp++ = *xp++; ! 1476: *cp = 0; ! 1477: ! 1478: len = strlen(buf); ! 1479: loc = -1; ! 1480: multi = 0; ! 1481: ! 1482: for (twalk(&commands); (tp = tnext()) != NULL; ) { ! 1483: int klen; ! 1484: ! 1485: if (!(tp->flag&ISSET)) ! 1486: continue; ! 1487: klen = strlen(tp->name); ! 1488: if (klen < len) ! 1489: return; ! 1490: if (strncmp(buf, tp->name, len) ==0) ! 1491: if (type) { ! 1492: if (loc == -1) { ! 1493: (void)strcpy(bug, tp->name); ! 1494: loc = klen; ! 1495: } else { ! 1496: multi = 1; ! 1497: loc = strmatch(bug, tp->name); ! 1498: bug[loc] = 0; ! 1499: } ! 1500: } else ! 1501: add_stash((char *)0, tp->name); ! 1502: } ! 1503: ! 1504: if (type) { ! 1505: if (loc <= 0) { ! 1506: x_putc(BEL); ! 1507: return; ! 1508: } ! 1509: cp = bug + len; ! 1510: x_ins(cp); ! 1511: if (!multi) ! 1512: x_ins(" "); ! 1513: } else ! 1514: list_stash(); ! 1515: } ! 1516: ! 1517: static int ! 1518: strmatch(s1, s2) ! 1519: register char *s1, *s2; ! 1520: { ! 1521: register char *p; ! 1522: ! 1523: for (p = s1; *p == *s2++ && *p != 0; p++) ! 1524: ; ! 1525: return p - s1; ! 1526: } ! 1527: ! 1528: #endif /* EDIT */ ! 1529:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.