1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-18 08:23:51 +03:00
Files
samba-mirror/source/lib/appweb/ejs-2.0/mpr/mprPrintf.c

925 lines
22 KiB
C

/**
* @file mprPrintf.c
* @brief Printf routines safe for embedded programming
* @overview This module provides safe replacements for the standard
* printf formatting routines.
* @remarks Most routines in this file are not thread-safe. It is the callers
* responsibility to perform all thread synchronization.
*/
/*
* @copy default
*
* Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
*
* This software is distributed under commercial and open source licenses.
* You may use the GPL open source license described below or you may acquire
* a commercial license from Mbedthis Software. You agree to be fully bound
* by the terms of either license. Consult the LICENSE.TXT distributed with
* this software for full details.
*
* This software is open source; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See the GNU General Public License for more
* details at: http://www.mbedthis.com/downloads/gplLicense.html
*
* This program is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* This GPL license does NOT permit incorporating this software into
* proprietary programs. If you are unable to comply with the GPL, you must
* acquire a commercial license to use this software. Commercial licenses
* for this software and support services are available from Mbedthis
* Software at http://www.mbedthis.com
*
* @end
*/
/********************************** Includes **********************************/
/*
* We need to use the underlying str(cpy) routines to implement our safe
* alternatives
*/
#if !DOXYGEN
#define UNSAFE_FUNCTIONS_OK 1
#endif
#include "mpr.h"
/*********************************** Defines **********************************/
/*
* Class definitions
*/
#define CLASS_NORMAL 0 /* [All other] Normal characters */
#define CLASS_PERCENT 1 /* [%] Begin format */
#define CLASS_MODIFIER 2 /* [-+ #,] Modifiers */
#define CLASS_ZERO 3 /* [0] Special modifier */
#define CLASS_STAR 4 /* [*] Width supplied by arg */
#define CLASS_DIGIT 5 /* [1-9] Field widths */
#define CLASS_DOT 6 /* [.] Introduce precision */
#define CLASS_BITS 7 /* [hlL] Length bits */
#define CLASS_TYPE 8 /* [cdfinopsSuxX] Type specifiers */
#define STATE_NORMAL 0 /* Normal chars in format string */
#define STATE_PERCENT 1 /* "%" */
#define STATE_MODIFIER 2 /* Read flag */
#define STATE_WIDTH 3 /* Width spec */
#define STATE_DOT 4 /* "." */
#define STATE_PRECISION 5 /* Precision spec */
#define STATE_BITS 6 /* Size spec */
#define STATE_TYPE 7 /* Data type */
#define STATE_COUNT 8
/*
* Format: %[modifier][width][precision][bits][type]
*
* #define CLASS_MODIFIER 2 [-+ #,] Modifiers
* #define CLASS_BITS 7 [hlL] Length bits
*/
/*
* Flags
*/
#define SPRINTF_LEFT 0x1 /* Left align */
#define SPRINTF_SIGN 0x2 /* Always sign the result */
#define SPRINTF_LEAD_SPACE 0x4 /* put leading space for +ve numbers */
#define SPRINTF_ALTERNATE 0x8 /* Alternate format */
#define SPRINTF_LEAD_ZERO 0x10 /* Zero pad */
#define SPRINTF_SHORT 0x20 /* 16-bit */
#define SPRINTF_LONG 0x40 /* 32-bit */
#if BLD_FEATURE_INT64
#define SPRINTF_LONGLONG 0x80 /* 64-bit */
#endif
#define SPRINTF_COMMA 0x100 /* Thousand comma separators */
#define SPRINTF_UPPER_CASE 0x200 /* As the name says for numbers */
typedef struct Format {
uchar *buf;
uchar *endbuf;
uchar *start;
uchar *end;
int growBy;
int maxsize;
int precision;
int radix;
int width;
int flags;
int len;
} Format;
static int growBuf(MPR_LOC_DEC(ctx, loc), Format *fmt);
#define BPUT(ctx, loc, fmt, c) \
if (1) { \
/* Less one to allow room for the null */ \
if ((fmt)->end >= ((fmt)->endbuf - sizeof(char))) { \
if (growBuf(MPR_LOC_PASS(ctx, loc), fmt)) { \
*(fmt)->end++ = (c); \
} \
} else { \
*(fmt)->end++ = (c); \
} \
} else
#define BPUTNULL(ctx, loc, fmt) \
if (1) { \
if ((fmt)->end > (fmt)->endbuf) { \
if (growBuf(MPR_LOC_PASS(ctx, loc), fmt)) { \
*(fmt)->end = '\0'; \
} \
} else { \
*(fmt)->end = '\0'; \
} \
} else
/******************************************************************************/
#if BLD_FEATURE_INT64
#define unum uint64
#define num int64
#else
#define unum uint
#define num int
#endif
/***************************** Forward Declarations ***************************/
#ifdef __cplusplus
extern "C" {
#endif
static int getState(char c, int state);
static int mprSprintfCore(MPR_LOC_DEC(ctx, loc), char **s,
int maxsize, const char *fmt, va_list arg);
static void outNum(MPR_LOC_DEC(ctx, loc), Format *fmt, const char *prefix,
unum val);
#if BLD_FEATURE_FLOATING_POINT
static void outFloat(MPR_LOC_DEC(ctx, loc), Format *fmt, char specChar,
double value);
#endif
/******************************************************************************/
int mprPrintf(MprCtx ctx, const char *fmt, ...)
{
va_list ap;
char *buf;
int len;
MprApp *app;
/* No asserts here as this is used as part of assert reporting */
app = mprGetApp(ctx);
va_start(ap, fmt);
len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, ap);
va_end(ap);
if (len >= 0 && app->console) {
len = mprWrite(app->console, buf, len);
}
mprFree(buf);
return len;
}
/******************************************************************************/
int mprErrorPrintf(MprCtx ctx, const char *fmt, ...)
{
va_list ap;
char *buf;
int len;
MprApp *app;
/* No asserts here as this is used as part of assert reporting */
app = mprGetApp(ctx);
va_start(ap, fmt);
len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, ap);
va_end(ap);
if (len >= 0 && app->error) {
len = mprWrite(app->error, buf, len);
}
mprFree(buf);
return len;
}
/******************************************************************************/
int mprFprintf(MprFile *file, const char *fmt, ...)
{
va_list ap;
char *buf;
int len;
if (file == 0) {
return MPR_ERR_BAD_HANDLE;
}
va_start(ap, fmt);
len = mprAllocVsprintf(MPR_LOC_ARGS(file), &buf, 0, fmt, ap);
va_end(ap);
if (len >= 0) {
len = mprWrite(file, buf, len);
}
mprFree(buf);
return len;
}
/******************************************************************************/
/*
* Printf with a static buffer. Used internally only. WILL NOT MALLOC.
*/
int mprStaticPrintf(MprCtx ctx, const char *fmt, ...)
{
va_list ap;
char buf[MPR_MAX_STRING];
char *bufp;
int len;
MprApp *app;
app = mprGetApp(ctx);
va_start(ap, fmt);
bufp = buf;
len = mprSprintfCore(MPR_LOC_ARGS(0), &bufp, MPR_MAX_STRING, fmt, ap);
va_end(ap);
if (len >= 0) {
len = mprWrite(app->console, buf, len);
}
return len;
}
/******************************************************************************/
int mprSprintf(char *buf, int n, const char *fmt, ...)
{
va_list ap;
int result;
mprAssert(buf);
mprAssert(fmt);
mprAssert(n > 0);
va_start(ap, fmt);
result = mprSprintfCore(MPR_LOC_ARGS(0), &buf, n, fmt, ap);
va_end(ap);
return result;
}
/******************************************************************************/
int mprVsprintf(char *buf, int n, const char *fmt, va_list arg)
{
mprAssert(buf);
mprAssert(fmt);
mprAssert(n > 0);
return mprSprintfCore(MPR_LOC_ARGS(0), &buf, n, fmt, arg);
}
/******************************************************************************/
int mprAllocSprintf(MPR_LOC_DEC(ctx, loc), char **buf, int maxSize,
const char *fmt, ...)
{
va_list ap;
int result;
mprAssert(buf);
mprAssert(fmt);
*buf = 0;
va_start(ap, fmt);
result = mprSprintfCore(MPR_LOC_PASS(ctx, loc), buf, maxSize, fmt, ap);
va_end(ap);
return result;
}
/******************************************************************************/
int mprAllocVsprintf(MPR_LOC_DEC(ctx, loc), char **buf, int maxSize,
const char *fmt, va_list arg)
{
mprAssert(buf);
mprAssert(fmt);
*buf = 0;
return mprSprintfCore(MPR_LOC_PASS(ctx, loc), buf, maxSize, fmt, arg);
}
/******************************************************************************/
static int getState(char c, int state)
{
/*
* Declared here to remove all static / globals
* FUTURE OPT -- need to measure this. Could be slow on BREW.
*/
char stateMap[] = {
/* STATES: Normal Percent Modifier Width Dot Prec Bits Type */
/* CLASS 0 1 2 3 4 5 6 7 */
/* Normal 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* Percent 1 */ 1, 0, 1, 1, 1, 1, 1, 1,
/* Modifier 2 */ 0, 2, 2, 0, 0, 0, 0, 0,
/* Zero 3 */ 0, 2, 2, 3, 0, 5, 0, 0,
/* Star 4 */ 0, 3, 3, 0, 5, 0, 0, 0,
/* Digit 5 */ 0, 3, 3, 3, 5, 5, 0, 0,
/* Dot 6 */ 0, 4, 4, 4, 0, 0, 0, 0,
/* Bits 7 */ 0, 6, 6, 6, 6, 6, 6, 0,
/* Types 8 */ 0, 7, 7, 7, 7, 7, 7, 0,
};
/*
* Format: %[modifier][width][precision][bits][type]
*/
char classMap[] = {
/* 0 ' ' ! " # $ % & ' */
2, 0, 0, 2, 0, 1, 0, 0,
/* 07 ( ) * + , - . / */
0, 0, 4, 2, 2, 2, 6, 0,
/* 10 0 1 2 3 4 5 6 7 */
3, 5, 5, 5, 5, 5, 5, 5,
/* 17 8 9 : ; < = > ? */
5, 5, 0, 0, 0, 0, 0, 0,
/* 20 @ A B C D E F G */
0, 0, 0, 0, 0, 0, 0, 0,
/* 27 H I J K L M N O */
0, 0, 0, 0, 7, 0, 0, 0,
/* 30 P Q R S T U V W */
0, 0, 0, 8, 0, 0, 0, 0,
/* 37 X Y Z [ \ ] ^ _ */
8, 0, 0, 0, 0, 0, 0, 0,
/* 40 ' a b c d e f g */
0, 0, 0, 8, 8, 0, 8, 0,
/* 47 h i j k l m n o */
7, 8, 0, 0, 7, 0, 8, 8,
/* 50 p q r s t u v w */
8, 0, 0, 8, 0, 8, 0, 0,
/* 57 x y z */
8, 0, 0,
};
int chrClass;
if (c < ' ' || c > 'z') {
chrClass = CLASS_NORMAL;
} else {
mprAssert((c - ' ') < (int) sizeof(classMap));
chrClass = classMap[(c - ' ')];
}
mprAssert((chrClass * STATE_COUNT + state) < (int) sizeof(stateMap));
state = stateMap[chrClass * STATE_COUNT + state];
return state;
}
/******************************************************************************/
static int mprSprintfCore(MPR_LOC_DEC(ctx, loc), char **bufPtr,
int maxsize, const char *spec, va_list arg)
{
Format fmt;
char *cp;
char c;
char *sValue;
num iValue;
unum uValue;
int count, i, len, state;
mprAssert(bufPtr);
mprAssert(spec);
if (*bufPtr != 0) {
mprAssert(maxsize > 0);
fmt.buf = (uchar*) *bufPtr;
fmt.endbuf = &fmt.buf[maxsize];
fmt.growBy = 0;
} else {
if (maxsize <= 0) {
maxsize = MAXINT;
}
len = min(MPR_DEFAULT_ALLOC, maxsize);
fmt.buf = (uchar*) mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
fmt.endbuf = &fmt.buf[len];
fmt.growBy = MPR_DEFAULT_ALLOC * 2;
}
fmt.maxsize = maxsize;
fmt.start = fmt.buf;
fmt.end = fmt.buf;
fmt.len = 0;
*fmt.start = '\0';
state = STATE_NORMAL;
while ((c = *spec++) != '\0') {
state = getState(c, state);
switch (state) {
case STATE_NORMAL:
BPUT(ctx, loc, &fmt, c);
break;
case STATE_PERCENT:
fmt.precision = -1;
fmt.width = 0;
fmt.flags = 0;
break;
case STATE_MODIFIER:
switch (c) {
case '+':
fmt.flags |= SPRINTF_SIGN;
break;
case '-':
fmt.flags |= SPRINTF_LEFT;
break;
case '#':
fmt.flags |= SPRINTF_ALTERNATE;
break;
case '0':
fmt.flags |= SPRINTF_LEAD_ZERO;
break;
case ' ':
fmt.flags |= SPRINTF_LEAD_SPACE;
break;
case ',':
fmt.flags |= SPRINTF_COMMA;
break;
}
break;
case STATE_WIDTH:
if (c == '*') {
fmt.width = va_arg(arg, int);
if (fmt.width < 0) {
fmt.width = -fmt.width;
fmt.flags |= SPRINTF_LEFT;
}
} else {
while (isdigit((int)c)) {
fmt.width = fmt.width * 10 + (c - '0');
c = *spec++;
}
spec--;
}
break;
case STATE_DOT:
fmt.precision = 0;
fmt.flags &= ~SPRINTF_LEAD_ZERO;
break;
case STATE_PRECISION:
if (c == '*') {
fmt.precision = va_arg(arg, int);
} else {
while (isdigit((int) c)) {
fmt.precision = fmt.precision * 10 + (c - '0');
c = *spec++;
}
spec--;
}
break;
case STATE_BITS:
switch (c) {
#if BLD_FEATURE_INT64
case 'L':
fmt.flags |= SPRINTF_LONGLONG; /* 64 bit */
break;
#endif
case 'l':
fmt.flags |= SPRINTF_LONG;
break;
case 'h':
fmt.flags |= SPRINTF_SHORT;
break;
}
break;
case STATE_TYPE:
switch (c) {
#if BLD_FEATURE_FLOATING_POINT
case 'e':
case 'g':
case 'f':
fmt.radix = 10;
outFloat(MPR_LOC_PASS(ctx, loc), &fmt, c,
(double) va_arg(arg, double));
break;
#endif
case 'c':
BPUT(ctx, loc, &fmt, (char) va_arg(arg, int));
break;
case 's':
case 'S':
sValue = va_arg(arg, char*);
if (sValue == 0) {
sValue = "null";
len = strlen(sValue);
} else if (fmt.flags & SPRINTF_ALTERNATE) {
sValue++;
len = (int) *sValue;
} else if (fmt.precision >= 0) {
/*
* Can't use strlen(), the string may not have a null
*/
cp = sValue;
for (len = 0; len < fmt.precision; len++) {
if (*cp++ == '\0') {
break;
}
}
} else {
len = strlen(sValue);
}
if (!(fmt.flags & SPRINTF_LEFT)) {
for (i = len; i < fmt.width; i++) {
BPUT(ctx, loc, &fmt, (char) ' ');
}
}
for (i = 0; i < len && *sValue; i++) {
BPUT(ctx, loc, &fmt, *sValue++);
}
if (fmt.flags & SPRINTF_LEFT) {
for (i = len; i < fmt.width; i++) {
BPUT(ctx, loc, &fmt, (char) ' ');
}
}
break;
case 'i':
;
case 'd':
fmt.radix = 10;
if (fmt.flags & SPRINTF_SHORT) {
iValue = (short) va_arg(arg, int);
} else if (fmt.flags & SPRINTF_LONG) {
iValue = va_arg(arg, long);
#if BLD_FEATURE_INT64
} else if (fmt.flags & SPRINTF_LONGLONG) {
iValue = va_arg(arg, num);
#endif
} else {
iValue = va_arg(arg, int);
}
if (iValue >= 0) {
if (fmt.flags & SPRINTF_LEAD_SPACE) {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, " ", iValue);
} else if (fmt.flags & SPRINTF_SIGN) {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, "+", iValue);
} else {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, iValue);
}
} else {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, "-", -iValue);
}
break;
case 'X':
fmt.flags |= SPRINTF_UPPER_CASE;
/* Fall through */
case 'o':
case 'x':
case 'u':
if (fmt.flags & SPRINTF_SHORT) {
uValue = (ushort) va_arg(arg, uint);
} else if (fmt.flags & SPRINTF_LONG) {
uValue = va_arg(arg, ulong);
#if BLD_FEATURE_INT64
} else if (fmt.flags & SPRINTF_LONGLONG) {
uValue = va_arg(arg, unum);
#endif
} else {
uValue = va_arg(arg, uint);
}
if (c == 'u') {
fmt.radix = 10;
outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, uValue);
} else if (c == 'o') {
fmt.radix = 8;
if (fmt.flags & SPRINTF_ALTERNATE && uValue != 0) {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0", uValue);
} else {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, uValue);
}
} else {
fmt.radix = 16;
if (fmt.flags & SPRINTF_ALTERNATE && uValue != 0) {
if (c == 'X') {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0X", uValue);
} else {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0x", uValue);
}
} else {
outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, uValue);
}
}
break;
case 'n': /* Count of chars seen thus far */
if (fmt.flags & SPRINTF_SHORT) {
short *count = va_arg(arg, short*);
*count = fmt.end - fmt.start;
} else if (fmt.flags & SPRINTF_LONG) {
long *count = va_arg(arg, long*);
*count = fmt.end - fmt.start;
} else {
int *count = va_arg(arg, int *);
*count = fmt.end - fmt.start;
}
break;
case 'p': /* Pointer */
#if __WORDSIZE == 64 && BLD_FEATURE_INT64
uValue = (unum) va_arg(arg, void*);
#else
uValue = (uint) (int) va_arg(arg, void*);
#endif
fmt.radix = 16;
outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0x", uValue);
break;
default:
BPUT(ctx, loc, &fmt, c);
}
}
}
BPUTNULL(ctx, loc, &fmt);
count = fmt.end - fmt.start;
if (*bufPtr == 0) {
*bufPtr = (char*) fmt.buf;
}
return count;
}
/******************************************************************************/
/*
* Output a number according to the given format. If BLD_FEATURE_INT64 is
* defined, then uses 64 bits universally. Slower but smaller code.
*/
static void outNum(MPR_LOC_DEC(ctx, loc), Format *fmt, const char *prefix,
unum value)
{
char numBuf[64];
char *cp;
char *endp;
char c;
int letter, len, leadingZeros, i, fill;
endp = &numBuf[sizeof(numBuf) - 1];
*endp = '\0';
cp = endp;
/*
* Convert to ascii
*/
if (fmt->radix == 16) {
do {
letter = (int) (value % fmt->radix);
if (letter > 9) {
if (fmt->flags & SPRINTF_UPPER_CASE) {
letter = 'A' + letter - 10;
} else {
letter = 'a' + letter - 10;
}
} else {
letter += '0';
}
*--cp = letter;
value /= fmt->radix;
} while (value > 0);
} else if (fmt->flags & SPRINTF_COMMA) {
i = 1;
do {
*--cp = '0' + (int) (value % fmt->radix);
value /= fmt->radix;
if ((i++ % 3) == 0 && value > 0) {
*--cp = ',';
}
} while (value > 0);
} else {
do {
*--cp = '0' + (int) (value % fmt->radix);
value /= fmt->radix;
} while (value > 0);
}
len = endp - cp;
fill = fmt->width - len;
if (prefix != 0) {
fill -= strlen(prefix);
}
leadingZeros = (fmt->precision > len) ? fmt->precision - len : 0;
fill -= leadingZeros;
if (!(fmt->flags & SPRINTF_LEFT)) {
c = (fmt->flags & SPRINTF_LEAD_ZERO) ? '0': ' ';
for (i = 0; i < fill; i++) {
BPUT(ctx, loc, fmt, c);
}
}
if (prefix != 0) {
while (*prefix) {
BPUT(ctx, loc, fmt, *prefix++);
}
}
for (i = 0; i < leadingZeros; i++) {
BPUT(ctx, loc, fmt, '0');
}
while (*cp) {
BPUT(ctx, loc, fmt, *cp);
cp++;
}
if (fmt->flags & SPRINTF_LEFT) {
for (i = 0; i < fill; i++) {
BPUT(ctx, loc, fmt, ' ');
}
}
}
/******************************************************************************/
#if BLD_FEATURE_FLOATING_POINT
/*
* Output a floating point number
*/
static void outFloat(MPR_LOC_DEC(ctx, loc), Format *fmt, char specChar,
double value)
{
char *cp;
#if FUTURE
char numBuf[64];
char *endp;
char c;
int letter, len, leadingZeros, i, fill, width, precision;
endp = &numBuf[sizeof(numBuf) - 1];
*endp = '\0';
precision = fmt->precision;
if (precision < 0) {
precision = 6;
} else if (precision > (sizeof(numBuf) - 1)) {
precision = (sizeof(numBuf) - 1);
}
width = min(fmt->width, sizeof(numBuf) - 1);
if (__isnanl(value)) {
"nan"
} else if (__isinfl(value)) {
"infinity"
} else if (value < 0) {
prefix = "-";
} else if (fmt.flags & SPRINTF_LEAD_SPACE) {
prefix = " ";
} else if (fmt.flags & SPRINTF_SIGN) {
prefix = "+";
}
/*
* Do the exponent part
*/
cp = &numBuf[sizeof(numBuf) - precision];
for (i = 0; i < precision; i++) {
*cp++ = '0' + (int) (value % fmt->radix);
value /= fmt->radix;
}
/*
* Do the decimal part
*/
if (fmt->flags & SPRINTF_COMMA) {
i = 1;
do {
*--cp = '0' + (int) (value % fmt->radix);
value /= fmt->radix;
if ((i++ % 3) == 0 && value > 0) {
*--cp = ',';
}
} while (value >= 1.0);
} else {
do {
*--cp = '0' + (int) (value % fmt->radix);
value /= fmt->radix;
} while (value > 1.0);
}
len = endp - cp;
fill = fmt->width - len;
if (prefix != 0) {
fill -= strlen(prefix);
}
leadingZeros = (fmt->precision > len) ? fmt->precision - len : 0;
fill -= leadingZeros;
if (!(fmt->flags & SPRINTF_LEFT)) {
c = (fmt->flags & SPRINTF_LEAD_ZERO) ? '0': ' ';
for (i = 0; i < fill; i++) {
BPUT(ctx, loc, fmt, c);
}
}
if (prefix != 0) {
BPUT(ctx, loc, fmt, prefix);
}
for (i = 0; i < leadingZeros; i++) {
BPUT(ctx, loc, fmt, '0');
}
BPUT(ctx, loc, fmt, cp);
if (fmt->flags & SPRINTF_LEFT) {
for (i = 0; i < fill; i++) {
BPUT(ctx, loc, fmt, ' ');
}
}
#else
char numBuf[64];
if (specChar == 'f') {
sprintf(numBuf, "%*.*f", fmt->width, fmt->precision, value);
} else if (specChar == 'g') {
sprintf(numBuf, "%*.*g", fmt->width, fmt->precision, value);
} else if (specChar == 'e') {
sprintf(numBuf, "%*.*e", fmt->width, fmt->precision, value);
}
for (cp = numBuf; *cp; cp++) {
BPUT(ctx, loc, fmt, *cp);
}
#endif
}
#endif /* BLD_FEATURE_FLOATING_POINT */
/******************************************************************************/
/*
* Grow the buffer to fit new data. Return 1 if the buffer can grow.
* Grow using the growBy size specified when creating the buffer.
*/
static int growBuf(MPR_LOC_DEC(ctx, loc), Format *fmt)
{
uchar *newbuf;
int buflen;
buflen = fmt->endbuf - fmt->buf;
if (fmt->maxsize >= 0 && buflen >= fmt->maxsize) {
return 0;
}
if (fmt->growBy < 0) {
/*
* User supplied buffer
*/
return 0;
}
newbuf = (uchar*) mprAlloc(ctx, buflen + fmt->growBy);
if (fmt->buf) {
memcpy(newbuf, fmt->buf, buflen);
mprFree(fmt->buf);
}
buflen += fmt->growBy;
fmt->end = newbuf + (fmt->end - fmt->buf);
fmt->start = newbuf + (fmt->start - fmt->buf);
fmt->buf = newbuf;
fmt->endbuf = &fmt->buf[buflen];
/*
* Increase growBy to reduce overhead
*/
if ((buflen + (fmt->growBy * 2)) < fmt->maxsize) {
fmt->growBy *= 2;
}
return 1;
}
/******************************************************************************/
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim:tw=78
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/