[BACK]Return to echo.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/echo.c, Revision 1.57

1.57    ! guenther    1: /*     $OpenBSD: echo.c,v 1.56 2014/03/20 07:47:29 lum Exp $   */
1.35      kjell       2:
                      3: /* This file is in the public domain. */
                      4:
1.1       deraadt     5: /*
1.3       millert     6:  *     Echo line reading and writing.
1.1       deraadt     7:  *
1.3       millert     8:  * Common routines for reading and writing characters in the echo line area
                      9:  * of the display screen. Used by the entire known universe.
1.1       deraadt    10:  */
1.3       millert    11:
                     12: #include "def.h"
                     13: #include "key.h"
                     14: #include "macro.h"
                     15:
1.16      art        16: #include "funmap.h"
                     17:
1.3       millert    18: #include <stdarg.h>
1.38      kjell      19: #include <term.h>
1.1       deraadt    20:
1.29      vincent    21: static char    *veread(const char *, char *, size_t, int, va_list);
1.38      kjell      22: static int      complt(int, int, char *, size_t, int, int *);
1.41      kjell      23: static int      complt_list(int, char *, int);
1.31      db         24: static void     eformat(const char *, va_list);
                     25: static void     eputi(int, int);
                     26: static void     eputl(long, int);
                     27: static void     eputs(const char *);
                     28: static void     eputc(char);
1.40      deraadt    29: static struct list     *copy_list(struct list *);
1.1       deraadt    30:
1.14      mickey     31: int            epresf = FALSE;         /* stuff in echo line flag */
1.1       deraadt    32:
                     33: /*
                     34:  * Erase the echo line.
                     35:  */
1.10      art        36: void
1.21      vincent    37: eerase(void)
1.2       millert    38: {
1.1       deraadt    39:        ttcolor(CTEXT);
1.2       millert    40:        ttmove(nrow - 1, 0);
1.1       deraadt    41:        tteeol();
                     42:        ttflush();
                     43:        epresf = FALSE;
                     44: }
                     45:
                     46: /*
1.14      mickey     47:  * Ask a "yes" or "no" question.  Return ABORT if the user answers the
                     48:  * question with the abort ("^G") character.  Return FALSE for "no" and
                     49:  * TRUE for "yes".  No formatting services are available.  No newline
1.3       millert    50:  * required.
1.1       deraadt    51:  */
1.2       millert    52: int
1.21      vincent    53: eyorn(const char *sp)
1.2       millert    54: {
1.3       millert    55:        int      s;
1.1       deraadt    56:
1.2       millert    57:        if (inmacro)
1.31      db         58:                return (TRUE);
1.50      lum        59:
1.1       deraadt    60:        ewprintf("%s? (y or n) ", sp);
                     61:        for (;;) {
                     62:                s = getkey(FALSE);
1.44      kjell      63:                if (s == 'y' || s == 'Y' || s == ' ')
1.31      db         64:                        return (TRUE);
1.44      kjell      65:                if (s == 'n' || s == 'N' || s == CCHR('M'))
1.31      db         66:                        return (FALSE);
1.2       millert    67:                if (s == CCHR('G'))
1.31      db         68:                        return (ctrlg(FFRAND, 1));
1.1       deraadt    69:                ewprintf("Please answer y or n.  %s? (y or n) ", sp);
1.52      florian    70:        }
                     71:        /* NOTREACHED */
                     72: }
                     73:
                     74: /*
                     75:  * Ask a "yes", "no" or "revert" question.  Return ABORT if the user answers
                     76:  * the question with the abort ("^G") character.  Return FALSE for "no",
                     77:  * TRUE for "yes" and REVERT for "revert". No formatting services are
                     78:  * available.  No newline required.
                     79:  */
                     80: int
                     81: eynorr(const char *sp)
                     82: {
                     83:        int      s;
                     84:
                     85:        if (inmacro)
                     86:                return (TRUE);
                     87:
                     88:        ewprintf("%s? (y, n or r) ", sp);
                     89:        for (;;) {
                     90:                s = getkey(FALSE);
                     91:                if (s == 'y' || s == 'Y' || s == ' ')
                     92:                        return (TRUE);
                     93:                if (s == 'n' || s == 'N' || s == CCHR('M'))
                     94:                        return (FALSE);
                     95:                if (s == 'r' || s == 'R')
                     96:                        return (REVERT);
                     97:                if (s == CCHR('G'))
                     98:                        return (ctrlg(FFRAND, 1));
                     99:                ewprintf("Please answer y, n or r.");
1.1       deraadt   100:        }
1.2       millert   101:        /* NOTREACHED */
1.1       deraadt   102: }
                    103:
                    104: /*
1.3       millert   105:  * Like eyorn, but for more important questions.  User must type all of
1.31      db        106:  * "yes" or "no" and the trailing newline.
1.1       deraadt   107:  */
1.2       millert   108: int
1.21      vincent   109: eyesno(const char *sp)
1.2       millert   110: {
1.29      vincent   111:        char     buf[64], *rep;
1.1       deraadt   112:
1.2       millert   113:        if (inmacro)
1.31      db        114:                return (TRUE);
1.50      lum       115:
1.36      kjell     116:        rep = eread("%s? (yes or no) ", buf, sizeof(buf),
                    117:            EFNUL | EFNEW | EFCR, sp);
1.1       deraadt   118:        for (;;) {
1.29      vincent   119:                if (rep == NULL)
1.31      db        120:                        return (ABORT);
1.29      vincent   121:                if (rep[0] != '\0') {
1.1       deraadt   122:                        if (macrodef) {
1.40      deraadt   123:                                struct line     *lp = maclcur;
1.1       deraadt   124:
1.2       millert   125:                                maclcur = lp->l_bp;
                    126:                                maclcur->l_fp = lp->l_fp;
1.43      kjell     127:                                free(lp);
1.1       deraadt   128:                        }
1.29      vincent   129:                        if ((rep[0] == 'y' || rep[0] == 'Y') &&
                    130:                            (rep[1] == 'e' || rep[1] == 'E') &&
                    131:                            (rep[2] == 's' || rep[2] == 'S') &&
                    132:                            (rep[3] == '\0'))
1.31      db        133:                                return (TRUE);
1.29      vincent   134:                        if ((rep[0] == 'n' || rep[0] == 'N') &&
                    135:                            (rep[1] == 'o' || rep[0] == 'O') &&
                    136:                            (rep[2] == '\0'))
1.31      db        137:                                return (FALSE);
1.1       deraadt   138:                }
1.36      kjell     139:                rep = eread("Please answer yes or no.  %s? (yes or no) ",
                    140:                    buf, sizeof(buf), EFNUL | EFNEW | EFCR, sp);
1.1       deraadt   141:        }
1.2       millert   142:        /* NOTREACHED */
1.1       deraadt   143: }
1.2       millert   144:
1.1       deraadt   145: /*
1.14      mickey    146:  * This is the general "read input from the echo line" routine.  The basic
1.3       millert   147:  * idea is that the prompt string "prompt" is written to the echo line, and
1.14      mickey    148:  * a one line reply is read back into the supplied "buf" (with maximum
1.36      kjell     149:  * length "len").
                    150:  * XXX: When checking for an empty return value, always check rep, *not* buf
                    151:  * as buf may be freed in pathological cases.
1.1       deraadt   152:  */
1.2       millert   153: /* VARARGS */
1.29      vincent   154: char *
                    155: eread(const char *fmt, char *buf, size_t nbuf, int flag, ...)
