[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.2

1.1       deraadt     1: /*
                      2:  *             Echo line reading and writing.
                      3:  *
                      4:  * Common routines for reading
                      5:  * and writing characters in the echo line area
                      6:  * of the display screen. Used by the entire
                      7:  * known universe.
                      8:  */
                      9: #include       "def.h"
                     10: #include       "key.h"
1.2     ! millert    11: #ifdef __STDC__
        !            12: #include       <stdarg.h>
1.1       deraadt    13: #else
                     14: #include       <varargs.h>
                     15: #endif
                     16: #ifndef NO_MACRO
1.2     ! millert    17: #include       "macro.h"
1.1       deraadt    18: #endif
                     19:
1.2     ! millert    20: static VOID     eformat                __P((const char *, va_list));
        !            21: static int     veread          __P((const char *, char *buf, int, int, va_list));
        !            22: static VOID     eputi          __P((int, int));
        !            23: static VOID     eputl          __P((long, int));
        !            24: static VOID     eputs          __P((char *));
        !            25: static VOID     eputc          __P((char));
        !            26: static int      complt         __P((int, int, char *, int));
        !            27: static int      complt_list    __P((int, int, char *, int));
        !            28: static LIST    *copy_list      __P((LIST *));
        !            29: static VOID    free_file_list  __P((LIST *));
1.1       deraadt    30:
1.2     ! millert    31: int             epresf = FALSE;                /* Stuff in echo line flag.      */
1.1       deraadt    32:
                     33: /*
                     34:  * Erase the echo line.
                     35:  */
                     36: VOID
1.2     ! millert    37: eerase()
        !            38: {
        !            39:
1.1       deraadt    40:        ttcolor(CTEXT);
1.2     ! millert    41:        ttmove(nrow - 1, 0);
1.1       deraadt    42:        tteeol();
                     43:        ttflush();
                     44:        epresf = FALSE;
                     45: }
                     46:
                     47: /*
                     48:  * Ask "yes" or "no" question.
                     49:  * Return ABORT if the user answers the question
                     50:  * with the abort ("^G") character. Return FALSE
                     51:  * for "no" and TRUE for "yes". No formatting
                     52:  * services are available. No newline required.
                     53:  */
1.2     ! millert    54: int
        !            55: eyorn(sp)
        !            56:        char  *sp;
        !            57: {
        !            58:        int    s;
1.1       deraadt    59:
                     60: #ifndef NO_MACRO
1.2     ! millert    61:        if (inmacro)
        !            62:                return TRUE;
1.1       deraadt    63: #endif
                     64:        ewprintf("%s? (y or n) ", sp);
                     65:        for (;;) {
                     66:                s = getkey(FALSE);
1.2     ! millert    67:                if (s == 'y' || s == 'Y')
        !            68:                        return TRUE;
        !            69:                if (s == 'n' || s == 'N')
        !            70:                        return FALSE;
        !            71:                if (s == CCHR('G'))
        !            72:                        return ctrlg(FFRAND, 1);
1.1       deraadt    73:                ewprintf("Please answer y or n.  %s? (y or n) ", sp);
                     74:        }
1.2     ! millert    75:        /* NOTREACHED */
1.1       deraadt    76: }
                     77:
                     78: /*
                     79:  * Like eyorn, but for more important question. User must type either all of
                     80:  * "yes" or "no", and the trainling newline.
                     81:  */
1.2     ! millert    82: int
        !            83: eyesno(sp)
        !            84:        char  *sp;
        !            85: {
        !            86:        int    s;
        !            87:        char   buf[64];
1.1       deraadt    88:
                     89: #ifndef NO_MACRO
1.2     ! millert    90:        if (inmacro)
        !            91:                return TRUE;
1.1       deraadt    92: #endif
                     93:        s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
                     94:        for (;;) {
1.2     ! millert    95:                if (s == ABORT)
        !            96:                        return ABORT;
1.1       deraadt    97:                if (s != FALSE) {
                     98: #ifndef NO_MACRO
                     99:                        if (macrodef) {
1.2     ! millert   100:                                LINE           *lp = maclcur;
1.1       deraadt   101:
1.2     ! millert   102:                                maclcur = lp->l_bp;
        !           103:                                maclcur->l_fp = lp->l_fp;
        !           104:                                free((char *) lp);
1.1       deraadt   105:                        }
                    106: #endif
                    107:                        if ((buf[0] == 'y' || buf[0] == 'Y')
1.2     ! millert   108:                            && (buf[1] == 'e' || buf[1] == 'E')
        !           109:                            && (buf[2] == 's' || buf[2] == 'S')
        !           110:                            && (buf[3] == '\0'))
        !           111:                                return TRUE;
1.1       deraadt   112:                        if ((buf[0] == 'n' || buf[0] == 'N')
1.2     ! millert   113:                            && (buf[1] == 'o' || buf[0] == 'O')
        !           114:                            && (buf[2] == '\0'))
        !           115:                                return FALSE;
1.1       deraadt   116:                }
                    117:                s = ereply("Please answer yes or no.  %s? (yes or no) ",
                    118:                           buf, sizeof(buf), sp);
                    119:        }
1.2     ! millert   120:        /* NOTREACHED */
1.1       deraadt   121: }
1.2     ! millert   122:
1.1       deraadt   123: /*
                    124:  * Write out a prompt, and read back a
                    125:  * reply. The prompt is now written out with full "ewprintf"
                    126:  * formatting, although the arguments are in a rather strange
                    127:  * place. This is always a new message, there is no auto
                    128:  * completion, and the return is echoed as such.
                    129:  */
1.2     ! millert   130: /* VARARGS */
        !           131: int
        !           132: #ifdef __STDC__
        !           133: ereply(const char *fmt, char *buf, int nbuf, ...)
        !           134: #else
1.1       deraadt   135: ereply(va_alist)
1.2     ! millert   136:        va_dcl
        !           137: #endif
1.1       deraadt   138: {
1.2     ! millert   139:        va_list         ap;
        !           140:        int    i;
        !           141: #ifdef __STDC__
        !           142:        va_start(ap, nbuf);
        !           143: #else
        !           144:        char  *fmt, *buf;
        !           145:        int    nbuf;
        !           146:
        !           147:        va_start(ap);
        !           148:        fmt = va_arg(ap, char *);
        !           149:        buf = va_arg(ap, char *);
        !           150:        nbuf = va_arg(ap, int);
        !           151: #endif
        !           152:        i = veread(fmt, buf, nbuf, EFNEW | EFCR, ap);
        !           153:        va_end(ap);
1.1       deraadt   154:        return i;
                    155: }
                    156:
                    157: /*
                    158:  * This is the general "read input from the
                    159:  * echo line" routine. The basic idea is that the prompt
                    160:  * string "prompt" is written to the echo line, and a one
                    161:  * line reply is read back into the supplied "buf" (with
                    162:  * maximum length "len"). The "flag" contains EFNEW (a
                    163:  * new prompt), an EFFUNC (autocomplete), or EFCR (echo
                    164:  * the carriage return as CR).
                    165:  */
1.2     ! millert   166: /* VARARGS */
        !           167: int
        !           168: #ifdef __STDC__
        !           169: eread(const char *fmt, char *buf, int nbuf, int flag, ...)
        !           170: #else
1.1       deraadt   171: eread(va_alist)
1.2     ! millert   172:        char *fmt;
        !           173:        char *buf;
        !           174:        int nbuf;
        !           175:        int flag;
        !           176:        va_dcl
        !           177: #endif
1.1       deraadt   178: {
1.2     ! millert   179:        int             i;
        !           180:        va_list         ap;
        !           181: #ifdef __STDC__
        !           182:        va_start(ap, flag);
        !           183: #else
        !           184:        char  *fmt, *buf;
        !           185:        int    nbuf;
        !           186:
        !           187:        va_start(ap);
        !           188:        fmt = va_arg(ap, char *);
        !           189:        buf = va_arg(ap, char *);
        !           190:        nbuf = va_arg(ap, int);
        !           191:        flag = va_arg(ap, int);
        !           192: #endif
        !           193:        i = veread(fmt, buf, nbuf, flag, ap);
        !           194:        va_end(ap);
1.1       deraadt   195:        return i;
                    196: }
                    197:
1.2     ! millert   198: static int
        !           199: veread(fp, buf, nbuf, flag, ap)
        !           200:        const char *fp;
        !           201:        char       *buf;
        !           202:        int         nbuf;
        !           203:        int         flag;
        !           204:        va_list     ap;
        !           205: {
        !           206:        int         cpos;
        !           207:        int         i;
        !           208:        int         c;
1.1       deraadt   209:
                    210: #ifndef NO_MACRO
1.2     ! millert   211:        if (inmacro) {
        !           212:                bcopy(maclcur->l_text, buf, maclcur->l_used);
        !           213:                buf[maclcur->l_used] = '\0';
        !           214:                maclcur = maclcur->l_fp;
        !           215:                return TRUE;
1.1       deraadt   216:        }
                    217: #endif
                    218:        cpos = 0;
1.2     ! millert   219:        if ((flag & EFNEW) != 0 || ttrow != nrow - 1) {
1.1       deraadt   220:                ttcolor(CTEXT);
1.2     ! millert   221:                ttmove(nrow - 1, 0);
1.1       deraadt   222:                epresf = TRUE;
                    223:        } else
                    224:                eputc(' ');
                    225:        eformat(fp, ap);
                    226:        tteeol();
                    227:        ttflush();
                    228:        for (;;) {
                    229:                c = getkey(FALSE);
1.2     ! millert   230:                if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
1.1       deraadt   231:                        cpos += complt(flag, c, buf, cpos);
                    232:                        continue;
                    233:                }
1.2     ! millert   234:                if ((flag & EFAUTO) != 0 && c == '?') {
1.1       deraadt   235:                        complt_list(flag, c, buf, cpos);
                    236:                        continue;
                    237:                }
                    238:                switch (c) {
1.2     ! millert   239:                case CCHR('J'):
        !           240:                        c = CCHR('M');  /* and continue          */
        !           241:                case CCHR('M'):/* Return, done.  */
        !           242:                        if ((flag & EFFUNC) != 0) {
1.1       deraadt   243:                                if ((i = complt(flag, c, buf, cpos)) == 0)
                    244:                                        continue;
1.2     ! millert   245:                                if (i > 0)
        !           246:                                        cpos += i;
1.1       deraadt   247:                        }
                    248:                        buf[cpos] = '\0';
1.2     ! millert   249:                        if ((flag & EFCR) != 0) {
1.1       deraadt   250:                                ttputc(CCHR('M'));
                    251:                                ttflush();
                    252:                        }
                    253: #ifndef NO_MACRO
1.2     ! millert   254:                        if (macrodef) {
        !           255:                                LINE           *lp;
1.1       deraadt   256:
1.2     ! millert   257:                                if ((lp = lalloc(cpos)) == NULL)
        !           258:                                        return FALSE;
        !           259:                                lp->l_fp = maclcur->l_fp;
        !           260:                                maclcur->l_fp = lp;
        !           261:                                lp->l_bp = maclcur;
        !           262:                                maclcur = lp;
        !           263:                                bcopy(buf, lp->l_text, cpos);
1.1       deraadt   264:                        }
                    265: #endif
                    266:                        goto done;
                    267:
1.2     ! millert   268:                case CCHR('G'): /* Bell, abort.          */
1.1       deraadt   269:                        eputc(CCHR('G'));
                    270:                        (VOID) ctrlg(FFRAND, 0);
                    271:                        ttflush();
                    272:                        return ABORT;
                    273:
1.2     ! millert   274:                case CCHR('H'):
        !           275:                case CCHR('?'): /* Rubout, erase.        */
1.1       deraadt   276:                        if (cpos != 0) {
                    277:                                ttputc('\b');
                    278:                                ttputc(' ');
                    279:                                ttputc('\b');
                    280:                                --ttcol;
                    281:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    282:                                        ttputc('\b');
                    283:                                        ttputc(' ');
                    284:                                        ttputc('\b');
                    285:                                        --ttcol;
                    286:                                }
                    287:                                ttflush();
                    288:                        }
                    289:                        break;
                    290:
1.2     ! millert   291:                case CCHR('X'): /* C-X                   */
        !           292:                case CCHR('U'): /* C-U, kill line.       */
1.1       deraadt   293:                        while (cpos != 0) {
                    294:                                ttputc('\b');
                    295:                                ttputc(' ');
                    296:                                ttputc('\b');
                    297:                                --ttcol;
                    298:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    299:                                        ttputc('\b');
                    300:                                        ttputc(' ');
                    301:                                        ttputc('\b');
                    302:                                        --ttcol;
                    303:                                }
                    304:                        }
                    305:                        ttflush();
                    306:                        break;
                    307:
1.2     ! millert   308:                case CCHR('W'): /* C-W, kill to beginning of */
        !           309:                        /* previous word         */
1.1       deraadt   310:                        /* back up to first word character or beginning */
                    311:                        while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
                    312:                                ttputc('\b');
                    313:                                ttputc(' ');
                    314:                                ttputc('\b');
                    315:                                --ttcol;
                    316:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    317:                                        ttputc('\b');
                    318:                                        ttputc(' ');
                    319:                                        ttputc('\b');
                    320:                                        --ttcol;
                    321:                                }
                    322:                        }
                    323:                        while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
                    324:                                ttputc('\b');
                    325:                                ttputc(' ');
                    326:                                ttputc('\b');
                    327:                                --ttcol;
                    328:                                if (ISCTRL(buf[--cpos]) != FALSE) {
                    329:                                        ttputc('\b');
                    330:                                        ttputc(' ');
                    331:                                        ttputc('\b');
                    332:                                        --ttcol;
                    333:                                }
                    334:                        }
                    335:                        ttflush();
                    336:                        break;
                    337:
