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