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

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