Annotation of src/usr.bin/mg/echo.c, Revision 1.13
1.13 ! mickey 1: /* $OpenBSD: echo.c,v 1.12 2001/05/23 23:29:47 mickey 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:
16: #include <stdarg.h>
1.1 deraadt 17:
1.3 millert 18: static int veread __P((const char *, char *buf, int, int, va_list));
19: static int complt __P((int, int, char *, int));
20: static int complt_list __P((int, int, char *, int));
1.10 art 21: static void eformat __P((const char *, 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));
1.2 millert 26: static LIST *copy_list __P((LIST *));
1.1 deraadt 27:
1.3 millert 28: int epresf = FALSE; /* stuff in echo line flag */
1.1 deraadt 29:
30: /*
31: * Erase the echo line.
32: */
1.10 art 33: void
1.2 millert 34: eerase()
35: {
1.1 deraadt 36: ttcolor(CTEXT);
1.2 millert 37: ttmove(nrow - 1, 0);
1.1 deraadt 38: tteeol();
39: ttflush();
40: epresf = FALSE;
41: }
42:
43: /*
1.3 millert 44: * Ask a "yes" or "no" question. Return ABORT if the user answers the
45: * question with the abort ("^G") character. Return FALSE for "no" and
46: * TRUE for "yes". No formatting services are available. No newline
47: * required.
1.1 deraadt 48: */
1.2 millert 49: int
50: eyorn(sp)
1.3 millert 51: char *sp;
1.2 millert 52: {
1.3 millert 53: int s;
1.1 deraadt 54:
55: #ifndef NO_MACRO
1.2 millert 56: if (inmacro)
57: return TRUE;
1.3 millert 58: #endif /* !NO_MACRO */
1.1 deraadt 59: ewprintf("%s? (y or n) ", sp);
60: for (;;) {
61: s = getkey(FALSE);
1.2 millert 62: if (s == 'y' || s == 'Y')
63: return TRUE;
64: if (s == 'n' || s == 'N')
65: return FALSE;
66: if (s == CCHR('G'))
67: return ctrlg(FFRAND, 1);
1.1 deraadt 68: ewprintf("Please answer y or n. %s? (y or n) ", sp);
69: }
1.2 millert 70: /* NOTREACHED */
1.1 deraadt 71: }
72:
73: /*
1.3 millert 74: * Like eyorn, but for more important questions. User must type all of
75: * "yes" or "no" and the trainling newline.
1.1 deraadt 76: */
1.2 millert 77: int
78: eyesno(sp)
1.3 millert 79: 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.1 deraadt 102: if ((buf[0] == 'y' || buf[0] == 'Y')
1.2 millert 103: && (buf[1] == 'e' || buf[1] == 'E')
104: && (buf[2] == 's' || buf[2] == 'S')
105: && (buf[3] == '\0'))
106: return TRUE;
1.1 deraadt 107: if ((buf[0] == 'n' || buf[0] == 'N')
1.2 millert 108: && (buf[1] == 'o' || buf[0] == 'O')
109: && (buf[2] == '\0'))
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.3 millert 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
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.3 millert 137: * This is the general "read input from the echo line" routine. The basic
138: * idea is that the prompt string "prompt" is written to the echo line, and
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
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
156: veread(fp, buf, nbuf, flag, ap)
157: const char *fp;
158: char *buf;
1.3 millert 159: int nbuf, flag;
1.2 millert 160: va_list ap;
161: {
1.3 millert 162: int cpos;
163: int i;
164: int c;
1.1 deraadt 165:
166: #ifndef NO_MACRO
1.2 millert 167: if (inmacro) {
168: bcopy(maclcur->l_text, buf, maclcur->l_used);
169: buf[maclcur->l_used] = '\0';
170: maclcur = maclcur->l_fp;
171: return TRUE;
1.1 deraadt 172: }
1.3 millert 173: #endif /* !NO_MACRO */
1.1 deraadt 174: cpos = 0;
1.2 millert 175: if ((flag & EFNEW) != 0 || ttrow != nrow - 1) {
1.1 deraadt 176: ttcolor(CTEXT);
1.2 millert 177: ttmove(nrow - 1, 0);
1.1 deraadt 178: epresf = TRUE;
179: } else
180: eputc(' ');
181: eformat(fp, ap);
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');
197: /* and continue */
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 */
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);
291: /* and continue */
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
308: complt(flags, c, buf, cpos)
1.3 millert 309: int flags, c, cpos;
310: char *buf;
311: {
312: LIST *lh, *lh2;
313: LIST *wholelist = NULL;
314: int i, nxtra, nhits, bxtra, msglen, nshown;
315: int wflag = FALSE;
316: char *msg;
317:
318: lh = lh2 = NULL;
1.2 millert 319:
320: if ((flags & EFFUNC) != 0) {
321: buf[cpos] = '\0';
1.6 art 322: wholelist = lh = complete_function_list(buf, c);
1.9 art 323: } else if ((flags & EFBUF) != 0) {
1.6 art 324: lh = &(bheadp->b_list);
1.9 art 325: } else if ((flags & EFFILE) != 0) {
1.6 art 326: buf[cpos] = '\0';
327: wholelist = lh = make_file_list(buf);
328: } else
329: panic("broken complt call: flags");
330:
331: if (c == ' ')
332: wflag = TRUE;
333: else if (c != '\t' && c != CCHR('M'))
334: panic("broken complt call: c");
335:
336: nhits = 0;
337: nxtra = HUGE;
338:
339: for (; lh != NULL; lh = lh->l_next) {
340: if (memcmp(buf, lh->l_name, cpos) != 0)
341: continue;
1.2 millert 342: if (nhits == 0)
1.6 art 343: lh2 = lh;
344: ++nhits;
345: if (lh->l_name[cpos] == '\0')
346: nxtra = -1;
1.3 millert 347: else {
1.6 art 348: bxtra = getxtra(lh, lh2, cpos, wflag);
349: if (bxtra < nxtra)
350: nxtra = bxtra;
351: lh2 = lh;
352: }
353: }
354: if (nhits == 0)
355: msg = " [No match]";
356: else if (nhits > 1 && nxtra == 0)
357: msg = " [Ambiguous]";
358: else {
359: /*
360: * Being lazy - ought to check length, but all things
361: * autocompleted have known types/lengths.
362: */
363: if (nxtra < 0 && nhits > 1 && c == ' ')
364: nxtra = 1;
365: for (i = 0; i < nxtra; ++i) {
366: buf[cpos] = lh2->l_name[cpos];
367: eputc(buf[cpos++]);
1.1 deraadt 368: }
1.6 art 369: ttflush();
370: free_file_list(wholelist);
371: if (nxtra < 0 && c != CCHR('M'))
372: return 0;
373: return nxtra;
1.1 deraadt 374: }
1.3 millert 375:
1.2 millert 376: /*
377: * wholelist is null if we are doing buffers. want to free lists
378: * that were created for us, but not the buffer list!
379: */
1.1 deraadt 380: free_file_list(wholelist);
1.3 millert 381:
1.1 deraadt 382: /* Set up backspaces, etc., being mindful of echo line limit */
383: msglen = strlen(msg);
384: nshown = (ttcol + msglen + 2 > ncol) ?
1.2 millert 385: ncol - ttcol - 2 : msglen;
1.1 deraadt 386: eputs(msg);
1.2 millert 387: ttcol -= (i = nshown); /* update ttcol! */
388: while (i--) /* move back before msg */
1.1 deraadt 389: ttputc('\b');
1.2 millert 390: ttflush(); /* display to user */
1.1 deraadt 391: i = nshown;
1.3 millert 392: while (i--) /* blank out on next flush */
1.1 deraadt 393: eputc(' ');
1.2 millert 394: ttcol -= (i = nshown); /* update ttcol on BS's */
1.1 deraadt 395: while (i--)
1.2 millert 396: ttputc('\b'); /* update ttcol again! */
1.1 deraadt 397: return 0;
398: }
399:
400: /*
401: * do completion on a list of objects, listing instead of completing
402: */
1.2 millert 403: static int
404: complt_list(flags, c, buf, cpos)
1.3 millert 405: int flags;
406: int c;
407: char *buf;
408: int cpos;
409: {
410: LIST *lh, *lh2, *lh3;
411: LIST *wholelist = NULL;
412: BUFFER *bp;
413: int i, maxwidth, width;
414: int preflen = 0;
415: int oldrow = ttrow;
416: int oldcol = ttcol;
417: int oldhue = tthue;
418: char linebuf[NCOL + 1];
419: char *cp;
420:
421: lh = NULL;
1.1 deraadt 422:
423: ttflush();
424:
425: /* the results are put into a help buffer */
1.2 millert 426: bp = bfind("*help*", TRUE);
427: if (bclear(bp) == FALSE)
428: return FALSE;
429:
430: { /* this {} present for historical reasons */
431:
432: /*
433: * first get the list of objects. This list may contain only
434: * the ones that complete what has been typed, or may be the
435: * whole list of all objects of this type. They are filtered
436: * later in any case. Set wholelist if the list has been
437: * cons'ed up just for us, so we can free it later. We have
438: * to copy the buffer list for this function even though we
439: * didn't for complt. The sorting code does destructive
440: * changes to the list, which we don't want to happen to the
441: * main buffer list!
442: */
443: if ((flags & EFBUF) != 0)
444: wholelist = lh = copy_list(&(bheadp->b_list));
445: else if ((flags & EFFUNC) != 0) {
446: buf[cpos] = '\0';
447: wholelist = lh = complete_function_list(buf, c);
448: } else if ((flags & EFFILE) != 0) {
449: buf[cpos] = '\0';
1.5 art 450: wholelist = lh = make_file_list(buf);
1.2 millert 451: /*
452: * We don't want to display stuff up to the / for file
453: * names preflen is the list of a prefix of what the
454: * user typed that should not be displayed.
455: */
456: cp = strrchr(buf, '/');
457: if (cp)
458: preflen = cp - buf + 1;
459: } else
460: panic("broken complt call: flags");
1.1 deraadt 461:
462:
1.2 millert 463: /*
464: * Sort the list, since users expect to see it in alphabetic
465: * order.
466: */
467: lh2 = lh;
468: while (lh2) {
469: lh3 = lh2->l_next;
470: while (lh3) {
471: if (strcmp(lh2->l_name, lh3->l_name) > 0) {
472: cp = lh2->l_name;
473: lh2->l_name = lh3->l_name;
474: lh3->l_name = cp;
475: }
476: lh3 = lh3->l_next;
477: }
478: lh2 = lh2->l_next;
479: }
1.1 deraadt 480:
481: /*
1.2 millert 482: * First find max width of object to be displayed, so we can
483: * put several on a line.
1.1 deraadt 484: */
1.2 millert 485: maxwidth = 0;
486: lh2 = lh;
487: while (lh2 != NULL) {
488: for (i = 0; i < cpos; ++i) {
489: if (buf[i] != lh2->l_name[i])
490: break;
491: }
492: if (i == cpos) {
493: width = strlen(lh2->l_name);
494: if (width > maxwidth)
495: maxwidth = width;
496: }
497: lh2 = lh2->l_next;
1.1 deraadt 498: }
1.2 millert 499: maxwidth += 1 - preflen;
500:
501: /*
502: * Now do the display. objects are written into linebuf until
503: * it fills, and then put into the help buffer.
504: */
505: cp = linebuf;
506: width = 0;
507: lh2 = lh;
508: while (lh2 != NULL) {
509: for (i = 0; i < cpos; ++i) {
510: if (buf[i] != lh2->l_name[i])
511: break;
512: }
513: if (i == cpos) {
514: if ((width + maxwidth) > ncol) {
515: *cp = 0;
516: addline(bp, linebuf);
517: cp = linebuf;
518: width = 0;
519: }
520: strcpy(cp, lh2->l_name + preflen);
521: i = strlen(lh2->l_name + preflen);
522: cp += i;
523: for (; i < maxwidth; i++)
524: *cp++ = ' ';
525: width += maxwidth;
526: }
527: lh2 = lh2->l_next;
528: }
529: if (width > 0) {
530: *cp = 0;
531: addline(bp, linebuf);
1.1 deraadt 532: }
1.2 millert 533: }
534: /*
535: * Note that we free lists only if they are put in wholelist lists
536: * that were built just for us should be freed. However when we use
537: * the buffer list, obviously we don't want it freed.
1.1 deraadt 538: */
539: free_file_list(wholelist);
1.2 millert 540: popbuftop(bp); /* split the screen and put up the help
541: * buffer */
542: update(); /* needed to make the new stuff actually
543: * appear */
544: ttmove(oldrow, oldcol); /* update leaves cursor in arbitrary place */
545: ttcolor(oldhue); /* with arbitrary color */
1.1 deraadt 546: ttflush();
547: return 0;
548: }
549:
550: /*
1.3 millert 551: * The "lp1" and "lp2" point to list structures. The "cpos" is a horizontal
552: * position in the name. Return the longest block of characters that can be
553: * autocompleted at this point. Sometimes the two symbols are the same, but
554: * this is normal.
1.2 millert 555: */
556: int
557: getxtra(lp1, lp2, cpos, wflag)
1.3 millert 558: LIST *lp1, *lp2;
559: int cpos;
560: int wflag;
1.2 millert 561: {
1.3 millert 562: int i;
1.1 deraadt 563:
564: i = cpos;
565: for (;;) {
1.2 millert 566: if (lp1->l_name[i] != lp2->l_name[i])
567: break;
568: if (lp1->l_name[i] == '\0')
569: break;
1.1 deraadt 570: ++i;
1.2 millert 571: if (wflag && !ISWORD(lp1->l_name[i - 1]))
572: break;
1.1 deraadt 573: }
574: return (i - cpos);
575: }
576:
577: /*
1.3 millert 578: * Special "printf" for the echo line. Each call to "ewprintf" starts a
579: * new line in the echo area, and ends with an erase to end of the echo
580: * line. The formatting is done by a call to the standard formatting
581: * routine.
1.1 deraadt 582: */
1.2 millert 583: /* VARARGS */
1.10 art 584: void
1.2 millert 585: ewprintf(const char *fmt, ...)
1.1 deraadt 586: {
1.3 millert 587: va_list ap;
1.1 deraadt 588:
589: #ifndef NO_MACRO
1.2 millert 590: if (inmacro)
591: return;
1.3 millert 592: #endif /* !NO_MACRO */
1.2 millert 593: va_start(ap, fmt);
1.1 deraadt 594: ttcolor(CTEXT);
1.2 millert 595: ttmove(nrow - 1, 0);
596: eformat(fmt, ap);
597: va_end(ap);
1.1 deraadt 598: tteeol();
599: ttflush();
600: epresf = TRUE;
601: }
602:
603: /*
1.3 millert 604: * Printf style formatting. This is called by both "ewprintf" and "ereply"
605: * to provide formatting services to their clients. The move to the start
606: * of the echo line, and the erase to the end of the echo line, is done by
607: * the caller.
1.1 deraadt 608: * Note: %c works, and prints the "name" of the character.
609: * %k prints the name of a key (and takes no arguments).
610: */
1.10 art 611: static void
1.1 deraadt 612: eformat(fp, ap)
1.3 millert 613: const char *fp;
1.12 mickey 614: va_list ap;
1.1 deraadt 615: {
1.12 mickey 616: char kname[NKNAME], *cp;
617: int c;
1.1 deraadt 618:
619: while ((c = *fp++) != '\0') {
620: if (c != '%')
621: eputc(c);
622: else {
623: c = *fp++;
624: switch (c) {
625: case 'c':
1.12 mickey 626: keyname(kname, sizeof(kname), va_arg(ap, int));
1.1 deraadt 627: eputs(kname);
628: break;
629:
630: case 'k':
1.12 mickey 631: for (cp = kname, c = 0; c < key.k_count; c++) {
632: if (c)
633: *cp++ = ' ';
634: cp = keyname(cp, sizeof(kname) -
635: (cp - kname) - 1, key.k_chars[c]);
1.1 deraadt 636: }
637: eputs(kname);
638: break;
639:
640: case 'd':
1.2 millert 641: eputi(va_arg(ap, int), 10);
1.1 deraadt 642: break;
643:
644: case 'o':
1.2 millert 645: eputi(va_arg(ap, int), 8);
1.1 deraadt 646: break;
647:
648: case 's':
1.2 millert 649: eputs(va_arg(ap, char *));
1.1 deraadt 650: break;
651:
1.3 millert 652: case 'l':
653: /* explicit longword */
1.1 deraadt 654: c = *fp++;
1.2 millert 655: switch (c) {
1.1 deraadt 656: case 'd':
1.13 ! mickey 657: eputl(va_arg(ap, long), 10);
1.1 deraadt 658: break;
659: default:
660: eputc(c);
661: break;
662: }
663: break;
664:
665: default:
666: eputc(c);
667: }
668: }
669: }
670: }
671:
672: /*
673: * Put integer, in radix "r".
674: */
1.10 art 675: static void
1.1 deraadt 676: eputi(i, r)
1.3 millert 677: int i, r;
1.1 deraadt 678: {
1.3 millert 679: int q;
1.1 deraadt 680:
1.2 millert 681: if (i < 0) {
682: eputc('-');
683: i = -i;
1.1 deraadt 684: }
1.2 millert 685: if ((q = i / r) != 0)
1.1 deraadt 686: eputi(q, r);
1.2 millert 687: eputc(i % r + '0');
1.1 deraadt 688: }
689:
690: /*
691: * Put long, in radix "r".
692: */
1.10 art 693: static void
1.1 deraadt 694: eputl(l, r)
1.3 millert 695: long l;
696: int r;
1.1 deraadt 697: {
1.3 millert 698: long q;
1.1 deraadt 699:
1.2 millert 700: if (l < 0) {
701: eputc('-');
702: l = -l;
1.1 deraadt 703: }
1.2 millert 704: if ((q = l / r) != 0)
1.1 deraadt 705: eputl(q, r);
1.3 millert 706: eputc((int)(l % r) + '0');
1.1 deraadt 707: }
708:
709: /*
710: * Put string.
711: */
1.10 art 712: static void
1.1 deraadt 713: eputs(s)
1.3 millert 714: char *s;
1.1 deraadt 715: {
1.3 millert 716: int c;
1.1 deraadt 717:
718: while ((c = *s++) != '\0')
719: eputc(c);
720: }
721:
722: /*
1.3 millert 723: * Put character. Watch for control characters, and for the line getting
724: * too long.
1.1 deraadt 725: */
1.10 art 726: static void
1.1 deraadt 727: eputc(c)
1.3 millert 728: char c;
1.1 deraadt 729: {
1.2 millert 730: if (ttcol + 2 < ncol) {
1.1 deraadt 731: if (ISCTRL(c)) {
732: eputc('^');
733: c = CCHR(c);
734: }
735: ttputc(c);
736: ++ttcol;
737: }
738: }
739:
1.10 art 740: void
1.1 deraadt 741: free_file_list(lp)
1.2 millert 742: LIST *lp;
1.1 deraadt 743: {
1.3 millert 744: LIST *next;
1.2 millert 745:
746: while (lp) {
747: next = lp->l_next;
748: free(lp);
749: lp = next;
750: }
1.1 deraadt 751: }
752:
1.2 millert 753: static LIST *
754: copy_list(lp)
755: LIST *lp;
756: {
1.3 millert 757: LIST *current, *last;
1.2 millert 758:
759: last = NULL;
760: while (lp) {
1.3 millert 761: current = (LIST *)malloc(sizeof(LIST));
1.2 millert 762: current->l_next = last;
763: current->l_name = lp->l_name;
1.3 millert 764: last = (LIST *)current;
1.2 millert 765: lp = lp->l_next;
766: }
767: return (last);
1.1 deraadt 768: }