1.2     ! millert   338:                case CCHR('\\'):
        !           339:                case CCHR('Q'): /* C-Q, quote next       */
        !           340:                        c = getkey(FALSE);      /* and continue          */
        !           341:                default:        /* All the rest.         */
        !           342:                        if (cpos < nbuf - 1) {
1.1       deraadt   343:                                buf[cpos++] = (char) c;
                    344:                                eputc((char) c);
                    345:                                ttflush();
                    346:                        }
                    347:                }
                    348:        }
                    349: done:  return buf[0] != '\0';
                    350: }
                    351:
                    352: /*
                    353:  * do completion on a list of objects.
                    354:  */
1.2     ! millert   355: static int
        !           356: complt(flags, c, buf, cpos)
        !           357:        int    flags;
        !           358:        int    c;
        !           359:        char  *buf;
        !           360:        int    cpos;
        !           361: {
        !           362:        LIST  *lh, *lh2;
        !           363:        LIST  *wholelist = NULL;
        !           364:        int    i, nxtra;
        !           365:        int    nhits, bxtra;
        !           366:        int    wflag = FALSE;
        !           367:        int    msglen, nshown;
        !           368:        char  *msg;
        !           369:
        !           370:        if ((flags & EFFUNC) != 0) {
        !           371:                buf[cpos] = '\0';
        !           372:                i = complete_function(buf, c);
        !           373:                if (i > 0) {
        !           374:                        eputs(&buf[cpos]);
        !           375:                        ttflush();
        !           376:                        return i;
        !           377:                }
        !           378:                switch (i) {
1.1       deraadt   379:                case -3:
1.2     ! millert   380:                        msg = " [Ambiguous]";
        !           381:                        break;
1.1       deraadt   382:                case -2:
1.2     ! millert   383:                        i = 0;
        !           384:                        msg = " [No match]";
        !           385:                        break;
1.1       deraadt   386:                case -1:
                    387:                case 0:
1.2     ! millert   388:                        return i;
1.1       deraadt   389:                default:
1.2     ! millert   390:                        msg = " [Internal error]";
        !           391:                        break;
        !           392:                }
1.1       deraadt   393:        } else {
1.2     ! millert   394:                if ((flags & EFBUF) != 0)
        !           395:                        lh = &(bheadp->b_list);
        !           396:                else if ((flags & EFFILE) != 0) {
        !           397:                        buf[cpos] = '\0';
        !           398:                        wholelist = lh = make_file_list(buf, 0);
        !           399:                } else
        !           400:                        panic("broken complt call: flags");
        !           401:
        !           402:                if (c == ' ')
        !           403:                        wflag = TRUE;
        !           404:                else if (c != '\t' && c != CCHR('M'))
        !           405:                        panic("broken complt call: c");
        !           406:
        !           407:                nhits = 0;
        !           408:                nxtra = HUGE;
        !           409:
        !           410:                while (lh != NULL) {
        !           411:                        for (i = 0; i < cpos; ++i) {
        !           412:                                if (buf[i] != lh->l_name[i])
        !           413:                                        break;
        !           414:                        }
        !           415:                        if (i == cpos) {
        !           416:                                if (nhits == 0)
        !           417:                                        lh2 = lh;
        !           418:                                ++nhits;
        !           419:                                if (lh->l_name[i] == '\0')
        !           420:                                        nxtra = -1;
        !           421:                                else {
        !           422:                                        bxtra = getxtra(lh, lh2, cpos, wflag);
        !           423:                                        if (bxtra < nxtra)
        !           424:                                                nxtra = bxtra;
        !           425:                                        lh2 = lh;
        !           426:                                }
        !           427:                        }
        !           428:                        lh = lh->l_next;
        !           429:                }
        !           430:                if (nhits == 0)
        !           431:                        msg = " [No match]";
        !           432:                else if (nhits > 1 && nxtra == 0)
        !           433:                        msg = " [Ambiguous]";
        !           434:                else {          /* Got a match, do it to it */
        !           435:                        /*
        !           436:                         * Being lazy - ought to check length, but all things
        !           437:                         * autocompleted have known types/lengths.
        !           438:                         */
        !           439:                        if (nxtra < 0 && nhits > 1 && c == ' ')
        !           440:                                nxtra = 1;
        !           441:                        for (i = 0; i < nxtra; ++i) {
        !           442:                                buf[cpos] = lh2->l_name[cpos];
        !           443:                                eputc(buf[cpos++]);
        !           444:                        }
        !           445:                        ttflush();
        !           446:                        free_file_list(wholelist);
        !           447:                        if (nxtra < 0 && c != CCHR('M'))
        !           448:                                return 0;
        !           449:                        return nxtra;
1.1       deraadt   450:                }
                    451:        }
1.2     ! millert   452:        /*
        !           453:         * wholelist is null if we are doing buffers.  want to free lists
        !           454:         * that were created for us, but not the buffer list!
        !           455:         */
1.1       deraadt   456:        free_file_list(wholelist);
                    457:        /* Set up backspaces, etc., being mindful of echo line limit */
                    458:        msglen = strlen(msg);
                    459:        nshown = (ttcol + msglen + 2 > ncol) ?
1.2     ! millert   460:                ncol - ttcol - 2 : msglen;
1.1       deraadt   461:        eputs(msg);
1.2     ! millert   462:        ttcol -= (i = nshown);  /* update ttcol!                 */
        !           463:        while (i--)             /* move back before msg          */
1.1       deraadt   464:                ttputc('\b');
1.2     ! millert   465:        ttflush();              /* display to user               */
1.1       deraadt   466:        i = nshown;
1.2     ! millert   467:        while (i--)             /* blank out    on next flush    */
1.1       deraadt   468:                eputc(' ');
1.2     ! millert   469:        ttcol -= (i = nshown);  /* update ttcol on BS's          */
1.1       deraadt   470:        while (i--)
1.2     ! millert   471:                ttputc('\b');   /* update ttcol again!           */
1.1       deraadt   472:        return 0;
                    473: }
                    474:
                    475: /*
                    476:  * do completion on a list of objects, listing instead of completing
                    477:  */
