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

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