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

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