1.2     ! millert   478: static int
        !           479: complt_list(flags, c, buf, cpos)
        !           480:        int     flags;
        !           481:        int     c;
        !           482:        char   *buf;
        !           483:        int     cpos;
        !           484: {
        !           485:        LIST   *lh, *lh2, *lh3;
        !           486:        LIST   *wholelist = NULL;
        !           487:        int     i, maxwidth, width;
        !           488:        int     preflen = 0;
        !           489:        BUFFER *bp;
        !           490:        int     oldrow = ttrow;
        !           491:        int     oldcol = ttcol;
        !           492:        int     oldhue = tthue;
        !           493:        char    linebuf[NCOL + 1];
        !           494:        char   *cp;
1.1       deraadt   495:
                    496:        ttflush();
                    497:
                    498:        /* the results are put into a help buffer */
1.2     ! millert   499:        bp = bfind("*help*", TRUE);
        !           500:        if (bclear(bp) == FALSE)
        !           501:                return FALSE;
        !           502:
        !           503:        {       /* this {} present for historical reasons */
        !           504:
        !           505:                /*
        !           506:                 * first get the list of objects.  This list may contain only
        !           507:                 * the ones that complete what has been typed, or may be the
        !           508:                 * whole list of all objects of this type.  They are filtered
        !           509:                 * later in any case.  Set wholelist if the list has been
        !           510:                 * cons'ed up just for us, so we can free it later.  We have
        !           511:                 * to copy the buffer list for this function even though we
        !           512:                 * didn't for complt.  The sorting code does destructive
        !           513:                 * changes to the list, which we don't want to happen to the
        !           514:                 * main buffer list!
        !           515:                 */
        !           516:                if ((flags & EFBUF) != 0)
        !           517:                        wholelist = lh = copy_list(&(bheadp->b_list));
        !           518:                else if ((flags & EFFUNC) != 0) {
        !           519:                        buf[cpos] = '\0';
        !           520:                        wholelist = lh = complete_function_list(buf, c);
        !           521:                } else if ((flags & EFFILE) != 0) {
        !           522:                        buf[cpos] = '\0';
        !           523:                        wholelist = lh = make_file_list(buf, 1);
        !           524:                        /*
        !           525:                         * We don't want to display stuff up to the / for file
        !           526:                         * names preflen is the list of a prefix of what the
        !           527:                         * user typed that should not be displayed.
        !           528:                         */
        !           529:                        cp = strrchr(buf, '/');
        !           530:                        if (cp)
        !           531:                                preflen = cp - buf + 1;
        !           532:                } else
        !           533:                        panic("broken complt call: flags");
1.1       deraadt   534:
                    535:
1.2     ! millert   536:                /*
        !           537:                 * Sort the list, since users expect to see it in alphabetic
        !           538:                 * order.
        !           539:                 */
        !           540:                lh2 = lh;
        !           541:                while (lh2) {
        !           542:                        lh3 = lh2->l_next;
        !           543:                        while (lh3) {
        !           544:                                if (strcmp(lh2->l_name, lh3->l_name) > 0) {
        !           545:                                        cp = lh2->l_name;
        !           546:                                        lh2->l_name = lh3->l_name;
        !           547:                                        lh3->l_name = cp;
        !           548:                                }
        !           549:                                lh3 = lh3->l_next;
        !           550:                        }
        !           551:                        lh2 = lh2->l_next;
        !           552:                }
1.1       deraadt   553:
                    554:                /*
1.2     ! millert   555:                 * First find max width of object to be displayed, so we can
        !           556:                 * put several on a line.
1.1       deraadt   557:                 */
1.2     ! millert   558:                maxwidth = 0;
        !           559:                lh2 = lh;
        !           560:                while (lh2 != NULL) {
        !           561:                        for (i = 0; i < cpos; ++i) {
        !           562:                                if (buf[i] != lh2->l_name[i])
        !           563:                                        break;
        !           564:                        }
        !           565:                        if (i == cpos) {
        !           566:                                width = strlen(lh2->l_name);
        !           567:                                if (width > maxwidth)
        !           568:                                        maxwidth = width;
        !           569:                        }
        !           570:                        lh2 = lh2->l_next;
1.1       deraadt   571:                }
1.2     ! millert   572:                maxwidth += 1 - preflen;
        !           573:
        !           574:                /*
        !           575:                 * Now do the display.  objects are written into linebuf until
        !           576:                 * it fills, and then put into the help buffer.
        !           577:                 */
        !           578:                cp = linebuf;
        !           579:                width = 0;
        !           580:                lh2 = lh;
        !           581:                while (lh2 != NULL) {
        !           582:                        for (i = 0; i < cpos; ++i) {
        !           583:                                if (buf[i] != lh2->l_name[i])
        !           584:                                        break;
        !           585:                        }
        !           586:                        if (i == cpos) {
        !           587:                                if ((width + maxwidth) > ncol) {
        !           588:                                        *cp = 0;
        !           589:                                        addline(bp, linebuf);
        !           590:                                        cp = linebuf;
        !           591:                                        width = 0;
        !           592:                                }
        !           593:                                strcpy(cp, lh2->l_name + preflen);
        !           594:                                i = strlen(lh2->l_name + preflen);
        !           595:                                cp += i;
        !           596:                                for (; i < maxwidth; i++)
        !           597:                                        *cp++ = ' ';
        !           598:                                width += maxwidth;
        !           599:                        }
        !           600:                        lh2 = lh2->l_next;
        !           601:                }
        !           602:                if (width > 0) {
        !           603:                        *cp = 0;
        !           604:                        addline(bp, linebuf);
1.1       deraadt   605:                }
1.2     ! millert   606:        }
        !           607:        /*
        !           608:         * Note that we free lists only if they are put in wholelist lists
        !           609:         * that were built just for us should be freed.  However when we use
        !           610:         * the buffer list, obviously we don't want it freed.
1.1       deraadt   611:         */
                    612:        free_file_list(wholelist);
1.2     ! millert   613:        popbuftop(bp);          /* split the screen and put up the help
        !           614:                                 * buffer */
        !           615:        update();               /* needed to make the new stuff actually
        !           616:                                 * appear */
        !           617:        ttmove(oldrow, oldcol); /* update leaves cursor in arbitrary place */
        !           618:        ttcolor(oldhue);        /* with arbitrary color */
1.1       deraadt   619:        ttflush();
                    620:        return 0;
                    621: }
                    622:
                    623: /*
                    624:  * The "lp1" and "lp2" point to list structures. The
                    625:  * "cpos" is a horizontal position in the name.
                    626:  * Return the longest block of characters that can be
                    627:  * autocompleted at this point. Sometimes the two
                    628:  * symbols are the same, but this is normal.
1.2     ! millert   629:  */
        !           630: int
        !           631: getxtra(lp1, lp2, cpos, wflag)
        !           632:        LIST  *lp1, *lp2;
        !           633:        int    cpos;
        !           634:        int    wflag;
        !           635: {
        !           636:        int    i;
1.1       deraadt   637:
                    638:        i = cpos;
                    639:        for (;;) {
1.2     ! millert   640:                if (lp1->l_name[i] != lp2->l_name[i])
        !           641:                        break;
        !           642:                if (lp1->l_name[i] == '\0')
        !           643:                        break;
1.1       deraadt   644:                ++i;
1.2     ! millert   645:                if (wflag && !ISWORD(lp1->l_name[i - 1]))
        !           646:                        break;
1.1       deraadt   647:        }
                    648:        return (i - cpos);
                    649: }
                    650:
                    651: /*
                    652:  * Special "printf" for the echo line.
                    653:  * Each call to "ewprintf" starts a new line in the
                    654:  * echo area, and ends with an erase to end of the
                    655:  * echo line. The formatting is done by a call
                    656:  * to the standard formatting routine.
                    657:  */
