| #include "c.h" |
| |
| static char rcsid[] = "$Id: output.c 355 2007-02-18 22:08:49Z drh $"; |
| |
| static char *outs(const char *str, FILE *f, char *bp) { |
| if (f) |
| fputs(str, f); |
| else |
| while (*bp = *str++) |
| bp++; |
| return bp; |
| } |
| |
| static char *outd(long n, FILE *f, char *bp) { |
| unsigned long m; |
| char buf[25], *s = buf + sizeof buf; |
| |
| *--s = '\0'; |
| if (n < 0) |
| m = -n; |
| else |
| m = n; |
| do |
| *--s = m%10 + '0'; |
| while ((m /= 10) != 0); |
| if (n < 0) |
| *--s = '-'; |
| return outs(s, f, bp); |
| } |
| |
| static char *outu(unsigned long n, int base, FILE *f, char *bp) { |
| char buf[25], *s = buf + sizeof buf; |
| |
| *--s = '\0'; |
| do |
| *--s = "0123456789abcdef"[n%base]; |
| while ((n /= base) != 0); |
| return outs(s, f, bp); |
| } |
| void print(const char *fmt, ...) { |
| va_list ap; |
| |
| va_start(ap, fmt); |
| vfprint(stdout, NULL, fmt, ap); |
| va_end(ap); |
| } |
| /* fprint - formatted output to f */ |
| void fprint(FILE *f, const char *fmt, ...) { |
| va_list ap; |
| |
| va_start(ap, fmt); |
| vfprint(f, NULL, fmt, ap); |
| va_end(ap); |
| } |
| |
| /* stringf - formatted output to a saved string */ |
| char *stringf(const char *fmt, ...) { |
| char buf[1024]; |
| va_list ap; |
| |
| va_start(ap, fmt); |
| vfprint(NULL, buf, fmt, ap); |
| va_end(ap); |
| return string(buf); |
| } |
| |
| /* vfprint - formatted output to f or string bp */ |
| void vfprint(FILE *f, char *bp, const char *fmt, va_list ap) { |
| for (; *fmt; fmt++) |
| if (*fmt == '%') |
| switch (*++fmt) { |
| case 'd': bp = outd(va_arg(ap, int), f, bp); break; |
| case 'D': bp = outd(va_arg(ap, long), f, bp); break; |
| case 'U': bp = outu(va_arg(ap, unsigned long), 10, f, bp); break; |
| case 'u': bp = outu(va_arg(ap, unsigned), 10, f, bp); break; |
| case 'o': bp = outu(va_arg(ap, unsigned), 8, f, bp); break; |
| case 'X': bp = outu(va_arg(ap, unsigned long), 16, f, bp); break; |
| case 'x': bp = outu(va_arg(ap, unsigned), 16, f, bp); break; |
| case 'f': case 'e': |
| case 'g': { |
| static char format[] = "%f"; |
| char buf[128]; |
| format[1] = *fmt; |
| sprintf(buf, format, va_arg(ap, double)); |
| bp = outs(buf, f, bp); |
| } |
| ; break; |
| case 's': bp = outs(va_arg(ap, char *), f, bp); break; |
| case 'p': { |
| void *p = va_arg(ap, void *); |
| if (p) |
| bp = outs("0x", f, bp); |
| bp = outu((unsigned long)p, 16, f, bp); |
| break; |
| } |
| case 'c': if (f) fputc(va_arg(ap, int), f); else *bp++ = va_arg(ap, int); break; |
| case 'S': { char *s = va_arg(ap, char *); |
| int n = va_arg(ap, int); |
| if (s) |
| for ( ; n-- > 0; s++) |
| if (f) (void)putc(*s, f); else *bp++ = *s; |
| } break; |
| case 'k': { int t = va_arg(ap, int); |
| static char *tokens[] = { |
| #define xx(a,b,c,d,e,f,g) g, |
| #define yy(a,b,c,d,e,f,g) g, |
| #include "token.h" |
| }; |
| assert(tokens[t&0177]); |
| bp = outs(tokens[t&0177], f, bp); |
| } break; |
| case 't': { Type ty = va_arg(ap, Type); |
| assert(f); |
| outtype(ty ? ty : voidtype, f); |
| } break; |
| case 'w': { Coordinate *p = va_arg(ap, Coordinate *); |
| if (p->file && *p->file) { |
| bp = outs(p->file, f, bp); |
| bp = outs(":", f, bp); |
| } |
| bp = outd(p->y, f, bp); |
| } break; |
| case 'I': { int n = va_arg(ap, int); |
| while (--n >= 0) |
| if (f) (void)putc(' ', f); else *bp++ = ' '; |
| } break; |
| default: if (f) (void)putc(*fmt, f); else *bp++ = *fmt; break; |
| } |
| else if (f) |
| (void)putc(*fmt, f); |
| else |
| *bp++ = *fmt; |
| if (!f) |
| *bp = '\0'; |
| } |