1.1       deraadt   156: {
1.3       millert   157:        va_list  ap;
1.31      db        158:        char    *rep;
1.29      vincent   159:
1.2       millert   160:        va_start(ap, flag);
1.29      vincent   161:        rep = veread(fmt, buf, nbuf, flag, ap);
1.2       millert   162:        va_end(ap);
1.31      db        163:        return (rep);
1.1       deraadt   164: }
                    165:
1.29      vincent   166: static char *
                    167: veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
1.2       millert   168: {
1.38      kjell     169:        int      dynbuf = (buf == NULL);
                    170:        int      cpos, epos;            /* cursor, end position in buf */
                    171:        int      c, i, y;
                    172:        int      cplflag = FALSE;       /* display completion list */
                    173:        int      cwin = FALSE;          /* completion list created */
                    174:        int      mr = 0;                /* match left arrow */
                    175:        int      ml = 0;                /* match right arrow */
                    176:        int      esc = 0;               /* position in esc pattern */
1.40      deraadt   177:        struct buffer   *bp;                    /* completion list buffer */
                    178:        struct mgwin    *wp;                    /* window for compl list */
1.38      kjell     179:        int      match;                 /* esc match found */
                    180:        int      cc, rr;                /* saved ttcol, ttrow */
                    181:        char    *ret;                   /* return value */
1.1       deraadt   182:
1.47      kjell     183:        static char emptyval[] = "";    /* XXX hackish way to return err msg*/
                    184:
1.2       millert   185:        if (inmacro) {
1.29      vincent   186:                if (dynbuf) {
                    187:                        if ((buf = malloc(maclcur->l_used + 1)) == NULL)
1.31      db        188:                                return (NULL);
1.29      vincent   189:                } else if (maclcur->l_used >= nbuf)
1.31      db        190:                        return (NULL);
1.2       millert   191:                bcopy(maclcur->l_text, buf, maclcur->l_used);
                    192:                buf[maclcur->l_used] = '\0';
                    193:                maclcur = maclcur->l_fp;
1.31      db        194:                return (buf);
1.1       deraadt   195:        }
1.38      kjell     196:        epos = cpos = 0;
                    197:        ml = mr = esc = 0;
                    198:        cplflag = FALSE;
                    199:
1.2       millert   200:        if ((flag & EFNEW) != 0 || ttrow != nrow - 1) {
1.1       deraadt   201:                ttcolor(CTEXT);
1.2       millert   202:                ttmove(nrow - 1, 0);
1.1       deraadt   203:                epresf = TRUE;
                    204:        } else
                    205:                eputc(' ');
                    206:        eformat(fp, ap);
1.16      art       207:        if ((flag & EFDEF) != 0) {
1.29      vincent   208:                if (buf == NULL)
1.31      db        209:                        return (NULL);
1.16      art       210:                eputs(buf);
1.38      kjell     211:                epos = cpos += strlen(buf);
1.16      art       212:        }
1.1       deraadt   213:        tteeol();
                    214:        ttflush();
                    215:        for (;;) {
                    216:                c = getkey(FALSE);
1.51      lum       217:                if ((flag & EFAUTO) != 0 && c == CCHR('I')) {
1.38      kjell     218:                        if (cplflag == TRUE) {
1.41      kjell     219:                                complt_list(flag, buf, cpos);
1.38      kjell     220:                                cwin = TRUE;
                    221:                        } else if (complt(flag, c, buf, nbuf, epos, &i) == TRUE) {
                    222:                                cplflag = TRUE;
                    223:                                epos += i;
                    224:                                cpos = epos;
                    225:                        }
1.1       deraadt   226:                        continue;
                    227:                }
1.38      kjell     228:                cplflag = FALSE;
                    229:
                    230:                if (esc > 0) { /* ESC sequence started */
                    231:                        match = 0;
                    232:                        if (ml == esc && key_left[ml] && c == key_left[ml]) {
                    233:                                match++;
                    234:                                if (key_left[++ml] == '\0') {
                    235:                                        c = CCHR('B');
                    236:                                        esc = 0;
                    237:                                }
                    238:                        }
                    239:                        if (mr == esc && key_right[mr] && c == key_right[mr]) {
                    240:                                match++;
                    241:                                if (key_right[++mr] == '\0') {
                    242:                                        c = CCHR('F');
                    243:                                        esc = 0;
                    244:                                }
                    245:                        }
                    246:                        if (match == 0) {
                    247:                                esc = 0;
                    248:                                continue;
                    249:                                /* hack. how do we know esc pattern is done? */
                    250:                        }
                    251:                        if (esc > 0) {
                    252:                                esc++;
                    253:                                continue;
                    254:                        }
1.1       deraadt   255:                }
1.39      deraadt   256:                switch (c) {
1.38      kjell     257:                case CCHR('A'): /* start of line */
                    258:                        while (cpos > 0) {
                    259:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    260:                                        ttputc('\b');
                    261:                                        --ttcol;
                    262:                                }
                    263:                                ttputc('\b');
                    264:                                --ttcol;
                    265:                        }
                    266:                        ttflush();
                    267:                        break;
                    268:                case CCHR('D'):
                    269:                        if (cpos != epos) {
                    270:                                tteeol();
                    271:                                epos--;
                    272:                                rr = ttrow;
                    273:                                cc = ttcol;
                    274:                                for (i = cpos; i < epos; i++) {
                    275:                                        buf[i] = buf[i + 1];
                    276:                                        eputc(buf[i]);
                    277:                                }
                    278:                                ttmove(rr, cc);
                    279:                                ttflush();
                    280:                        }
                    281:                        break;
                    282:                case CCHR('E'): /* end of line */
                    283:                        while (cpos < epos) {
                    284:                                eputc(buf[cpos++]);
                    285:                        }
                    286:                        ttflush();
                    287:                        break;
                    288:                case CCHR('B'): /* back */
                    289:                        if (cpos > 0) {
                    290:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    291:                                        ttputc('\b');
                    292:                                        --ttcol;
                    293:                                }
                    294:                                ttputc('\b');
                    295:                                --ttcol;
                    296:                                ttflush();
                    297:                        }
                    298:                        break;
                    299:                case CCHR('F'): /* forw */
                    300:                        if (cpos < epos) {
                    301:                                eputc(buf[cpos++]);
                    302:                                ttflush();
                    303:                        }
                    304:                        break;
                    305:                case CCHR('Y'): /* yank from kill buffer */
                    306:                        i = 0;
                    307:                        while ((y = kremove(i++)) >= 0 && y != '\n') {
                    308:                                int t;
                    309:                                if (dynbuf && epos + 1 >= nbuf) {
                    310:                                        void *newp;
                    311:                                        size_t newsize = epos + epos + 16;
                    312:                                        if ((newp = realloc(buf, newsize))
                    313:                                            == NULL)
1.47      kjell     314:                                                goto memfail;
1.38      kjell     315:                                        buf = newp;
                    316:                                        nbuf = newsize;
                    317:                                }
1.47      kjell     318:                                if (!dynbuf && epos + 1 >= nbuf) {
1.56      lum       319:                                        dobeep();
1.47      kjell     320:                                        ewprintf("Line too long");
                    321:                                        return (emptyval);
                    322:                                }
1.38      kjell     323:                                for (t = epos; t > cpos; t--)
                    324:                                        buf[t] = buf[t - 1];
                    325:                                buf[cpos++] = (char)y;
                    326:                                epos++;
                    327:                                eputc((char)y);
                    328:                                cc = ttcol;
                    329:                                rr = ttrow;
                    330:                                for (t = cpos; t < epos; t++)
                    331:                                        eputc(buf[t]);
                    332:                                ttmove(rr, cc);
                    333:                        }
                    334:                        ttflush();
                    335:                        break;
                    336:                case CCHR('K'): /* copy here-EOL to kill buffer */
                    337:                        kdelete();
                    338:                        for (i = cpos; i < epos; i++)
                    339:                                kinsert(buf[i], KFORW);
                    340:                        tteeol();
                    341:                        epos = cpos;
                    342:                        ttflush();
                    343:                        break;
                    344:                case CCHR('['):
                    345:                        ml = mr = esc = 1;
                    346:                        break;
1.2       millert   347:                case CCHR('J'):
1.3       millert   348:                        c = CCHR('M');
1.22      vincent   349:                        /* FALLTHROUGH */
1.3       millert   350:                case CCHR('M'):                 /* return, done */
1.36      kjell     351:                        /* if there's nothing in the minibuffer, abort */
1.38      kjell     352:                        if (epos == 0 && !(flag & EFNUL)) {
1.33      cloder    353:                                (void)ctrlg(FFRAND, 0);
                    354:                                ttflush();
                    355:                                return (NULL);
                    356:                        }
1.2       millert   357:                        if ((flag & EFFUNC) != 0) {
1.38      kjell     358:                                if (complt(flag, c, buf, nbuf, epos, &i)
                    359:                                    == FALSE)
1.1       deraadt   360:                                        continue;
1.2       millert   361:                                if (i > 0)
1.38      kjell     362:                                        epos += i;
1.1       deraadt   363:                        }
1.38      kjell     364:                        buf[epos] = '\0';
1.2       millert   365:                        if ((flag & EFCR) != 0) {
1.1       deraadt   366:                                ttputc(CCHR('M'));
                    367:                                ttflush();
                    368:                        }
1.2       millert   369:                        if (macrodef) {
1.40      deraadt   370:                                struct line     *lp;
1.1       deraadt   371:
1.47      kjell     372:                                if ((lp = lalloc(cpos)) == NULL)
                    373:                                        goto memfail;
1.2       millert   374:                                lp->l_fp = maclcur->l_fp;
                    375:                                maclcur->l_fp = lp;
                    376:                                lp->l_bp = maclcur;
                    377:                                maclcur = lp;
                    378:                                bcopy(buf, lp->l_text, cpos);
1.1       deraadt   379:                        }
1.38      kjell     380:                        ret = buf;
1.1       deraadt   381:                        goto done;
1.3       millert   382:                case CCHR('G'):                 /* bell, abort */
1.1       deraadt   383:                        eputc(CCHR('G'));
1.10      art       384:                        (void)ctrlg(FFRAND, 0);
1.1       deraadt   385:                        ttflush();
1.38      kjell     386:                        ret = NULL;
                    387:                        goto done;
1.3       millert   388:                case CCHR('H'):                 /* rubout, erase */
1.14      mickey    389:                case CCHR('?'):
1.1       deraadt   390:                        if (cpos != 0) {
1.38      kjell     391:                                y = buf[--cpos];
                    392:                                epos--;
1.1       deraadt   393:                                ttputc('\b');
1.38      kjell     394:                                ttcol--;
                    395:                                if (ISCTRL(y) != FALSE) {
                    396:                                        ttputc('\b');
                    397:                                        ttcol--;
                    398:                                }
                    399:                                rr = ttrow;
                    400:                                cc = ttcol;
                    401:                                for (i = cpos; i < epos; i++) {
                    402:                                        buf[i] = buf[i + 1];
                    403:                                        eputc(buf[i]);
                    404:                                }
1.1       deraadt   405:                                ttputc(' ');
1.38      kjell     406:                                if (ISCTRL(y) != FALSE) {
1.1       deraadt   407:                                        ttputc(' ');
                    408:                                        ttputc('\b');
                    409:                                }
1.38      kjell     410:                                ttputc('\b');
                    411:                                ttmove(rr, cc);
1.1       deraadt   412:                                ttflush();
                    413:                        }
                    414:                        break;
1.3       millert   415:                case CCHR('X'):                 /* kill line */
                    416:                case CCHR('U'):
1.1       deraadt   417:                        while (cpos != 0) {
                    418:                                ttputc('\b');
                    419:                                ttputc(' ');
                    420:                                ttputc('\b');
                    421:                                --ttcol;
                    422:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    423:                                        ttputc('\b');
                    424:                                        ttputc(' ');
                    425:                                        ttputc('\b');
                    426:                                        --ttcol;
                    427:                                }
1.38      kjell     428:                                epos--;
1.1       deraadt   429:                        }
                    430:                        ttflush();
                    431:                        break;
