X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/c846879ccf3e86ea293c157f4aa2ff8716fb5b4c..78b1464e4a78dc364ecc8aebcfd5ec13b3f6bb07:/dstr.c diff --git a/dstr.c b/dstr.c index 06a621e..273c53a 100644 --- a/dstr.c +++ b/dstr.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: dstr.c,v 1.3 1999/05/05 18:50:31 mdw Exp $ + * $Id: dstr.c,v 1.15 2000/07/16 12:29:16 mdw Exp $ * * Handle dynamically growing strings * @@ -22,13 +22,50 @@ * 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. + * 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: dstr.c,v $ + * Revision 1.15 2000/07/16 12:29:16 mdw + * Change to arena `realloc' interface, to fix a design bug. + * + * Revision 1.14 2000/06/17 10:37:39 mdw + * Add support for arena management. + * + * Revision 1.13 1999/12/22 15:39:28 mdw + * Fix overflow in dstr_putline. + * + * Revision 1.12 1999/12/10 23:42:04 mdw + * Change header file guard names. + * + * Revision 1.11 1999/10/28 22:05:29 mdw + * Modify and debug allocation routines. + * + * 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. + * + * Revision 1.8 1999/06/01 09:47:52 mdw + * Fix nasty bugs in `dstr_vputf'. + * + * Revision 1.7 1999/05/21 22:14:30 mdw + * Take advantage of the new dynamic string macros. + * + * Revision 1.6 1999/05/21 08:38:33 mdw + * Implement some more functions in terms of macros. + * + * Revision 1.5 1999/05/13 22:47:57 mdw + * Misc documentation fixes. Change `-ise' to `-ize' throughout. + * + * Revision 1.4 1999/05/06 19:51:35 mdw + * Reformatted the LGPL notice a little bit. + * * Revision 1.3 1999/05/05 18:50:31 mdw * Change licensing conditions to LGPL. * @@ -43,10 +80,6 @@ /*----- Header files ------------------------------------------------------*/ -#include -#include -#include -#include #include #include #include @@ -56,9 +89,13 @@ /*----- Tunable constants -------------------------------------------------*/ -#define DSTR_INITSZ 256 /* Initial buffer size */ -#define DSTR_INCSZ 4096 /* Threshhold for doubling */ -#define DSTR_PUTFSTEP 64 /* Buffer size for @putf@ */ +/* + * 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. + */ + +#define DSTR_INITSZ 64 /* Initial buffer size */ /*----- Main code ---------------------------------------------------------*/ @@ -68,15 +105,10 @@ * * Returns: --- * - * Use: Initialises a dynamic string. + * Use: Initializes a dynamic string. */ -void dstr_create(dstr *d) -{ - d->sz = 0; - d->len = 0; - d->buf = 0; -} +void dstr_create(dstr *d) { DCREATE(d); } /* --- @dstr_destroy@ --- * * @@ -87,28 +119,18 @@ void dstr_create(dstr *d) * Use: Reclaims the space used by a dynamic string. */ -void dstr_destroy(dstr *d) -{ - if (d->buf) - free(d->buf); - d->buf = 0; - d->len = 0; - d->sz = 0; -} +void dstr_destroy(dstr *d) { DDESTROY(d); } /* --- @dstr_reset@ --- * * - * Arguments: @dstr *d@ = pointer to a dynaimc string block + * Arguments: @dstr *d@ = pointer to a dynamic string block * * Returns: --- * * Use: Resets a string so that new data gets put at the beginning. */ -void dstr_reset(dstr *d) -{ - d->len = 0; -} +void dstr_reset(dstr *d) { DRESET(d); } /* --- @dstr_ensure@ --- * * @@ -131,27 +153,18 @@ void dstr_ensure(dstr *d, size_t sz) if (rq <= d->sz) return; - /* --- Grow the buffer --- * - * - * For small buffers, just double the size. For big buffers, make them - * a multiple of some suitably large chunk size. - */ + /* --- Grow the buffer --- */ nsz = d->sz; - do { - if (nsz == 0) - nsz = DSTR_INITSZ; - else if (d->sz < 0x1000) - nsz <<= 1; - else - nsz = (rq + 0x0fff) & ~0x0fff; - } while (rq > nsz); + if (nsz == 0) + nsz = (DSTR_INITSZ >> 1); + do nsz <<= 1; while (nsz < rq); if (d->buf) - d->buf = xrealloc(d->buf, nsz); + d->buf = x_realloc(d->a, d->buf, nsz, d->sz); else - d->buf = xmalloc(nsz); + d->buf = x_alloc(d->a, nsz); d->sz = nsz; } @@ -165,10 +178,7 @@ void dstr_ensure(dstr *d, size_t sz) * Use: Appends a character to a string. */ -void dstr_putc(dstr *d, char ch) -{ - DPUTC(d, ch); -} +void dstr_putc(dstr *d, char ch) { DPUTC(d, ch); } /* --- @dstr_putz@ --- * * @@ -181,10 +191,7 @@ void dstr_putc(dstr *d, char ch) * by subsequent `put' operations. */ -void dstr_putz(dstr *d) -{ - DPUTZ(d); -} +void dstr_putz(dstr *d) { DPUTZ(d); } /* --- @dstr_puts@ --- * * @@ -197,252 +204,7 @@ void dstr_putz(dstr *d) * byte is added, as for @dstr_putz@. */ -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: --- - * - * 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; - - while (*p) { - unsigned f; - int wd, prec; - dstr dd; - - 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 --- */ - - dstr_create(&dd); - 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_prec; - 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: - dstr_destroy(&dd); - q = ++p; - } - - DPUTM(d, q, p - q); -finished: - DPUTZ(d); - 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: --- - * - * 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); -} +void dstr_puts(dstr *d, const char *s) { DPUTS(d, s); } /* --- @dstr_putd@ --- * * @@ -455,10 +217,7 @@ int dstr_putf(dstr *d, const char *p, ...) * byte is added, as for @dstr_putz@. */ -void dstr_putd(dstr *d, const dstr *s) -{ - DPUTD(d, s); -} +void dstr_putd(dstr *d, const dstr *s) { DPUTD(d, s); } /* --- @dstr_putm@ --- * * @@ -470,10 +229,7 @@ void dstr_putd(dstr *d, const dstr *s) * null is appended. */ -void dstr_putm(dstr *d, const void *p, size_t sz) -{ - DPUTM(d, p, sz); -} +void dstr_putm(dstr *d, const void *p, size_t sz) { DPUTM(d, p, sz); } /* --- @dstr_tidy@ --- * * @@ -487,8 +243,8 @@ void dstr_putm(dstr *d, const void *p, size_t sz) void dstr_tidy(dstr *d) { - dstr_putz(d); - d->buf = xrealloc(d->buf, d->len + 1); + d->buf = x_realloc(d->a, d->buf, d->len + 1, d->sz); + d->buf[d->len] = 0; d->sz = d->len + 1; } @@ -514,13 +270,6 @@ int dstr_putline(dstr *d, FILE *fp) for (;;) { - /* --- Make sure there's some buffer space --- */ - - if (!left) { - dstr_ensure(d, 1); - left = d->sz - off; - } - /* --- Read the next byte --- */ ch = getc(fp); @@ -530,6 +279,14 @@ int dstr_putline(dstr *d, FILE *fp) if (ch == EOF && !rd) return (EOF); + /* --- Make sure there's some buffer space --- */ + + if (!left) { + d->len = off; + dstr_ensure(d, 1); + left = d->sz - off; + } + /* --- End-of-file or newline ends the loop --- */ if (ch == EOF || ch == '\n') { @@ -555,9 +312,6 @@ int dstr_putline(dstr *d, FILE *fp) * Use: Writes a dynamic string to a file. */ -size_t dstr_write(dstr *d, FILE *fp) -{ - return (fwrite(d->buf, 1, d->len, fp)); -} +size_t dstr_write(const dstr *d, FILE *fp) { return (DWRITE(d, fp)); } /*----- That's all, folks -------------------------------------------------*/