1 /*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)output.c 5.2 (Berkeley) 04/04/91";
10 #endif /* not lint */
11
12 /*
13 * adb - output
14 */
15
16 #include "defs.h"
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <varargs.h>
20
21 extern char TOODEEP[];
22
23 int infile;
24 int outfile = 1;
25
26 char printbuf[LINELEN];
27 char *printptr = printbuf;
28
29
30 /*
31 * Print the string s.
32 */
prints(s)33 prints(s)
34 register char *s;
35 {
36 register int c;
37
38 while ((c = *s++) != '\0')
39 printc(c);
40 }
41
42 /*
43 * Print the character c.
44 */
printc(c)45 printc(c)
46 int c;
47 {
48
49 if (mkfault)
50 return;
51 switch (c) {
52
53 case 0:
54 return;
55
56 case '\n':
57 sendout();
58 return;
59
60 default:
61 if (isprint(c))
62 *printptr++ = c;
63 break;
64 }
65 if (printptr >= &printbuf[LINELEN - 1]) /* 1 == space for \n */
66 sendout();
67 }
68
69 /*
70 * Send (write) out the contents of the print buffer, compressing
71 * spaces into tabs.
72 */
73 static
sendout()74 sendout()
75 {
76 register char *p, *q;
77 register int c, off = 0, spaces = 0, s;
78 #define tabsize(x) (8 - ((x) & 7))
79
80 for (q = p = printbuf; p < printptr;) {
81 c = *p++;
82 switch (c) {
83
84 case ' ':
85 spaces++;
86 break;
87
88 case '\t':
89 spaces += tabsize(off + spaces);
90 break;
91
92 default:
93 s = tabsize(off);
94 off += spaces + 1;
95 while (spaces >= s) {
96 *q++ = '\t';
97 spaces -= s;
98 s = 8;
99 }
100 while (--spaces >= 0)
101 *q++ = ' ';
102 spaces = 0;
103 *q++ = c;
104 }
105 }
106 *q++ = '\n';
107 (void) write(outfile, printbuf, q - printbuf);
108 printptr = printbuf;
109 #undef tabsize
110 }
111
charpos()112 charpos()
113 {
114
115 return (printptr - printbuf);
116 }
117
endline()118 endline()
119 {
120
121 if (printptr - printbuf >= maxcol)
122 printc('\n');
123 }
124
flushbuf()125 flushbuf()
126 {
127
128 if (printptr != printbuf)
129 sendout();
130 }
131
132 /* this should not be necessary! */
133 #ifdef lint
134 #undef va_arg
135 #define va_arg(ap, type) (ap = ap, (type)0)
136 #endif
137
138 /*
139 * Context passed between adbprintf and decodefmt.
140 */
141 struct prf {
142 char *fmt; /* format pointer */
143 va_list ap; /* argument pointer */
144 char *buf; /* digit buffer, or %s string */
145 int adj; /* 'l'eft (-) or 'r'ight adjustment */
146 int width; /* width from format */
147 int prec; /* precision from format */
148 };
149
150 /*
151 * adb's very own version of printf() ... of course, all the format
152 * escapes are different. Noteworthy are the %<width>m and %<tabstop>t
153 * formats, which move the given width, or to the given tabstop, and
154 * the %?a format, which evaluates one argument, and if not zero, prints
155 * according to format a. (Note that any modifiers must appear in the
156 * `a' part, not in the %? part.)
157 */
158 /* VARARGS1 */
adbprintf(fmt,va_alist)159 adbprintf(fmt, va_alist)
160 char *fmt;
161 va_dcl
162 {
163 register char *s;
164 register int n, c;
165 struct prf prf;
166 char digits[130]; /* good to at least 128 bit expr_t */
167
168 /* set up the fields adbprf needs */
169 prf.fmt = fmt;
170 va_start(prf.ap);
171 for (;;) {
172 /* look for % conversions */
173 s = prf.fmt;
174 while ((c = *s++) != '%') {
175 if (c == 0)
176 return;
177 printc(c);
178 }
179 prf.fmt = s;
180 prf.buf = digits;
181 dofmt(&prf); /* format one format */
182 n = strlen(s = prf.buf);
183 if (prf.prec >= 0 && n > prf.prec)
184 n = prf.prec;
185 c = prf.width - n;
186 if (prf.adj == 'r')
187 while (--c >= 0)
188 printc(' ');
189 while (--n >= 0)
190 printc(*s++);
191 while (--c >= 0)
192 printc(' ');
193 }
194 va_end(prf.ap);
195 }
196
197 /*
198 * Do a single format.
199 */
200 static
dofmt(prf)201 dofmt(prf)
202 register struct prf *prf;
203 {
204 register char *s = prf->fmt;
205 register va_list ap = prf->ap;
206 register int c, n;
207 expr_t v;
208 int pluspref = 0;
209 static char null[] = "";
210
211 prf->adj = 'r';
212 prf->width = 0;
213 prf->prec = -1;
214 more:
215 c = *s++;
216 sw:
217 switch (c) {
218
219 case '-':
220 prf->adj = 'l';
221 goto more;
222
223 case '+':
224 pluspref = 1;
225 goto more;
226
227 case '*':
228 prf->width = va_arg(ap, int);
229 goto more;
230
231 case '0': case '1': case '2': case '3': case '4':
232 case '5': case '6': case '7': case '8': case '9':
233 for (n = c - '0'; isdigit(c = *s++);)
234 n = 10 * n + c - '0';
235 prf->width = n;
236 goto sw;
237
238 case '.':
239 c = *s++;
240 if (c == '*') {
241 prf->prec = va_arg(ap, int);
242 goto more;
243 }
244 for (n = 0; isdigit(c); c = *s++)
245 n = 10 * n + c - '0';
246 prf->prec = n;
247 goto sw;
248
249 case 'v': case 'V':
250 /* print in signed version of current radix */
251 if ((n = radix) > 0)
252 n = -n;
253 goto rprint;
254
255 case 'q': case 'Q': n = -8; goto rprint; /* octal */
256 case 'd': case 'D': n = -10; goto rprint; /* decimal */
257 case 'z': case 'Z': n = -16; goto rprint; /* hex */
258 case 'o': case 'O': n = 8; goto rprint; /* and */
259 case 'u': case 'U': n = 10; goto rprint; /* unsigned */
260 case 'x': case 'X': n = 16; goto rprint; /* versions */
261
262 case 'r': case 'R':
263 n = radix;
264 rprint:
265 if (isupper(c))
266 v = n < 0 ? SF_ARG : UF_ARG;
267 else
268 v = n < 0 ? SH_ARG : UH_ARG;
269 printradix(prf->buf, v, n, pluspref);
270 break;
271
272 case 'Y':
273 printdate(prf->buf, va_arg(ap, time_t));
274 break;
275
276 case 'c':
277 *prf->buf = va_arg(ap, int);
278 prf->buf[1] = 0;
279 break;
280
281 case 's':
282 prf->buf = va_arg(ap, char *);
283 break;
284
285 case 'f':
286 /* here comes stdio ... sigh */
287 (void) sprintf(prf->buf, "%+*.*e", prf->width,
288 prf->prec >= 0 ? prf->prec : 16, va_arg(ap, double));
289 prf->prec = -1;
290 break;
291
292 case 'm':
293 prf->buf = null;
294 break;
295
296 case 't':
297 if (prf->width)
298 prf->width -= charpos() % prf->width;
299 prf->buf = null;
300 break;
301
302 case '?':
303 c = va_arg(ap, int);
304 prf->fmt = s;
305 prf->ap = ap;
306 dofmt(prf);
307 if (c == 0)
308 prf->buf = null;
309 return;
310
311 default:
312 panic("dofmt");
313 /* NOTREACHED */
314 }
315 prf->fmt = s;
316 prf->ap = ap;
317 }
318
319 /*
320 * Print the date into the buffer at `p'.
321 */
322 static
printdate(p,tm)323 printdate(p, tm)
324 register char *p;
325 time_t tm;
326 {
327 char *asc = ctime(&tm);
328 char *strncpy();
329
330 (void) strncpy(p, asc + 20, 4); /* "1988" */
331 (void) strncpy(p + 4, asc + 3, 16); /* " Aug 18 03:04:49" */
332 p[20] = 0;
333 }
334
335 /*
336 * Print the value `val' in base `base' into the buffer at `p'.
337 * If base is negative, assume the number is signed.
338 */
339 static
printradix(p,val,base,pluspref)340 printradix(p, val, base, pluspref)
341 register char *p;
342 register expr_t val;
343 register int base;
344 int pluspref;
345 {
346 register char *d;
347 register expr_t high;
348 char digs[128]; /* good to 128 bits minimum */
349
350 if (base < 0) {
351 base = -base;
352 if ((sexpr_t)val < 0) {
353 val = -val;
354 *p++ = '-';
355 } else if (pluspref)
356 *p++ = '+';
357 } else if (pluspref)
358 *p++ = '+';
359
360 d = digs;
361 switch (base) {
362
363 case 8:
364 while (val != 0) {
365 *d++ = val & 7;
366 val >>= 3;
367 }
368 *d++ = 0;
369 break;
370
371 case 16:
372 do {
373 *d++ = val & 15;
374 } while ((val >>= 4) != 0);
375 break;
376
377 default:
378 do {
379 high = val / base;
380 *d++ = val - (high * base);
381 } while ((val = high) != 0);
382 break;
383 }
384 while (d > digs)
385 *p++ = "0123456789abcdef"[*--d];
386 *p = 0;
387 }
388
389 /*
390 * BEGIN XXX
391 * THIS BELONGS ELSEWHERE
392 */
393 #define MAXIFD 5
394 struct {
395 int fd;
396 expr_t v9;
397 } istack[MAXIFD];
398 int ifiledepth;
399
iclose(stack,err)400 iclose(stack, err)
401 int stack, err;
402 {
403
404 if (err) {
405 if (infile) {
406 (void) close(infile);
407 infile = 0;
408 }
409 while (--ifiledepth >= 0)
410 if (istack[ifiledepth].fd)
411 (void) close(istack[ifiledepth].fd);
412 ifiledepth = 0;
413 } else if (stack == 0) {
414 if (infile) {
415 (void) close(infile);
416 infile = 0;
417 }
418 } else if (stack > 0) {
419 if (ifiledepth >= MAXIFD)
420 error(TOODEEP);
421 istack[ifiledepth].fd = infile;
422 istack[ifiledepth].v9 = var[9];
423 ifiledepth++;
424 infile = 0;
425 } else {
426 if (infile) {
427 (void) close(infile);
428 infile = 0;
429 }
430 if (ifiledepth > 0) {
431 infile = istack[--ifiledepth].fd;
432 var[9] = istack[ifiledepth].v9;
433 }
434 }
435 }
436
oclose()437 oclose()
438 {
439
440 if (outfile != 1) {
441 flushbuf();
442 (void) close(outfile);
443 outfile = 1;
444 }
445 }
446