1.3       millert   432:                case CCHR('W'):                 /* kill to beginning of word */
1.1       deraadt   433:                        while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
                    434:                                ttputc('\b');
                    435:                                ttputc(' ');
                    436:                                ttputc('\b');
                    437:                                --ttcol;
                    438:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    439:                                        ttputc('\b');
                    440:                                        ttputc(' ');
                    441:                                        ttputc('\b');
                    442:                                        --ttcol;
                    443:                                }
1.46      kjell     444:                                epos--;
1.1       deraadt   445:                        }
                    446:                        while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
                    447:                                ttputc('\b');
                    448:                                ttputc(' ');
                    449:                                ttputc('\b');
                    450:                                --ttcol;
                    451:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    452:                                        ttputc('\b');
                    453:                                        ttputc(' ');
                    454:                                        ttputc('\b');
                    455:                                        --ttcol;
                    456:                                }
1.46      kjell     457:                                epos--;
1.1       deraadt   458:                        }
                    459:                        ttflush();
                    460:                        break;
1.2       millert   461:                case CCHR('\\'):
1.3       millert   462:                case CCHR('Q'):                 /* quote next */
                    463:                        c = getkey(FALSE);
1.22      vincent   464:                        /* FALLTHROUGH */
1.30      deraadt   465:                default:
1.38      kjell     466:                        if (dynbuf && epos + 1 >= nbuf) {
1.29      vincent   467:                                void *newp;
1.38      kjell     468:                                size_t newsize = epos + epos + 16;
                    469:                                if ((newp = realloc(buf, newsize)) == NULL)
1.47      kjell     470:                                        goto memfail;
1.29      vincent   471:                                buf = newp;
                    472:                                nbuf = newsize;
                    473:                        }
