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:
parent
47770c4dfb
commit
827dbcb150
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user