X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/18c831dcd0ae4d660c70ccac69d27ed2a97851be..c81c35dfd10050ffef85d57dc2ad73f52f38a3f2:/struct/dstr-putf.c diff --git a/struct/dstr-putf.c b/struct/dstr-putf.c index 38eb8f6..48c2f6a 100644 --- a/struct/dstr-putf.c +++ b/struct/dstr-putf.c @@ -29,27 +29,12 @@ #include "config.h" -#include -#include #include +#include #include -#include -#include - -#ifdef HAVE_FLOAT_H -# include -#endif #include "dstr.h" - -/*----- Tunable constants -------------------------------------------------*/ - -/* - * For each format specifier, at least @DSTR_PUTFSTEP@ bytes are ensured - * before writing the formatted result. - */ - -#define DSTR_PUTFSTEP 64 /* Buffer size for @putf@ */ +#include "gprintf.h" /*----- Main code ---------------------------------------------------------*/ @@ -65,220 +50,33 @@ * supplied functions with @printf@-style interfaces. */ -int dstr_vputf(dstr *d, const char *p, va_list *ap) -{ - const char *q = p; - size_t n = d->len; - size_t sz; - dstr dd = DSTR_INIT; - - while (*p) { - unsigned f; - int wd, prec; - -#define f_short 1u -#define f_long 2u -#define f_Long 4u -#define f_wd 8u -#define f_prec 16u - - /* --- Most stuff gets passed on through --- */ - - if (*p != '%') { - p++; - continue; - } - - /* --- Dump out what's between @q@ and @p@ --- */ - - DPUTM(d, q, p - q); - p++; - - /* --- Sort out the various silly flags and things --- */ - - DPUTC(&dd, '%'); - f = 0; - sz = DSTR_PUTFSTEP; - - for (;;) { - switch (*p) { - - /* --- Various simple flags --- */ - - case '+': - case '-': - case '#': - case '0': - goto putch; - case 'h': - f |= f_short; - goto putch; - case 'l': - f |= f_long; - goto putch; - case 'L': - f |= f_Long; - goto putch; - case 0: - goto finished; +static int putch(void *out, int ch) + { dstr *d = out; DPUTC(d, ch); return (0); } +static int putm(void *out, const char *p, size_t sz) + { dstr *d = out; DPUTM(d, p, sz); return (0); } - /* --- Field widths and precision specifiers --- */ - - { - int *ip; - - case '.': - DPUTC(&dd, '.'); - ip = ≺ - f |= f_prec; - p++; - goto getnum; - case '*': - ip = &wd; - f |= f_wd; - goto getnum; - default: - if (isdigit((unsigned char)*p)) { - f |= f_wd; - ip = &wd; - goto getnum; - } - DPUTC(d, *p); - goto formatted; - getnum: - *ip = 0; - if (*p == '*') { - *ip = va_arg(*ap, int); - DENSURE(&dd, DSTR_PUTFSTEP); - dd.len += sprintf(dd.buf + dd.len, "%i", *ip); - } else { - *ip = *p - '0'; - DPUTC(&dd, *p); - p++; - while (isdigit((unsigned char)*p)) { - DPUTC(&dd, *p); - *ip = 10 * *ip + *p++ - '0'; - } - } - break; - } - - /* --- Output formatting --- */ - - case 'd': case 'i': case 'x': case 'X': case 'o': case 'u': - DPUTC(&dd, *p); - DPUTZ(&dd); - if ((f & f_prec) && prec + 16 > sz) - sz = prec + 16; - if ((f & f_wd) && wd + 1> sz) - sz = wd + 1; - DENSURE(d, sz); - if (f & f_long) - d->len += sprintf(d->buf + d->len, dd.buf, - va_arg(*ap, unsigned long)); - else - d->len += sprintf(d->buf + d->len, dd.buf, - va_arg(*ap, unsigned int)); - goto formatted; +static int nputf(void *out, size_t maxsz, const char *p, ...) +{ + dstr *d = out; + va_list ap; + int n; - case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': -#ifdef HAVE_FLOAT_H - DPUTC(&dd, *p); - DPUTZ(&dd); - if (*p == 'f') { - size_t mx = (f & f_Long ? LDBL_MAX_10_EXP : DBL_MAX_10_EXP) + 16; - if (mx > sz) - sz = mx; - } - if (!(f & f_prec)) - prec = 6; - else - sz += prec + 16; - if ((f & f_wd) && wd + 1 > sz) - sz = wd + 1; - DENSURE(d, sz); - if (f & f_Long) - d->len += sprintf(d->buf + d->len, dd.buf, - va_arg(*ap, long double)); - else - d->len += sprintf(d->buf + d->len, dd.buf, - va_arg(*ap, double)); - goto formatted; + va_start(ap, p); + DENSURE(d, maxsz + 1); +#ifdef HAVE_SNPRINTF + n = vsnprintf(d->buf + d->len, maxsz + 1, p, ap); #else - DPUTS(d, ""); + n = vsprintf(d->buf + d->len, p, ap); #endif + assert(0 <= n && n <= maxsz); + va_end(ap); d->len += n; return (n); +} - case 'c': - DPUTC(&dd, *p); - DPUTZ(&dd); - if ((f & f_wd) && wd + 1> sz) - sz = wd + 1; - DENSURE(d, sz); - d->len += sprintf(d->buf + d->len, dd.buf, - va_arg(*ap, unsigned)); - goto formatted; - - case 's': { - const char *s = va_arg(*ap, const char *); - sz = strlen(s); - DPUTC(&dd, *p); - DPUTZ(&dd); - if (f & f_prec) - sz = prec; - if ((f & f_wd) && wd > sz) - sz = wd; - DENSURE(d, sz + 1); - d->len += sprintf(d->buf + d->len, dd.buf, s); - goto formatted; - } - - case 'p': - DPUTC(&dd, *p); - DPUTZ(&dd); - if ((f & f_prec) && prec + 16 > sz) - sz = prec + 16; - if ((f & f_wd) && wd + 1> sz) - sz = wd + 1; - DENSURE(d, sz); - d->len += sprintf(d->buf + d->len, dd.buf, - va_arg(*ap, const void *)); - goto formatted; - - case 'n': - if (f & f_long) - *va_arg(*ap, long *) = (long)(d->len - n); - else if (f & f_short) - *va_arg(*ap, short *) = (short)(d->len - n); - else - *va_arg(*ap, int *) = (int)(d->len - n); - goto formatted; - - /* --- Other random stuff --- */ - - putch: - DPUTC(&dd, *p); - p++; - break; - } - } - - formatted: - DRESET(&dd); - q = ++p; - -#undef f_short -#undef f_long -#undef f_Long -#undef f_wd -#undef f_prec - } +const struct gprintf_ops dstr_printops = + { putch, putm, nputf }; - DPUTM(d, q, p - q); -finished: - DPUTZ(d); - DDESTROY(&dd); - return (d->len - n); -} +int dstr_vputf(dstr *d, const char *p, va_list *ap) + { int n = vgprintf(&dstr_printops, d, p, ap); DPUTZ(d); return (n); } /* --- @dstr_putf@ --- * *