1.47      kjell     474:                        if (!dynbuf && epos + 1 >= nbuf) {
1.56      lum       475:                                dobeep();
1.47      kjell     476:                                ewprintf("Line too long");
                    477:                                return (emptyval);
                    478:                        }
1.38      kjell     479:                        for (i = epos; i > cpos; i--)
                    480:                                buf[i] = buf[i - 1];
                    481:                        buf[cpos++] = (char)c;
                    482:                        epos++;
                    483:                        eputc((char)c);
                    484:                        cc = ttcol;
                    485:                        rr = ttrow;
                    486:                        for (i = cpos; i < epos; i++)
                    487:                                eputc(buf[i]);
                    488:                        ttmove(rr, cc);
                    489:                        ttflush();
1.1       deraadt   490:                }
                    491:        }
1.7       art       492: done:
1.38      kjell     493:        if (cwin == TRUE) {
                    494:                /* blow away cpltion window */
                    495:                bp = bfind("*Completions*", TRUE);
1.49      kjell     496:                if ((wp = popbuf(bp, WEPHEM)) != NULL) {
                    497:                        if (wp->w_flag & WEPHEM) {
                    498:                                curwp = wp;
                    499:                                delwind(FFRAND, 1);
                    500:                        } else {
                    501:                                killbuffer(bp);
                    502:                        }
1.38      kjell     503:                }
                    504:        }
                    505:        return (ret);
