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

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