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