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

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