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

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