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