1.47      kjell     506: memfail:
                    507:        if (dynbuf && buf)
                    508:                free(buf);
1.56      lum       509:        dobeep();
1.38      kjell     510:        ewprintf("Out of memory");
1.47      kjell     511:        return (emptyval);
1.1       deraadt   512: }
                    513:
                    514: /*
1.31      db        515:  * Do completion on a list of objects.
1.38      kjell     516:  * c is SPACE, TAB, or CR
                    517:  * return TRUE if matched (or partially matched)
                    518:  * FALSE is result is ambiguous,
                    519:  * ABORT on error.
1.1       deraadt   520:  */
1.2       millert   521: static int
1.38      kjell     522: complt(int flags, int c, char *buf, size_t nbuf, int cpos, int *nx)
1.3       millert   523: {
1.40      deraadt   524:        struct list     *lh, *lh2;
                    525:        struct list     *wholelist = NULL;
1.3       millert   526:        int      i, nxtra, nhits, bxtra, msglen, nshown;
                    527:        int      wflag = FALSE;
                    528:        char    *msg;
                    529:
                    530:        lh = lh2 = NULL;
1.2       millert   531:
                    532:        if ((flags & EFFUNC) != 0) {
                    533:                buf[cpos] = '\0';
1.32      otto      534:                wholelist = lh = complete_function_list(buf);
1.9       art       535:        } else if ((flags & EFBUF) != 0) {
1.6       art       536:                lh = &(bheadp->b_list);
1.9       art       537:        } else if ((flags & EFFILE) != 0) {
1.6       art       538:                buf[cpos] = '\0';
                    539:                wholelist = lh = make_file_list(buf);
                    540:        } else
                    541:                panic("broken complt call: flags");
                    542:
                    543:        if (c == ' ')
                    544:                wflag = TRUE;
                    545:        else if (c != '\t' && c != CCHR('M'))
                    546:                panic("broken complt call: c");
                    547:
                    548:        nhits = 0;
                    549:        nxtra = HUGE;
                    550:
                    551:        for (; lh != NULL; lh = lh->l_next) {
                    552:                if (memcmp(buf, lh->l_name, cpos) != 0)
                    553:                        continue;
1.2       millert   554:                if (nhits == 0)
1.6       art       555:                        lh2 = lh;
                    556:                ++nhits;
                    557:                if (lh->l_name[cpos] == '\0')
1.38      kjell     558:                        nxtra = -1; /* exact match */
1.3       millert   559:                else {
1.6       art       560:                        bxtra = getxtra(lh, lh2, cpos, wflag);
                    561:                        if (bxtra < nxtra)
                    562:                                nxtra = bxtra;
                    563:                        lh2 = lh;
                    564:                }
                    565:        }
                    566:        if (nhits == 0)
                    567:                msg = " [No match]";
                    568:        else if (nhits > 1 && nxtra == 0)
1.37      kjell     569:                msg = " [Ambiguous. Ctrl-G to cancel]";
1.6       art       570:        else {
                    571:                /*
                    572:                 * Being lazy - ought to check length, but all things
                    573:                 * autocompleted have known types/lengths.
                    574:                 */
                    575:                if (nxtra < 0 && nhits > 1 && c == ' ')
1.38      kjell     576:                        nxtra = 1; /* ??? */
1.29      vincent   577:                for (i = 0; i < nxtra && cpos < nbuf; ++i) {
1.6       art       578:                        buf[cpos] = lh2->l_name[cpos];
                    579:                        eputc(buf[cpos++]);
1.1       deraadt   580:                }
1.38      kjell     581:                /* XXX should grow nbuf */
1.6       art       582:                ttflush();
                    583:                free_file_list(wholelist);
1.38      kjell     584:                *nx = nxtra;
                    585:                if (nxtra < 0 && c != CCHR('M')) /* exact */
                    586:                        *nx = 0;
                    587:                return (TRUE);
1.1       deraadt   588:        }
1.3       millert   589:
1.2       millert   590:        /*
1.31      db        591:         * wholelist is NULL if we are doing buffers.  Want to free lists
1.2       millert   592:         * that were created for us, but not the buffer list!
                    593:         */
1.1       deraadt   594:        free_file_list(wholelist);
1.3       millert   595:
1.31      db        596:        /* Set up backspaces, etc., being mindful of echo line limit. */
1.1       deraadt   597:        msglen = strlen(msg);
                    598:        nshown = (ttcol + msglen + 2 > ncol) ?
1.2       millert   599:                ncol - ttcol - 2 : msglen;
1.1       deraadt   600:        eputs(msg);
1.2       millert   601:        ttcol -= (i = nshown);  /* update ttcol!                 */
                    602:        while (i--)             /* move back before msg          */
1.1       deraadt   603:                ttputc('\b');
1.2       millert   604:        ttflush();              /* display to user               */
1.1       deraadt   605:        i = nshown;
1.3       millert   606:        while (i--)             /* blank out on next flush       */
1.1       deraadt   607:                eputc(' ');
1.2       millert   608:        ttcol -= (i = nshown);  /* update ttcol on BS's          */
1.1       deraadt   609:        while (i--)
1.2       millert   610:                ttputc('\b');   /* update ttcol again!           */
1.38      kjell     611:        *nx = nxtra;
                    612:        return ((nhits > 0) ? TRUE : FALSE);
1.1       deraadt   613: }
                    614:
                    615: /*
1.31      db        616:  * Do completion on a list of objects, listing instead of completing.
1.1       deraadt   617:  */
1.2       millert   618: static int
1.41      kjell     619: complt_list(int flags, char *buf, int cpos)
1.3       millert   620: {
1.40      deraadt   621:        struct list     *lh, *lh2, *lh3;
                    622:        struct list     *wholelist = NULL;
                    623:        struct buffer   *bp;
1.3       millert   624:        int      i, maxwidth, width;
                    625:        int      preflen = 0;
                    626:        int      oldrow = ttrow;
                    627:        int      oldcol = ttcol;
                    628:        int      oldhue = tthue;
1.17      art       629:        char     *linebuf;
1.26      millert   630:        size_t   linesize, len;
1.43      kjell     631:        char *cp;
1.3       millert   632:
                    633:        lh = NULL;
1.1       deraadt   634:
                    635:        ttflush();
                    636:
1.38      kjell     637:        /* The results are put into a completion buffer. */
                    638:        bp = bfind("*Completions*", TRUE);
1.2       millert   639:        if (bclear(bp) == FALSE)
1.31      db        640:                return (FALSE);
1.2       millert   641:
1.24      vincent   642:        /*
1.31      db        643:         * First get the list of objects.  This list may contain only
1.24      vincent   644:         * the ones that complete what has been typed, or may be the
                    645:         * whole list of all objects of this type.  They are filtered
                    646:         * later in any case.  Set wholelist if the list has been
                    647:         * cons'ed up just for us, so we can free it later.  We have
                    648:         * to copy the buffer list for this function even though we
                    649:         * didn't for complt.  The sorting code does destructive
                    650:         * changes to the list, which we don't want to happen to the
                    651:         * main buffer list!
                    652:         */
                    653:        if ((flags & EFBUF) != 0)
                    654:                wholelist = lh = copy_list(&(bheadp->b_list));
                    655:        else if ((flags & EFFUNC) != 0) {
                    656:                buf[cpos] = '\0';
1.32      otto      657:                wholelist = lh = complete_function_list(buf);
1.24      vincent   658:        } else if ((flags & EFFILE) != 0) {
                    659:                buf[cpos] = '\0';
                    660:                wholelist = lh = make_file_list(buf);
1.2       millert   661:                /*
1.24      vincent   662:                 * We don't want to display stuff up to the / for file
                    663:                 * names preflen is the list of a prefix of what the
                    664:                 * user typed that should not be displayed.
1.2       millert   665:                 */
1.24      vincent   666:                cp = strrchr(buf, '/');
                    667:                if (cp)
                    668:                        preflen = cp - buf + 1;
                    669:        } else
                    670:                panic("broken complt call: flags");
1.1       deraadt   671:
1.24      vincent   672:        /*
                    673:         * Sort the list, since users expect to see it in alphabetic
                    674:         * order.
                    675:         */
                    676:        lh2 = lh;
                    677:        while (lh2 != NULL) {
                    678:                lh3 = lh2->l_next;
                    679:                while (lh3 != NULL) {
                    680:                        if (strcmp(lh2->l_name, lh3->l_name) > 0) {
                    681:                                cp = lh2->l_name;
                    682:                                lh2->l_name = lh3->l_name;
                    683:                                lh3->l_name = cp;
1.2       millert   684:                        }
1.24      vincent   685:                        lh3 = lh3->l_next;
1.2       millert   686:                }
1.24      vincent   687:                lh2 = lh2->l_next;
                    688:        }
1.1       deraadt   689:
1.24      vincent   690:        /*
                    691:         * First find max width of object to be displayed, so we can
                    692:         * put several on a line.
                    693:         */
                    694:        maxwidth = 0;
                    695:        lh2 = lh;
                    696:        while (lh2 != NULL) {
                    697:                for (i = 0; i < cpos; ++i) {
                    698:                        if (buf[i] != lh2->l_name[i])
                    699:                                break;
                    700:                }
                    701:                if (i == cpos) {
                    702:                        width = strlen(lh2->l_name);
                    703:                        if (width > maxwidth)
                    704:                                maxwidth = width;
1.1       deraadt   705:                }
1.24      vincent   706:                lh2 = lh2->l_next;
                    707:        }
                    708:        maxwidth += 1 - preflen;
1.2       millert   709:
1.24      vincent   710:        /*
1.31      db        711:         * Now do the display.  Objects are written into linebuf until
1.24      vincent   712:         * it fills, and then put into the help buffer.
                    713:         */
1.57    ! guenther  714:        linesize = (ncol > maxwidth ? ncol : maxwidth) + 1;
1.54      florian   715:        if ((linebuf = malloc(linesize)) == NULL) {
                    716:                free_file_list(wholelist);
1.31      db        717:                return (FALSE);
1.54      florian   718:        }
1.24      vincent   719:        width = 0;
1.19      vincent   720:
1.25      deraadt   721:        /*
1.24      vincent   722:         * We're going to strlcat() into the buffer, so it has to be
1.31      db        723:         * NUL terminated.
1.24      vincent   724:         */
                    725:        linebuf[0] = '\0';
                    726:        for (lh2 = lh; lh2 != NULL; lh2 = lh2->l_next) {
                    727:                for (i = 0; i < cpos; ++i) {
                    728:                        if (buf[i] != lh2->l_name[i])
                    729:                                break;
1.2       millert   730:                }
1.24      vincent   731:                /* if we have a match */
                    732:                if (i == cpos) {
                    733:                        /* if it wraps */
                    734:                        if ((width + maxwidth) > ncol) {
                    735:                                addline(bp, linebuf);
                    736:                                linebuf[0] = '\0';
                    737:                                width = 0;
                    738:                        }
1.43      kjell     739:                        len = strlcat(linebuf, lh2->l_name + preflen,
                    740:                            linesize);
1.24      vincent   741:                        width += maxwidth;
1.26      millert   742:                        if (len < width && width < linesize) {
                    743:                                /* pad so the objects nicely line up */
                    744:                                memset(linebuf + len, ' ',
                    745:                                    maxwidth - strlen(lh2->l_name + preflen));
                    746:                                linebuf[width] = '\0';
                    747:                        }
1.1       deraadt   748:                }
1.2       millert   749:        }
1.24      vincent   750:        if (width > 0)
                    751:                addline(bp, linebuf);
                    752:        free(linebuf);
                    753:
1.2       millert   754:        /*
                    755:         * Note that we free lists only if they are put in wholelist lists
                    756:         * that were built just for us should be freed.  However when we use
                    757:         * the buffer list, obviously we don't want it freed.
1.1       deraadt   758:         */
                    759:        free_file_list(wholelist);
1.49      kjell     760:        popbuftop(bp, WEPHEM);  /* split the screen and put up the help
1.2       millert   761:                                 * buffer */
1.55      lum       762:        update(CMODE);          /* needed to make the new stuff actually
1.2       millert   763:                                 * appear */
                    764:        ttmove(oldrow, oldcol); /* update leaves cursor in arbitrary place */
                    765:        ttcolor(oldhue);        /* with arbitrary color */
1.1       deraadt   766:        ttflush();
1.31      db        767:        return (0);
1.1       deraadt   768: }
                    769:
                    770: /*
1.3       millert   771:  * The "lp1" and "lp2" point to list structures.  The "cpos" is a horizontal
1.14      mickey    772:  * position in the name.  Return the longest block of characters that can be
                    773:  * autocompleted at this point.  Sometimes the two symbols are the same, but
1.3       millert   774:  * this is normal.
1.2       millert   775:  */
                    776: int
