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

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