1.2     ! millert   658: /* VARARGS */
1.1       deraadt   659: VOID
1.2     ! millert   660: #ifdef __STDC__
        !           661: ewprintf(const char *fmt, ...)
        !           662: #else
1.1       deraadt   663: ewprintf(va_alist)
1.2     ! millert   664:        va_dcl
        !           665: #endif
1.1       deraadt   666: {
1.2     ! millert   667:        va_list         ap;
        !           668: #ifndef __STDC__
        !           669:        char          *fmt;
        !           670: #endif
1.1       deraadt   671:
                    672: #ifndef NO_MACRO
1.2     ! millert   673:        if (inmacro)
        !           674:                return;
        !           675: #endif
        !           676: #ifdef __STDC__
        !           677:        va_start(ap, fmt);
        !           678: #else
        !           679:        va_start(ap);
        !           680:        fmt = va_arg(ap, char *);
1.1       deraadt   681: #endif
                    682:        ttcolor(CTEXT);
1.2     ! millert   683:        ttmove(nrow - 1, 0);
        !           684:        eformat(fmt, ap);
        !           685:        va_end(ap);
1.1       deraadt   686:        tteeol();
                    687:        ttflush();
                    688:        epresf = TRUE;
                    689: }
                    690:
                    691: /*
                    692:  * Printf style formatting. This is
                    693:  * called by both "ewprintf" and "ereply" to provide
                    694:  * formatting services to their clients. The move to the
                    695:  * start of the echo line, and the erase to the end of
                    696:  * the echo line, is done by the caller.
                    697:  * Note: %c works, and prints the "name" of the character.
                    698:  * %k prints the name of a key (and takes no arguments).
                    699:  */
                    700: static VOID
                    701: eformat(fp, ap)
