📄 mprprintf.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 __cplusplusextern "C" {#endifstatic 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_POINTstatic 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -