From 002eaee36ed12caf6cf7f2a7188111240a427d80 Mon Sep 17 00:00:00 2001 Message-Id: <002eaee36ed12caf6cf7f2a7188111240a427d80.1716645419.git.mdw@distorted.org.uk> From: Mark Wooding Date: Mon, 4 Oct 1999 21:44:47 +0000 Subject: [PATCH] Move `dstr_putf' and `dstr_vputf' into a separate source file. Organization: Straylight/Edgeware From: mdw --- dputf.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dstr.c | 262 +----------------------------------------------- 2 files changed, 308 insertions(+), 257 deletions(-) create mode 100644 dputf.c diff --git a/dputf.c b/dputf.c new file mode 100644 index 0000000..9c827bc --- /dev/null +++ b/dputf.c @@ -0,0 +1,303 @@ +/* -*-c-*- + * + * $Id: dputf.c,v 1.1 1999/10/04 21:44:47 mdw Exp $ + * + * `printf'-style formatting for dynamic strings + * + * (c) 1999 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the mLib utilities library. + * + * mLib is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * mLib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with mLib; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Revision history --------------------------------------------------* + * + * $Log: dputf.c,v $ + * Revision 1.1 1999/10/04 21:44:47 mdw + * Move `dstr_putf' and `dstr_vputf' into a separate source file. + * + */ + +/*----- Header files ------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include + +#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@ */ + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @dstr_vputf@ --- * + * + * Arguments: @dstr *d@ = pointer to a dynamic string block + * @const char *p@ = pointer to @printf@-style format string + * @va_list ap@ = argument handle + * + * Returns: The number of characters written to the string. + * + * Use: As for @dstr_putf@, but may be used as a back-end to user- + * 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; + + enum { + f_short = 1, + f_long = 2, + f_Long = 4, + f_wd = 8, + f_prec = 16 + }; + + /* --- 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; + + /* --- Field widths and precision specifiers --- */ + + { + int *ip; + + case '.': + DPUTC(&dd, '.'); + ip = ≺ + f |= f_prec; + 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; + + case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': + 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) == 0) + prec = 6; + if ((f & f_prec)) + 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; + + 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 char)); + 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; + } + + DPUTM(d, q, p - q); +finished: + DPUTZ(d); + DDESTROY(&dd); + return (d->len - n); +} + +/* --- @dstr_putf@ --- * + * + * Arguments: @dstr *d@ = pointer to a dynamic string block + * @const char *p@ = pointer to @printf@-style format string + * @...@ = argument handle + * + * Returns: The number of characters written to the string. + * + * Use: Writes a piece of text to a dynamic string, doing @printf@- + * style substitutions as it goes. Intended to be robust if + * faced with malicious arguments, but not if the format string + * itself is malicious. + */ + +int dstr_putf(dstr *d, const char *p, ...) +{ + int n; + va_list ap; + va_start(ap, p); + n = dstr_vputf(d, p, ap); + va_end(ap); + return (n); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/dstr.c b/dstr.c index e43e138..82f0805 100644 --- a/dstr.c +++ b/dstr.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: dstr.c,v 1.9 1999/07/06 19:16:06 mdw Exp $ + * $Id: dstr.c,v 1.10 1999/10/04 21:44:47 mdw Exp $ * * Handle dynamically growing strings * @@ -30,6 +30,9 @@ /*----- Revision history --------------------------------------------------* * * $Log: dstr.c,v $ + * Revision 1.10 1999/10/04 21:44:47 mdw + * Move `dstr_putf' and `dstr_vputf' into a separate source file. + * * Revision 1.9 1999/07/06 19:16:06 mdw * Simplify buffer-growing algorithm. Just double it each time. * @@ -62,10 +65,6 @@ /*----- Header files ------------------------------------------------------*/ -#include -#include -#include -#include #include #include #include @@ -75,8 +74,7 @@ /*----- Tunable constants -------------------------------------------------*/ -/* --- Buffer expansion parameters --- * - * +/* * If the buffer is empty, it is set to @DSTR_INITSZ@ bytes in size. * Otherwise, it's set to the next power of two that's large enough. This is * memory-hungry, but efficient. @@ -84,14 +82,6 @@ #define DSTR_INITSZ 256 /* Initial buffer size */ -/* --- Parameters for @dstr_putf@ --- * - * - * For each format specifier, at least @DSTR_PUTFSTEP@ bytes are ensured - * before writing the formatted result. - */ - -#define DSTR_PUTFSTEP 64 /* Buffer size for @putf@ */ - /*----- Main code ---------------------------------------------------------*/ /* --- @dstr_create@ --- * @@ -202,248 +192,6 @@ void dstr_putz(dstr *d) { DPUTZ(d); } void dstr_puts(dstr *d, const char *s) { DPUTS(d, s); } -/* --- @dstr_vputf@ --- * - * - * Arguments: @dstr *d@ = pointer to a dynamic string block - * @const char *p@ = pointer to @printf@-style format string - * @va_list ap@ = argument handle - * - * Returns: The number of characters written to the string. - * - * Use: As for @dstr_putf@, but may be used as a back-end to user- - * 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; - - enum { - f_short = 1, - f_long = 2, - f_Long = 4, - f_wd = 8, - f_prec = 16 - }; - - /* --- 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; - - /* --- Field widths and precision specifiers --- */ - - { - int *ip; - - case '.': - DPUTC(&dd, '.'); - ip = ≺ - f |= f_prec; - 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; - - case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': - 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) == 0) - prec = 6; - if ((f & f_prec)) - 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; - - 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 char)); - 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; - } - - DPUTM(d, q, p - q); -finished: - DPUTZ(d); - DDESTROY(&dd); - return (d->len - n); -} - -/* --- @dstr_putf@ --- * - * - * Arguments: @dstr *d@ = pointer to a dynamic string block - * @const char *p@ = pointer to @printf@-style format string - * @...@ = argument handle - * - * Returns: The number of characters written to the string. - * - * Use: Writes a piece of text to a dynamic string, doing @printf@- - * style substitutions as it goes. Intended to be robust if - * faced with malicious arguments, but not if the format string - * itself is malicious. - */ - -int dstr_putf(dstr *d, const char *p, ...) -{ - int n; - va_list ap; - va_start(ap, p); - n = dstr_vputf(d, p, ap); - va_end(ap); - return (n); -} - /* --- @dstr_putd@ --- * * * Arguments: @dstr *d@ = pointer to a dynamic string block -- [mdw]