Annotation of coherent/a/usr/bob/korn/edit.c, revision 1.1.1.1

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, &ltcharsorig);
                    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, &ltchars);
                    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, &ltcharsorig);
                    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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.