1.2     ! millert   702:        const char  *fp;
        !           703:        va_list ap;
1.1       deraadt   704: {
1.2     ! millert   705:        int    c;
        !           706:        char   kname[NKNAME];
        !           707:        char  *cp;
1.1       deraadt   708:
                    709:        while ((c = *fp++) != '\0') {
                    710:                if (c != '%')
                    711:                        eputc(c);
                    712:                else {
                    713:                        c = *fp++;
                    714:                        switch (c) {
                    715:                        case 'c':
1.2     ! millert   716:                                (VOID) keyname(kname, va_arg(ap, int));
1.1       deraadt   717:                                eputs(kname);
                    718:                                break;
                    719:
                    720:                        case 'k':
                    721:                                cp = kname;
1.2     ! millert   722:                                for (c = 0; c < key.k_count; c++) {
        !           723:                                        cp = keyname(cp, key.k_chars[c]);
        !           724:                                        *cp++ = ' ';
1.1       deraadt   725:                                }
                    726:                                *--cp = '\0';
                    727:                                eputs(kname);
                    728:                                break;
                    729:
                    730:                        case 'd':
1.2     ! millert   731:                                eputi(va_arg(ap, int), 10);
1.1       deraadt   732:                                break;
                    733:
                    734:                        case 'o':
1.2     ! millert   735:                                eputi(va_arg(ap, int), 8);
1.1       deraadt   736:                                break;
                    737:
                    738:                        case 's':
1.2     ! millert   739:                                eputs(va_arg(ap, char *));
1.1       deraadt   740:                                break;
                    741:
1.2     ! millert   742:                        case 'l':       /* explicit longword */
1.1       deraadt   743:                                c = *fp++;
1.2     ! millert   744:                                switch (c) {
1.1       deraadt   745:                                case 'd':
1.2     ! millert   746:                                        eputl((long) va_arg(ap, long), 10);
1.1       deraadt   747:                                        break;
                    748:                                default:
                    749:                                        eputc(c);
                    750:                                        break;
                    751:                                }
                    752:                                break;
                    753:
                    754:                        default:
                    755:                                eputc(c);
                    756:                        }
                    757:                }
                    758:        }
                    759: }
                    760:
                    761: /*
                    762:  * Put integer, in radix "r".
                    763:  */
                    764: static VOID
                    765: eputi(i, r)