1.40      deraadt   777: getxtra(struct list *lp1, struct list *lp2, int cpos, int wflag)
1.2       millert   778: {
1.3       millert   779:        int     i;
1.1       deraadt   780:
                    781:        i = cpos;
                    782:        for (;;) {
1.2       millert   783:                if (lp1->l_name[i] != lp2->l_name[i])
                    784:                        break;
                    785:                if (lp1->l_name[i] == '\0')
                    786:                        break;
1.1       deraadt   787:                ++i;
1.2       millert   788:                if (wflag && !ISWORD(lp1->l_name[i - 1]))
                    789:                        break;
1.1       deraadt   790:        }
                    791:        return (i - cpos);
                    792: }
                    793:
                    794: /*
1.14      mickey    795:  * Special "printf" for the echo line.  Each call to "ewprintf" starts a
                    796:  * new line in the echo area, and ends with an erase to end of the echo
                    797:  * line.  The formatting is done by a call to the standard formatting
1.3       millert   798:  * routine.
1.1       deraadt   799:  */
1.2       millert   800: /* VARARGS */
1.10      art       801: void
1.2       millert   802: ewprintf(const char *fmt, ...)
1.1       deraadt   803: {
1.3       millert   804:        va_list  ap;
1.1       deraadt   805:
1.2       millert   806:        if (inmacro)
                    807:                return;
1.50      lum       808:
1.2       millert   809:        va_start(ap, fmt);
1.1       deraadt   810:        ttcolor(CTEXT);
1.2       millert   811:        ttmove(nrow - 1, 0);
                    812:        eformat(fmt, ap);
                    813:        va_end(ap);
1.1       deraadt   814:        tteeol();
                    815:        ttflush();
                    816:        epresf = TRUE;
                    817: }
                    818:
                    819: /*
1.14      mickey    820:  * Printf style formatting. This is called by both "ewprintf" and "ereply"
                    821:  * to provide formatting services to their clients.  The move to the start
                    822:  * of the echo line, and the erase to the end of the echo line, is done by
1.48      kjell     823:  * the caller.
                    824:  * %c prints the "name" of the supplied character.
                    825:  * %k prints the name of the current key (and takes no arguments).
                    826:  * %d prints a decimal integer
                    827:  * %o prints an octal integer
                    828:  * %p prints a pointer
                    829:  * %s prints a string
                    830:  * %ld prints a long word
                    831:  * Anything else is echoed verbatim
1.1       deraadt   832:  */
1.10      art       833: static void
1.15      mickey    834: eformat(const char *fp, va_list ap)
1.1       deraadt   835: {
1.27      vincent   836:        char    kname[NKNAME], tmp[100], *cp;
1.12      mickey    837:        int     c;
1.1       deraadt   838:
                    839:        while ((c = *fp++) != '\0') {
                    840:                if (c != '%')
                    841:                        eputc(c);
                    842:                else {
                    843:                        c = *fp++;
                    844:                        switch (c) {
                    845:                        case 'c':
1.48      kjell     846:                                getkeyname(kname, sizeof(kname),
                    847:                                    va_arg(ap, int));
1.1       deraadt   848:                                eputs(kname);
                    849:                                break;
                    850:
                    851:                        case 'k':
1.12      mickey    852:                                for (cp = kname, c = 0; c < key.k_count; c++) {
                    853:                                        if (c)
                    854:                                                *cp++ = ' ';
1.42      kjell     855:                                        cp = getkeyname(cp, sizeof(kname) -
1.12      mickey    856:                                            (cp - kname) - 1, key.k_chars[c]);
1.1       deraadt   857:                                }
                    858:                                eputs(kname);
                    859:                                break;
                    860:
                    861:                        case 'd':
1.2       millert   862:                                eputi(va_arg(ap, int), 10);
1.1       deraadt   863:                                break;
                    864:
                    865:                        case 'o':
1.2       millert   866:                                eputi(va_arg(ap, int), 8);
1.27      vincent   867:                                break;
                    868:
                    869:                        case 'p':
1.31      db        870:                                snprintf(tmp, sizeof(tmp), "%p",
1.27      vincent   871:                                    va_arg(ap, void *));
                    872:                                eputs(tmp);
1.1       deraadt   873:                                break;
                    874:
                    875:                        case 's':
1.2       millert   876:                                eputs(va_arg(ap, char *));
1.1       deraadt   877:                                break;
                    878:
1.3       millert   879:                        case 'l':
                    880:                                /* explicit longword */
1.1       deraadt   881:                                c = *fp++;
1.2       millert   882:                                switch (c) {
1.1       deraadt   883:                                case 'd':
1.13      mickey    884:                                        eputl(va_arg(ap, long), 10);
1.1       deraadt   885:                                        break;
                    886:                                default:
                    887:                                        eputc(c);
                    888:                                        break;
                    889:                                }
                    890:                                break;
                    891:
                    892:                        default:
                    893:                                eputc(c);
                    894:                        }
                    895:                }
                    896:        }
                    897: }
                    898:
                    899: /*
                    900:  * Put integer, in radix "r".
                    901:  */
