Annotation of coherent/a/usr/bob/korn/edit.c, revision 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.