rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit 39edd860750a18dffd6767042b90a69648d10db6
parent 2ea901dfe7f367ddad61b3a64bbef4195a90ce35
Author: tim <tim>
Date:   Wed, 21 May 1997 12:26:01 +0000

Initial revision

Diffstat:
Aprint.c | 466+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 466 insertions(+), 0 deletions(-)

diff --git a/print.c b/print.c @@ -0,0 +1,466 @@ +/* print.c -- formatted printing routines (Paul Haahr, 12/91) */ + +#include "rc.h" +#include <setjmp.h> + +#define PRINT_ALLOCSIZE ((SIZE_T)64) +#define SPRINT_BUFSIZ ((SIZE_T)1024) + +#define MAXCONV 256 + +/* + * conversion functions + * true return -> flag changes only, not a conversion + */ + +#define Flag(name, flag) \ +static bool name(Format *format, int c) { \ + format->flags |= flag; \ + return TRUE; \ +} + +Flag(uconv, FMT_unsigned) +Flag(hconv, FMT_short) +Flag(lconv, FMT_long) +Flag(altconv, FMT_altform) +Flag(leftconv, FMT_leftside) +Flag(dotconv, FMT_f2set) + +static bool digitconv(Format *format, int c) { + if (format->flags & FMT_f2set) + format->f2 = 10 * format->f2 + c - '0'; + else { + format->flags |= FMT_f1set; + format->f1 = 10 * format->f1 + c - '0'; + } + return TRUE; +} + +static bool zeroconv(Format *format, int c) { + if (format->flags & (FMT_f1set | FMT_f2set)) + return digitconv(format, '0'); + format->flags |= FMT_zeropad; + return TRUE; +} + +static void pad(Format *format, SIZE_T len, int c) { + while (len-- != 0) + fmtputc(format, c); +} + +static bool sconv(Format *format, int c) { + char *s = va_arg(format->args, char *); + if ((format->flags & FMT_f1set) == 0) + fmtcat(format, s); + else { + SIZE_T len = strlen(s), width = format->f1 - len; + if (format->flags & FMT_leftside) { + fmtappend(format, s, len); + pad(format, width, ' '); + } else { + pad(format, width, ' '); + fmtappend(format, s, len); + } + } + return FALSE; +} + +static char *utoa(unsigned long u, char *t, unsigned int radix, const char *digit) { + if (u >= radix) { + t = utoa(u / radix, t, radix, digit); + u %= radix; + } + *t++ = digit[u]; + return t; +} + +static void intconv(Format *format, unsigned int radix, int upper, const char *altform) { + static const char * const table[] = { + "0123456789abcdefghijklmnopqrstuvwxyz", + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + }; + char padchar; + SIZE_T len, pre, zeroes, padding, width; + long n, flags; + unsigned long u; + char number[64], prefix[20]; + + if (radix > 36) + return; + + flags = format->flags; + if (flags & FMT_long) + n = va_arg(format->args, long); + else if (flags & FMT_short) + n = va_arg(format->args, short); + else + n = va_arg(format->args, int); + + pre = 0; + if ((flags & FMT_unsigned) || n >= 0) + u = n; + else { + prefix[pre++] = '-'; + u = -n; + } + + if (flags & FMT_altform) + while (*altform != '\0') + prefix[pre++] = *altform++; + + len = utoa(u, number, radix, table[upper]) - number; + if ((flags & FMT_f2set) && (SIZE_T) format->f2 > len) + zeroes = format->f2 - len; + else + zeroes = 0; + + width = pre + zeroes + len; + if ((flags & FMT_f1set) && (SIZE_T) format->f1 > width) { + padding = format->f1 - width; + } else + padding = 0; + + padchar = ' '; + if (padding > 0 && flags & FMT_zeropad) { + padchar = '0'; + if ((flags & FMT_leftside) == 0) { + zeroes += padding; + padding = 0; + } + } + + + if ((flags & FMT_leftside) == 0) + pad(format, padding, padchar); + fmtappend(format, prefix, pre); + pad(format, zeroes, '0'); + fmtappend(format, number, len); + if (flags & FMT_leftside) + pad(format, padding, padchar); +} + +static bool cconv(Format *format, int c) { + fmtputc(format, va_arg(format->args, int)); + return FALSE; +} + +static bool dconv(Format *format, int c) { + intconv(format, 10, 0, ""); + return FALSE; +} + +static bool oconv(Format *format, int c) { + intconv(format, 8, 0, "0"); + return FALSE; +} + +static bool xconv(Format *format, int c) { + intconv(format, 16, 0, "0x"); + return FALSE; +} + +static bool pctconv(Format *format, int c) { + fmtputc(format, '%'); + return FALSE; +} + +static bool badconv(Format *format, int c) { + panic("bad conversion character in printfmt"); + /* NOTREACHED */ + return FALSE; /* hush up gcc -Wall */ +} + + +/* + * conversion table management + */ + +static Conv fmttab[MAXCONV]; + +static void inittab(void) { + int i; + for (i = 0; i < MAXCONV; i++) + fmttab[i] = badconv; + + fmttab['s'] = sconv; + fmttab['c'] = cconv; + fmttab['d'] = dconv; + fmttab['o'] = oconv; + fmttab['x'] = xconv; + fmttab['%'] = pctconv; + + fmttab['u'] = uconv; + fmttab['h'] = hconv; + fmttab['l'] = lconv; + fmttab['#'] = altconv; + fmttab['-'] = leftconv; + fmttab['.'] = dotconv; + + fmttab['0'] = zeroconv; + for (i = '1'; i <= '9'; i++) + fmttab[i] = digitconv; +} + +extern bool (*fmtinstall(int c, bool (*f)(Format *, int)))(Format *, int) { +/*Conv fmtinstall(int c, Conv f) {*/ + Conv oldf; + if (fmttab[0] == NULL) + inittab(); + c &= MAXCONV - 1; + oldf = fmttab[c]; + if (f != NULL) + fmttab[c] = f; + return oldf; +} + + +/* + * functions for inserting strings in the format buffer + */ + +extern void fmtappend(Format *format, const char *s, SIZE_T len) { + while (format->buf + len > format->bufend) { + SIZE_T split = format->bufend - format->buf; + memcpy(format->buf, s, split); + format->buf += split; + s += split; + len -= split; + (*format->grow)(format, len); + } + memcpy(format->buf, s, len); + format->buf += len; +} + +extern void fmtcat(Format *format, const char *s) { + fmtappend(format, s, strlen(s)); +} + +/* + * printfmt -- the driver routine + */ + +extern int printfmt(Format *format, const char *fmt) { + unsigned const char *s = (unsigned const char *) fmt; + + if (fmttab[0] == NULL) + inittab(); + + for (;;) { + int c = *s++; + switch (c) { + case '%': + format->flags = format->f1 = format->f2 = 0; + do + c = *s++; + while ((*fmttab[c])(format, c)); + break; + case '\0': + return format->buf - format->bufbegin + format->flushed; + default: + fmtputc(format, c); + break; + } + } +} + + +/* + * the public entry points + */ + +extern int fmtprint(Format *format, const char *fmt,...) { + int n = -format->flushed; + va_list ap, saveargs; + + va_start(ap, fmt); + saveargs = format->args; + format->args = ap; + n += printfmt(format, fmt); + va_end(format->args); + format->args = saveargs; + + return n + format->flushed; +} + +static void fprint_flush(Format *format, SIZE_T more) { + SIZE_T n = format->buf - format->bufbegin; + char *buf = format->bufbegin; + + format->flushed += n; + format->buf = format->bufbegin; + writeall(format->u.n, buf, n); +} + +extern int fprint(int fd, const char *fmt,...) { + char buf[1024]; + Format format; + va_list ap; + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + sizeof buf; + format.grow = fprint_flush; + format.flushed = 0; + format.u.n = fd; + + va_start(ap, fmt); + format.args = ap; + printfmt(&format, fmt); + va_end(format.args); + + fprint_flush(&format, (SIZE_T) 0); + return format.flushed; +} + +static void memprint_grow(Format *format, SIZE_T more) { + char *buf; + SIZE_T len = format->bufend - format->bufbegin + 1; + len = (len >= more) + ? len * 2 + : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1); + if (format->u.n) + buf = erealloc(format->bufbegin, len); + else { + SIZE_T used = format->buf - format->bufbegin; + buf = nalloc(len); + memcpy(buf, format->bufbegin, used); + } + format->buf = buf + (format->buf - format->bufbegin); + format->bufbegin = buf; + format->bufend = buf + len - 1; +} + +static char *memprint(Format *format, const char *fmt, char *buf, SIZE_T len) { + format->buf = buf; + format->bufbegin = buf; + format->bufend = buf + len - 1; + format->grow = memprint_grow; + format->flushed = 0; + printfmt(format, fmt); + *format->buf = '\0'; + return format->bufbegin; +} + +extern char *mprint(const char *fmt,...) { + Format format; + char *result; + va_list ap; + + format.u.n = 1; + va_start(ap, fmt); + format.args = ap; + result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); + va_end(format.args); + return result; +} + +extern char *nprint(const char *fmt,...) { + Format format; + char *result; + va_list ap; + + format.u.n = 0; + va_start(ap, fmt); + format.args = ap; + result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE); + va_end(format.args); + return result; +} + + +/* THESE ARE UNUSED IN rc */ + +#if 0 + +extern int print(const char *fmt,...) { + char buf[1024]; + Format format; + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + sizeof buf; + format.grow = fprint_flush; + format.flushed = 0; + format.u.n = 1; + + va_start(format.args, fmt); + printfmt(&format, fmt); + va_end(format.args); + + fprint_flush(&format, 0); + return format.flushed; +} + +extern int eprint(const char *fmt,...) { + char buf[1024]; + Format format; + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + sizeof buf; + format.grow = fprint_flush; + format.flushed = 0; + format.u.n = 2; + + va_start(format.args, fmt); + printfmt(&format, fmt); + va_end(format.args); + + fprint_flush(&format, 0); + return format.flushed; +} + +static void snprint_grow(Format *format, SIZE_T more) { + longjmp(format->u.p, 1); +} + +extern int snprint(char *buf, int buflen, const char *fmt,...) { + int n; + jmp_buf jbuf; + Format format; + + if (setjmp(jbuf)) { + *format.buf = '\0'; + return format.buf - format.bufbegin; + } + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + buflen - 1; + format.grow = snprint_grow; + format.flushed = 0; + format.u.p = jbuf; + + va_start(format.args, fmt); + n = printfmt(&format, fmt); + va_end(format.args); + + *format.buf = '\0'; + return n; +} + +extern int sprint(char *buf, const char *fmt,...) { + int n; + jmp_buf jbuf; + Format format; + + if (setjmp(jbuf)) { + *format.buf = '\0'; + return format.buf - format.bufbegin; + } + + format.buf = buf; + format.bufbegin = buf; + format.bufend = buf + SPRINT_BUFSIZ - 1; + format.grow = snprint_grow; + format.flushed = 0; + format.u.p = jbuf; + + va_start(format.args, fmt); + n = printfmt(&format, fmt); + va_end(format.args); + + *format.buf = '\0'; + return n; +} +#endif