1.10      art       902: static void
1.21      vincent   903: eputi(int i, int r)
1.1       deraadt   904: {
1.3       millert   905:        int      q;
1.1       deraadt   906:
1.2       millert   907:        if (i < 0) {
                    908:                eputc('-');
                    909:                i = -i;
1.1       deraadt   910:        }
1.2       millert   911:        if ((q = i / r) != 0)
1.1       deraadt   912:                eputi(q, r);
1.2       millert   913:        eputc(i % r + '0');
1.1       deraadt   914: }
                    915:
                    916: /*
                    917:  * Put long, in radix "r".
                    918:  */
1.10      art       919: static void
1.21      vincent   920: eputl(long l, int r)
1.1       deraadt   921: {
1.3       millert   922:        long     q;
1.1       deraadt   923:
1.2       millert   924:        if (l < 0) {
                    925:                eputc('-');
                    926:                l = -l;
1.1       deraadt   927:        }
1.2       millert   928:        if ((q = l / r) != 0)
1.1       deraadt   929:                eputl(q, r);
1.3       millert   930:        eputc((int)(l % r) + '0');
1.1       deraadt   931: }
                    932:
                    933: /*
                    934:  * Put string.
                    935:  */
1.10      art       936: static void
1.21      vincent   937: eputs(const char *s)
1.1       deraadt   938: {
1.3       millert   939:        int      c;
1.1       deraadt   940:
                    941:        while ((c = *s++) != '\0')
                    942:                eputc(c);
                    943: }
                    944:
                    945: /*
1.14      mickey    946:  * Put character.  Watch for control characters, and for the line getting
1.3       millert   947:  * too long.
1.1       deraadt   948:  */
1.10      art       949: static void
1.21      vincent   950: eputc(char c)
1.1       deraadt   951: {
1.2       millert   952:        if (ttcol + 2 < ncol) {
1.1       deraadt   953:                if (ISCTRL(c)) {
                    954:                        eputc('^');
                    955:                        c = CCHR(c);
                    956:                }
                    957:                ttputc(c);
                    958:                ++ttcol;
                    959:        }
                    960: }
                    961:
