summaryrefslogtreecommitdiff
path: root/source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c')
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c924
1 files changed, 924 insertions, 0 deletions
diff --git a/source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c b/source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c
new file mode 100644
index 0000000000..2d0951acfa
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c
@@ -0,0 +1,924 @@
+/**
+ * @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
+ */