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