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