1.2     ! millert   766:        int    i;
        !           767:        int    r;
1.1       deraadt   768: {
1.2     ! millert   769:        int    q;
1.1       deraadt   770:
1.2     ! millert   771:        if (i < 0) {
        !           772:                eputc('-');
        !           773:                i = -i;
1.1       deraadt   774:        }
1.2     ! millert   775:        if ((q = i / r) != 0)
1.1       deraadt   776:                eputi(q, r);
1.2     ! millert   777:        eputc(i % r + '0');
1.1       deraadt   778: }
                    779:
                    780: /*
                    781:  * Put long, in radix "r".
                    782:  */
                    783: static VOID
                    784: eputl(l, r)
1.2     ! millert   785:        long   l;
        !           786:        int    r;
1.1       deraadt   787: {
1.2     ! millert   788:        long   q;
1.1       deraadt   789:
1.2     ! millert   790:        if (l < 0) {
        !           791:                eputc('-');
        !           792:                l = -l;
1.1       deraadt   793:        }
1.2     ! millert   794:        if ((q = l / r) != 0)
1.1       deraadt   795:                eputl(q, r);
1.2     ! millert   796:        eputc((int) (l % r) + '0');
1.1       deraadt   797: }
                    798:
                    799: /*
                    800:  * Put string.
                    801:  */
                    802: static VOID
                    803: eputs(s)
