Change the printing mahine used by BIO_printf() and friends so it can

handle an externally provided "static" buffer as well a a dynamic
buffer.  The "static" buffer is filled first, but if overflowed, the
dynamic buffer is used instead, being allocated somewhere i the heap.

This combines the benefits of putting the output in a preallocated
buffer (on the stack, for example) and in a buffer that grows
somewhere in the heap.
This commit is contained in:
Richard Levitte 2000-09-07 05:50:14 +00:00
parent 47770c4dfb
commit 827dbcb150

View File

@ -113,24 +113,15 @@
#define LLONG long #define LLONG long
#endif #endif
static void fmtstr (void (*)(char **, size_t *, size_t *, int), static void fmtstr (char **, char **, size_t *, size_t *,
char **, size_t *, size_t *, const char *, int, int, const char *, int, int, int);
int); static void fmtint (char **, char **, size_t *, size_t *,
static void fmtint (void (*)(char **, size_t *, size_t *, int), LLONG, int, int, int, int);
char **, size_t *, size_t *, LLONG, int, int, int, int); static void fmtfp (char **, char **, size_t *, size_t *,
static void fmtfp (void (*)(char **, size_t *, size_t *, int), LDOUBLE, int, int, int);
char **, size_t *, size_t *, LDOUBLE, int, int, int); static void doapr_outch (char **, char **, size_t *, size_t *, int);
static int dopr_isbig (size_t, size_t); static void _dopr(char **sbuffer, char **buffer,
static int dopr_copy (size_t); size_t *maxlen, size_t *retlen, int *truncated,
static void dopr_outch (char **, size_t *, size_t *, int);
#ifdef USE_ALLOCATING_PRINT
static int doapr_isbig (size_t, size_t);
static int doapr_copy (size_t);
static void doapr_outch (char **, size_t *, size_t *, int);
#endif
static void _dopr(void (*)(char **, size_t *, size_t *, int),
int (*)(size_t, size_t), int (*)(size_t),
char **buffer, size_t *maxlen, size_t *retlen, int *truncated,
const char *format, va_list args); const char *format, va_list args);
/* format read states */ /* format read states */
@ -162,40 +153,9 @@ static void _dopr(void (*)(char **, size_t *, size_t *, int),
#define char_to_int(p) (p - '0') #define char_to_int(p) (p - '0')
#define MAX(p,q) ((p >= q) ? p : q) #define MAX(p,q) ((p >= q) ? p : q)
#ifndef USE_ALLOCATING_PRINT
static void
dopr(
char *buffer,
size_t maxlen,
size_t *retlen,
const char *format,
va_list args)
{
int ignored;
_dopr(dopr_outch, dopr_isbig, dopr_copy,
&buffer, &maxlen, retlen, &ignored, format, args);
}
#else
static void
doapr(
char **buffer,
size_t *retlen,
const char *format,
va_list args)
{
size_t dummy_maxlen = 0;
int ignored;
_dopr(doapr_outch, doapr_isbig, doapr_copy,
buffer, &dummy_maxlen, retlen, &ignored, format, args);
}
#endif
static void static void
_dopr( _dopr(
void (*outch_fn)(char **, size_t *, size_t *, int), char **sbuffer,
int (*isbig_fn)(size_t, size_t),
int (*copy_fn)(size_t),
char **buffer, char **buffer,
size_t *maxlen, size_t *maxlen,
size_t *retlen, size_t *retlen,
@ -220,7 +180,7 @@ _dopr(
ch = *format++; ch = *format++;
while (state != DP_S_DONE) { while (state != DP_S_DONE) {
if ((ch == '\0') || (*isbig_fn)(currlen, *maxlen)) if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
state = DP_S_DONE; state = DP_S_DONE;
switch (state) { switch (state) {
@ -228,7 +188,7 @@ _dopr(
if (ch == '%') if (ch == '%')
state = DP_S_FLAGS; state = DP_S_FLAGS;
else else
(*outch_fn)(buffer, &currlen, maxlen, ch); doapr_outch(sbuffer,buffer, &currlen, maxlen, ch);
ch = *format++; ch = *format++;
break; break;
case DP_S_FLAGS: case DP_S_FLAGS:
@ -334,7 +294,7 @@ _dopr(
value = va_arg(args, int); value = va_arg(args, int);
break; break;
} }
fmtint(outch_fn, buffer, &currlen, maxlen, fmtint(sbuffer, buffer, &currlen, maxlen,
value, 10, min, max, flags); value, 10, min, max, flags);
break; break;
case 'X': case 'X':
@ -360,7 +320,7 @@ _dopr(
unsigned int); unsigned int);
break; break;
} }
fmtint(outch_fn, buffer, &currlen, maxlen, value, fmtint(sbuffer, buffer, &currlen, maxlen, value,
ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
min, max, flags); min, max, flags);
break; break;
@ -369,7 +329,7 @@ _dopr(
fvalue = va_arg(args, LDOUBLE); fvalue = va_arg(args, LDOUBLE);
else else
fvalue = va_arg(args, double); fvalue = va_arg(args, double);
fmtfp(outch_fn, buffer, &currlen, maxlen, fmtfp(sbuffer, buffer, &currlen, maxlen,
fvalue, min, max, flags); fvalue, min, max, flags);
break; break;
case 'E': case 'E':
@ -389,19 +349,23 @@ _dopr(
fvalue = va_arg(args, double); fvalue = va_arg(args, double);
break; break;
case 'c': case 'c':
(*outch_fn)(buffer, &currlen, maxlen, doapr_outch(sbuffer, buffer, &currlen, maxlen,
va_arg(args, int)); va_arg(args, int));
break; break;
case 's': case 's':
strvalue = va_arg(args, char *); strvalue = va_arg(args, char *);
if (max < 0) if (max < 0) {
max = (*copy_fn)(*maxlen); if (buffer)
fmtstr(outch_fn, buffer, &currlen, maxlen, strvalue, max = INT_MAX;
else
max = *maxlen;
}
fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
flags, min, max); flags, min, max);
break; break;
case 'p': case 'p':
value = (long)va_arg(args, void *); value = (long)va_arg(args, void *);
fmtint(outch_fn, buffer, &currlen, maxlen, fmtint(sbuffer, buffer, &currlen, maxlen,
value, 16, min, max, flags); value, 16, min, max, flags);
break; break;
case 'n': /* XXX */ case 'n': /* XXX */
@ -424,7 +388,7 @@ _dopr(
} }
break; break;
case '%': case '%':
(*outch_fn)(buffer, &currlen, maxlen, ch); doapr_outch(sbuffer, buffer, &currlen, maxlen, ch);
break; break;
case 'w': case 'w':
/* not supported yet, treat as next char */ /* not supported yet, treat as next char */
@ -448,14 +412,14 @@ _dopr(
*truncated = (currlen > *maxlen - 1); *truncated = (currlen > *maxlen - 1);
if (*truncated) if (*truncated)
currlen = *maxlen - 1; currlen = *maxlen - 1;
(*buffer)[currlen] = '\0'; doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0');
*retlen = currlen; *retlen = currlen - 1;
return; return;
} }
static void static void
fmtstr( fmtstr(
void (*outch_fn)(char **, size_t *, size_t *, int), char **sbuffer,
char **buffer, char **buffer,
size_t *currlen, size_t *currlen,
size_t *maxlen, size_t *maxlen,
@ -478,16 +442,16 @@ fmtstr(
padlen = -padlen; padlen = -padlen;
while ((padlen > 0) && (cnt < max)) { while ((padlen > 0) && (cnt < max)) {
(*outch_fn)(buffer, currlen, maxlen, ' '); doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
--padlen; --padlen;
++cnt; ++cnt;
} }
while (*value && (cnt < max)) { while (*value && (cnt < max)) {
(*outch_fn)(buffer, currlen, maxlen, *value++); doapr_outch(sbuffer, buffer, currlen, maxlen, *value++);
++cnt; ++cnt;
} }
while ((padlen < 0) && (cnt < max)) { while ((padlen < 0) && (cnt < max)) {
(*outch_fn)(buffer, currlen, maxlen, ' '); doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
++padlen; ++padlen;
++cnt; ++cnt;
} }
@ -495,7 +459,7 @@ fmtstr(
static void static void
fmtint( fmtint(
void (*outch_fn)(char **, size_t *, size_t *, int), char **sbuffer,
char **buffer, char **buffer,
size_t *currlen, size_t *currlen,
size_t *maxlen, size_t *maxlen,
@ -552,28 +516,28 @@ fmtint(
/* spaces */ /* spaces */
while (spadlen > 0) { while (spadlen > 0) {
(*outch_fn)(buffer, currlen, maxlen, ' '); doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
--spadlen; --spadlen;
} }
/* sign */ /* sign */
if (signvalue) if (signvalue)
(*outch_fn)(buffer, currlen, maxlen, signvalue); doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
/* zeros */ /* zeros */
if (zpadlen > 0) { if (zpadlen > 0) {
while (zpadlen > 0) { while (zpadlen > 0) {
(*outch_fn)(buffer, currlen, maxlen, '0'); doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
--zpadlen; --zpadlen;
} }
} }
/* digits */ /* digits */
while (place > 0) while (place > 0)
(*outch_fn)(buffer, currlen, maxlen, convert[--place]); doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]);
/* left justified spaces */ /* left justified spaces */
while (spadlen < 0) { while (spadlen < 0) {
(*outch_fn)(buffer, currlen, maxlen, ' '); doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
++spadlen; ++spadlen;
} }
return; return;
@ -612,7 +576,7 @@ round(LDOUBLE value)
static void static void
fmtfp( fmtfp(
void (*outch_fn)(char **, size_t *, size_t *, int), char **sbuffer,
char **buffer, char **buffer,
size_t *currlen, size_t *currlen,
size_t *maxlen, size_t *maxlen,
@ -693,117 +657,85 @@ fmtfp(
if ((flags & DP_F_ZERO) && (padlen > 0)) { if ((flags & DP_F_ZERO) && (padlen > 0)) {
if (signvalue) { if (signvalue) {
(*outch_fn)(buffer, currlen, maxlen, signvalue); doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
--padlen; --padlen;
signvalue = 0; signvalue = 0;
} }
while (padlen > 0) { while (padlen > 0) {
(*outch_fn)(buffer, currlen, maxlen, '0'); doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
--padlen; --padlen;
} }
} }
while (padlen > 0) { while (padlen > 0) {
(*outch_fn)(buffer, currlen, maxlen, ' '); doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
--padlen; --padlen;
} }
if (signvalue) if (signvalue)
(*outch_fn)(buffer, currlen, maxlen, signvalue); doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue);
while (iplace > 0) while (iplace > 0)
(*outch_fn)(buffer, currlen, maxlen, iconvert[--iplace]); doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]);
/* /*
* Decimal point. This should probably use locale to find the correct * Decimal point. This should probably use locale to find the correct
* char to print out. * char to print out.
*/ */
if (max > 0) { if (max > 0) {
(*outch_fn)(buffer, currlen, maxlen, '.'); doapr_outch(sbuffer, buffer, currlen, maxlen, '.');
while (fplace > 0) while (fplace > 0)
(*outch_fn)(buffer, currlen, maxlen, fconvert[--fplace]); doapr_outch(sbuffer, buffer, currlen, maxlen, fconvert[--fplace]);
} }
while (zpadlen > 0) { while (zpadlen > 0) {
(*outch_fn)(buffer, currlen, maxlen, '0'); doapr_outch(sbuffer, buffer, currlen, maxlen, '0');
--zpadlen; --zpadlen;
} }
while (padlen < 0) { while (padlen < 0) {
(*outch_fn)(buffer, currlen, maxlen, ' '); doapr_outch(sbuffer, buffer, currlen, maxlen, ' ');
++padlen; ++padlen;
} }
} }
static int
dopr_copy(
size_t len)
{
return len;
}
#ifdef USE_ALLOCATING_PRINT
static int
doapr_copy(
size_t len)
{
/* Return as high an integer as possible */
return INT_MAX;
}
#endif
static int
dopr_isbig(
size_t currlen,
size_t maxlen)
{
return currlen > maxlen;
}
#ifdef USE_ALLOCATING_PRINT
static int
doapr_isbig(
size_t currlen,
size_t maxlen)
{
return 0;
}
#endif
static void
dopr_outch(
char **buffer,
size_t *currlen,
size_t *maxlen,
int c)
{
if (*currlen < *maxlen)
(*buffer)[(*currlen)++] = (char)c;
return;
}
#ifdef USE_ALLOCATING_PRINT
static void static void
doapr_outch( doapr_outch(
char **sbuffer,
char **buffer, char **buffer,
size_t *currlen, size_t *currlen,
size_t *maxlen, size_t *maxlen,
int c) int c)
{ {
/* If we haven't at least one buffer, someone has doe a big booboo */
assert(*sbuffer != NULL || buffer != NULL);
if (buffer) {
while (*currlen >= *maxlen) {
if (*buffer == NULL) { if (*buffer == NULL) {
assert(*sbuffer != NULL);
if (*maxlen == 0) if (*maxlen == 0)
*maxlen = 1024; *maxlen = 1024;
*buffer = OPENSSL_malloc(*maxlen); *buffer = OPENSSL_malloc(*maxlen);
} if (*currlen > 0)
while (*currlen >= *maxlen) { memcpy(*buffer, *sbuffer, *currlen);
*sbuffer = NULL;
} else {
*maxlen += 1024; *maxlen += 1024;
*buffer = OPENSSL_realloc(*buffer, *maxlen); *buffer = OPENSSL_realloc(*buffer, *maxlen);
} }
}
/* What to do if *buffer is NULL? */ /* What to do if *buffer is NULL? */
assert(*buffer != NULL); assert(*sbuffer != NULL || *buffer != NULL);
}
if (*currlen < *maxlen) {
if (*sbuffer)
(*sbuffer)[(*currlen)++] = (char)c;
else
(*buffer)[(*currlen)++] = (char)c; (*buffer)[(*currlen)++] = (char)c;
}
return; return;
} }
#endif
/***************************************************************************/ /***************************************************************************/
@ -824,29 +756,26 @@ int BIO_vprintf (BIO *bio, const char *format, va_list args)
{ {
int ret; int ret;
size_t retlen; size_t retlen;
#ifdef USE_ALLOCATING_PRINT
char *hugebuf;
#else
MS_STATIC char hugebuf[1024*10]; MS_STATIC char hugebuf[1024*10];
#endif char *hugebufp = hugebuf;
size_t hugebufsize = sizeof(hugebuf);
char *dynbuf = NULL;
int ignored;
#ifndef USE_ALLOCATING_PRINT dynbuf = NULL;
hugebuf[0]='\0';
dopr(hugebuf, sizeof(hugebuf), &retlen, format, args);
#else
hugebuf = NULL;
CRYPTO_push_info("doapr()"); CRYPTO_push_info("doapr()");
doapr(&hugebuf, &retlen, format, args); _dopr(&hugebufp, &dynbuf, &hugebufsize,
if (hugebuf) &retlen, &ignored, format, args);
if (dynbuf)
{
ret=BIO_write(bio, dynbuf, (int)retlen);
OPENSSL_free(dynbuf);
}
else
{ {
#endif
ret=BIO_write(bio, hugebuf, (int)retlen); ret=BIO_write(bio, hugebuf, (int)retlen);
#ifdef USE_ALLOCATING_PRINT
OPENSSL_free(hugebuf);
} }
CRYPTO_pop_info(); CRYPTO_pop_info();
#endif
return(ret); return(ret);
} }
@ -872,8 +801,8 @@ int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
size_t retlen; size_t retlen;
int truncated; int truncated;
_dopr(dopr_outch, dopr_isbig, dopr_copy, _dopr(&buf, NULL, &n, &retlen, &truncated, format, args);
&buf, &n, &retlen, &truncated, format, args);
if (truncated) if (truncated)
/* In case of truncation, return -1 like traditional snprintf. /* In case of truncation, return -1 like traditional snprintf.
* (Current drafts for ISO/IEC 9899 say snprintf should return * (Current drafts for ISO/IEC 9899 say snprintf should return