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