1.2     ! millert   804:        char  *s;
1.1       deraadt   805: {
1.2     ! millert   806:        int    c;
1.1       deraadt   807:
                    808:        while ((c = *s++) != '\0')
                    809:                eputc(c);
                    810: }
                    811:
                    812: /*
                    813:  * Put character. Watch for
                    814:  * control characters, and for the line
                    815:  * getting too long.
                    816:  */
                    817: static VOID
                    818: eputc(c)
1.2     ! millert   819:        char   c;
1.1       deraadt   820: {
1.2     ! millert   821:
        !           822:        if (ttcol + 2 < ncol) {
1.1       deraadt   823:                if (ISCTRL(c)) {
                    824:                        eputc('^');
                    825:                        c = CCHR(c);
                    826:                }
                    827:                ttputc(c);
                    828:                ++ttcol;
                    829:        }
                    830: }
                    831:
1.2     ! millert   832: static VOID
1.1       deraadt   833: free_file_list(lp)
1.2     ! millert   834:        LIST *lp;
1.1       deraadt   835: {
1.2     ! millert   836:        LIST *next;
        !           837:
        !           838:        while (lp) {
        !           839:                next = lp->l_next;
        !           840:                free(lp);
        !           841:                lp = next;
        !           842:        }
1.1       deraadt   843: }
                    844:
1.2     ! millert   845: static LIST *
        !           846: copy_list(lp)
        !           847:        LIST *lp;
        !           848: {
        !           849:        LIST *current, *last;
        !           850:
        !           851:        last = NULL;
        !           852:        while (lp) {
        !           853:                current = (LIST *) malloc(sizeof(LIST));
        !           854:                current->l_next = last;
        !           855:                current->l_name = lp->l_name;
        !           856:                last = (LIST *) current;
        !           857:                lp = lp->l_next;
        !           858:        }
        !           859:        return (last);
1.1       deraadt   860: }