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