X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/0fbb1412198acf1954c9e8dad34358b3fff36aa4..f23d010aa281711352a1e8ea2b8d631742a41b82:/dstr.c diff --git a/dstr.c b/dstr.c index 86cde6e..cda48a2 100644 --- a/dstr.c +++ b/dstr.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: dstr.c,v 1.8 1999/06/01 09:47:52 mdw Exp $ + * $Id: dstr.c,v 1.16 2004/04/08 01:36:11 mdw Exp $ * * Handle dynamically growing strings * * (c) 1998 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of the mLib utilities library. * @@ -15,54 +15,20 @@ * 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: dstr.c,v $ - * 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. - * - * Revision 1.2 1998/12/15 23:53:22 mdw - * New functions `dstr_putf' and `dstr_vputf' which do `printf'-style - * formatting in a safe way. - * - * Revision 1.1.1.1 1998/06/17 23:44:42 mdw - * Initial version of mLib - * - */ - /*----- Header files ------------------------------------------------------*/ -#include -#include -#include -#include #include #include #include @@ -72,9 +38,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 ---------------------------------------------------------*/ @@ -102,7 +72,7 @@ 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: --- * @@ -132,27 +102,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; } @@ -194,248 +155,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 @@ -473,8 +192,8 @@ void dstr_putm(dstr *d, const void *p, size_t sz) { DPUTM(d, p, 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; } @@ -500,13 +219,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); @@ -516,6 +228,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') {