1.10      art       962: void
1.40      deraadt   963: free_file_list(struct list *lp)
1.1       deraadt   964: {
1.40      deraadt   965:        struct list     *next;
1.2       millert   966:
                    967:        while (lp) {
                    968:                next = lp->l_next;
1.43      kjell     969:                free(lp->l_name);
1.2       millert   970:                free(lp);
                    971:                lp = next;
                    972:        }
1.1       deraadt   973: }
                    974:
1.40      deraadt   975: static struct list *
                    976: copy_list(struct list *lp)
1.2       millert   977: {
1.40      deraadt   978:        struct list     *current, *last, *nxt;
1.2       millert   979:
                    980:        last = NULL;
                    981:        while (lp) {
1.45      kjell     982:                current = malloc(sizeof(struct list));
1.23      vincent   983:                if (current == NULL) {
1.43      kjell     984:                        /* Free what we have allocated so far */
1.23      vincent   985:                        for (current = last; current; current = nxt) {
                    986:                                nxt = current->l_next;
1.43      kjell     987:                                free(current->l_name);
1.23      vincent   988:                                free(current);
                    989:                        }
1.28      vincent   990:                        return (NULL);
1.23      vincent   991:                }
1.2       millert   992:                current->l_next = last;
1.43      kjell     993:                current->l_name = strdup(lp->l_name);
1.28      vincent   994:                last = current;
1.2       millert   995:                lp = lp->l_next;
                    996:        }
                    997:        return (last);
1.1       deraadt   998: }