You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1721 lines
62 KiB
1721 lines
62 KiB
/*
|
|
* Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
|
|
* Licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
* Description: Used by secureprintoutput_a.c and secureprintoutput_w.c to include.
|
|
* This file provides a template function for ANSI and UNICODE compiling
|
|
* by different type definition. The functions of SecOutputS or
|
|
* SecOutputSW provides internal implementation for printf family API, such as sprintf, swprintf_s.
|
|
* Create: 2014-02-25
|
|
* Notes: see www.cplusplus.com/reference/cstdio/printf/
|
|
*/
|
|
/*
|
|
* [Standardize-exceptions] Use unsafe function: Portability
|
|
* [reason] Use unsafe function to implement security function to maintain platform compatibility.
|
|
* And sufficient input validation is performed before calling
|
|
*/
|
|
#ifndef OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
|
|
#define OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
|
|
|
|
#ifndef SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
|
|
/* Some compilers do not support long double */
|
|
#define SECUREC_ENABLE_SPRINTF_LONG_DOUBLE 1
|
|
#endif
|
|
|
|
#define SECUREC_NULL_STRING_SIZE 8
|
|
#define SECUREC_STATE_TABLE_SIZE 337
|
|
|
|
#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)
|
|
#define SECUREC_DIV_QUOTIENT_OCTAL(val64) ((val64) >> 3ULL)
|
|
#define SECUREC_DIV_RESIDUE_OCTAL(val64) ((val64) & 7ULL)
|
|
|
|
#define SECUREC_DIV_QUOTIENT_HEX(val64) ((val64) >> 4ULL)
|
|
#define SECUREC_DIV_RESIDUE_HEX(val64) ((val64) & 0xfULL)
|
|
#endif
|
|
|
|
#define SECUREC_RADIX_OCTAL 8U
|
|
#define SECUREC_RADIX_DECIMAL 10U
|
|
#define SECUREC_RADIX_HEX 16U
|
|
#define SECUREC_PREFIX_LEN 2
|
|
/* Size include '+' and '\0' */
|
|
#define SECUREC_FLOAT_BUF_EXT 2
|
|
|
|
/* Sign extend or Zero-extend */
|
|
#define SECUREC_GET_LONG_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
|
|
(SecInt64)(long)va_arg(argList, long) : \
|
|
(SecInt64)(unsigned long)va_arg(argList, long))
|
|
|
|
/* Sign extend or Zero-extend */
|
|
#define SECUREC_GET_CHAR_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
|
|
SecUpdateNegativeChar(&(attr), ((char)va_arg(argList, int))) : \
|
|
(SecInt64)(unsigned char)va_arg(argList, int))
|
|
|
|
/* Sign extend or Zero-extend */
|
|
#define SECUREC_GET_SHORT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
|
|
(SecInt64)(short)va_arg(argList, int) : \
|
|
(SecInt64)(unsigned short)va_arg(argList, int))
|
|
|
|
/* Sign extend or Zero-extend */
|
|
#define SECUREC_GET_INT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
|
|
(SecInt64)(int)va_arg(argList, int) : \
|
|
(SecInt64)(unsigned int)va_arg(argList, int))
|
|
|
|
#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
|
|
/* Sign extend or Zero-extend. No suitable macros were found to handle the branch */
|
|
#define SECUREC_GET_SIZE_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
|
|
((SecIsSameSize(sizeof(size_t), sizeof(long)) != 0) ? (SecInt64)(long)va_arg(argList, long) : \
|
|
((SecIsSameSize(sizeof(size_t), sizeof(long long)) != 0) ? (SecInt64)(long long)va_arg(argList, long long) : \
|
|
(SecInt64)(int)va_arg(argList, int))) : \
|
|
(SecInt64)(size_t)va_arg(argList, size_t))
|
|
#endif
|
|
|
|
/* Format output buffer pointer and available size */
|
|
typedef struct {
|
|
int count;
|
|
SecChar *cur;
|
|
} SecPrintfStream;
|
|
|
|
typedef union {
|
|
/* Integer formatting refers to the end of the buffer, plus 1 to prevent tool alarms */
|
|
char str[SECUREC_BUFFER_SIZE + 1];
|
|
#if SECUREC_HAVE_WCHART
|
|
wchar_t wStr[SECUREC_WCHAR_BUFFER_SIZE]; /* Just for %lc */
|
|
#endif
|
|
} SecBuffer;
|
|
|
|
typedef union {
|
|
char *str; /* Not a null terminated string */
|
|
#if SECUREC_HAVE_WCHART
|
|
wchar_t *wStr;
|
|
#endif
|
|
} SecFormatBuf;
|
|
|
|
typedef struct {
|
|
const char *digits; /* Point to the hexadecimal subset */
|
|
SecFormatBuf text; /* Point to formatted string */
|
|
int textLen; /* Length of the text */
|
|
int textIsWide; /* Flag for text is wide chars ; 0 is not wide char */
|
|
unsigned int radix; /* Use for output number , default set to 10 */
|
|
unsigned int flags;
|
|
int fldWidth;
|
|
int precision;
|
|
int dynWidth; /* %* 1 width from variable parameter ;0 not */
|
|
int dynPrecision; /* %.* 1 precision from variable parameter ;0 not */
|
|
int padding; /* Padding len */
|
|
int prefixLen; /* Length of prefix, 0 or 1 or 2 */
|
|
SecChar prefix[SECUREC_PREFIX_LEN]; /* Prefix is 0 or 0x */
|
|
SecBuffer buffer;
|
|
} SecFormatAttr;
|
|
|
|
#if SECUREC_ENABLE_SPRINTF_FLOAT
|
|
#ifdef SECUREC_STACK_SIZE_LESS_THAN_1K
|
|
#define SECUREC_FMT_STR_LEN 8
|
|
#else
|
|
#define SECUREC_FMT_STR_LEN 16
|
|
#endif
|
|
typedef struct {
|
|
char buffer[SECUREC_FMT_STR_LEN];
|
|
char *fmtStr; /* Initialization must point to buffer */
|
|
char *allocatedFmtStr; /* Initialization must be NULL to store allocated point */
|
|
char *floatBuffer; /* Use heap memory if the SecFormatAttr.buffer is not enough */
|
|
int bufferSize; /* The size of floatBuffer */
|
|
} SecFloatAdapt;
|
|
#endif
|
|
|
|
/* Use 20 to Align the data */
|
|
#define SECUREC_DIGITS_BUF_SIZE 20
|
|
/* The serial number of 'x' or 'X' is 16 */
|
|
#define SECUREC_NUMBER_OF_X 16
|
|
/* Some systems can not use pointers to point to string literals, but can use string arrays. */
|
|
/* For example, when handling code under uboot, there is a problem with the pointer */
|
|
static const char g_itoaUpperDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789ABCDEFX";
|
|
static const char g_itoaLowerDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789abcdefx";
|
|
|
|
#if SECUREC_ENABLE_SPRINTF_FLOAT
|
|
/* Call system sprintf to format float value */
|
|
SECUREC_INLINE int SecFormatFloat(char *strDest, const char *format, ...)
|
|
{
|
|
int ret; /* If initialization causes e838 */
|
|
va_list argList;
|
|
|
|
va_start(argList, format);
|
|
SECUREC_MASK_VSPRINTF_WARNING
|
|
ret = vsprintf(strDest, format, argList);
|
|
SECUREC_END_MASK_VSPRINTF_WARNING
|
|
va_end(argList);
|
|
(void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
|
|
/* Out put long double value to dest */
|
|
SECUREC_INLINE void SecFormatLongDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, long double ldValue)
|
|
{
|
|
int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth);
|
|
if (attr->dynWidth != 0 && attr->dynPrecision != 0) {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, ldValue);
|
|
} else if (attr->dynWidth != 0) {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, ldValue);
|
|
} else if (attr->dynPrecision != 0) {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, ldValue);
|
|
} else {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, ldValue);
|
|
}
|
|
if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) {
|
|
attr->textLen = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Out put double value to dest */
|
|
SECUREC_INLINE void SecFormatDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, double dValue)
|
|
{
|
|
int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth);
|
|
if (attr->dynWidth != 0 && attr->dynPrecision != 0) {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, dValue);
|
|
} else if (attr->dynWidth != 0) {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, dValue);
|
|
} else if (attr->dynPrecision != 0) {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, dValue);
|
|
} else {
|
|
attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, dValue);
|
|
}
|
|
if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) {
|
|
attr->textLen = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
|
|
/* To clear e506 warning */
|
|
SECUREC_INLINE int SecIsSameSize(size_t sizeA, size_t sizeB)
|
|
{
|
|
return (int)(sizeA == sizeB);
|
|
}
|
|
#endif
|
|
|
|
#ifndef SECUREC_ON_64BITS
|
|
/*
|
|
* Compiler Optimized Division 8.
|
|
* The text.str point to buffer end, must be Large enough
|
|
*/
|
|
SECUREC_INLINE void SecNumber32ToOctalString(SecUnsignedInt32 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt32 val32 = number;
|
|
do {
|
|
--attr->text.str;
|
|
/* Just use lowerDigits for 0 - 9 */
|
|
*(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_OCTAL];
|
|
val32 /= SECUREC_RADIX_OCTAL;
|
|
} while (val32 != 0);
|
|
}
|
|
|
|
#ifdef _AIX
|
|
/*
|
|
* Compiler Optimized Division 10.
|
|
* The text.str point to buffer end, must be Large enough
|
|
*/
|
|
SECUREC_INLINE void SecNumber32ToDecString(SecUnsignedInt32 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt32 val32 = number;
|
|
do {
|
|
--attr->text.str;
|
|
/* Just use lowerDigits for 0 - 9 */
|
|
*(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL];
|
|
val32 /= SECUREC_RADIX_DECIMAL;
|
|
} while (val32 != 0);
|
|
}
|
|
#endif
|
|
/*
|
|
* Compiler Optimized Division 16.
|
|
* The text.str point to buffer end, must be Large enough
|
|
*/
|
|
SECUREC_INLINE void SecNumber32ToHexString(SecUnsignedInt32 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt32 val32 = number;
|
|
do {
|
|
--attr->text.str;
|
|
*(attr->text.str) = attr->digits[val32 % SECUREC_RADIX_HEX];
|
|
val32 /= SECUREC_RADIX_HEX;
|
|
} while (val32 != 0);
|
|
}
|
|
|
|
#ifndef _AIX
|
|
/* Use fast div 10 */
|
|
SECUREC_INLINE void SecNumber32ToDecStringFast(SecUnsignedInt32 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt32 val32 = number;
|
|
do {
|
|
SecUnsignedInt32 quotient;
|
|
SecUnsignedInt32 remain;
|
|
--attr->text.str;
|
|
*(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL];
|
|
quotient = (val32 >> 1U) + (val32 >> 2U); /* Fast div magic 2 */
|
|
quotient = quotient + (quotient >> 4U); /* Fast div magic 4 */
|
|
quotient = quotient + (quotient >> 8U); /* Fast div magic 8 */
|
|
quotient = quotient + (quotient >> 16U); /* Fast div magic 16 */
|
|
quotient = quotient >> 3U; /* Fast div magic 3 */
|
|
remain = val32 - SECUREC_MUL_TEN(quotient);
|
|
val32 = (remain > 9U) ? (quotient + 1U) : quotient; /* Fast div magic 9 */
|
|
} while (val32 != 0);
|
|
}
|
|
#endif
|
|
|
|
SECUREC_INLINE void SecNumber32ToString(SecUnsignedInt32 number, SecFormatAttr *attr)
|
|
{
|
|
switch (attr->radix) {
|
|
case SECUREC_RADIX_HEX:
|
|
SecNumber32ToHexString(number, attr);
|
|
break;
|
|
case SECUREC_RADIX_OCTAL:
|
|
SecNumber32ToOctalString(number, attr);
|
|
break;
|
|
case SECUREC_RADIX_DECIMAL:
|
|
#ifdef _AIX
|
|
/* The compiler will optimize div 10 */
|
|
SecNumber32ToDecString(number, attr);
|
|
#else
|
|
SecNumber32ToDecStringFast(number, attr);
|
|
#endif
|
|
break;
|
|
default:
|
|
/* Do nothing */
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(SECUREC_USE_SPECIAL_DIV64) || (defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS))
|
|
/*
|
|
* This function just to clear warning, on sume vxworks compiler shift 32 bit make warnings
|
|
*/
|
|
SECUREC_INLINE SecUnsignedInt64 SecU64Shr32(SecUnsignedInt64 number)
|
|
{
|
|
return (((number) >> 16U) >> 16U); /* Two shifts of 16 bits to realize shifts of 32 bits */
|
|
}
|
|
/*
|
|
* Fast divide by 10 algorithm.
|
|
* Calculation divisor multiply 0xcccccccccccccccdULL, resultHi64 >> 3 as quotient
|
|
*/
|
|
SECUREC_INLINE void SecU64Div10(SecUnsignedInt64 divisor, SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue)
|
|
{
|
|
SecUnsignedInt64 mask = 0xffffffffULL; /* Use 0xffffffffULL as 32 bit mask */
|
|
SecUnsignedInt64 magicHi = 0xccccccccULL; /* Fast divide 10 magic numbers high 32bit 0xccccccccULL */
|
|
SecUnsignedInt64 magicLow = 0xcccccccdULL; /* Fast divide 10 magic numbers low 32bit 0xcccccccdULL */
|
|
SecUnsignedInt64 divisorHi = (SecUnsignedInt64)(SecU64Shr32(divisor)); /* High 32 bit use */
|
|
SecUnsignedInt64 divisorLow = (SecUnsignedInt64)(divisor & mask); /* Low 32 bit mask */
|
|
SecUnsignedInt64 factorHi = divisorHi * magicHi;
|
|
SecUnsignedInt64 factorLow1 = divisorHi * magicLow;
|
|
SecUnsignedInt64 factorLow2 = divisorLow * magicHi;
|
|
SecUnsignedInt64 factorLow3 = divisorLow * magicLow;
|
|
SecUnsignedInt64 carry = (factorLow1 & mask) + (factorLow2 & mask) + SecU64Shr32(factorLow3);
|
|
SecUnsignedInt64 resultHi64 = factorHi + SecU64Shr32(factorLow1) + SecU64Shr32(factorLow2) + SecU64Shr32(carry);
|
|
|
|
*quotient = resultHi64 >> 3U; /* Fast divide 10 magic numbers 3 */
|
|
*residue = (SecUnsignedInt32)(divisor - ((*quotient) * 10)); /* Quotient mul 10 */
|
|
return;
|
|
}
|
|
#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)
|
|
/*
|
|
* Divide function for VXWORKS
|
|
*/
|
|
SECUREC_INLINE int SecU64Div32(SecUnsignedInt64 divisor, SecUnsignedInt32 radix,
|
|
SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue)
|
|
{
|
|
switch (radix) {
|
|
case SECUREC_RADIX_DECIMAL:
|
|
SecU64Div10(divisor, quotient, residue);
|
|
break;
|
|
case SECUREC_RADIX_HEX:
|
|
*quotient = SECUREC_DIV_QUOTIENT_HEX(divisor);
|
|
*residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_HEX(divisor);
|
|
break;
|
|
case SECUREC_RADIX_OCTAL:
|
|
*quotient = SECUREC_DIV_QUOTIENT_OCTAL(divisor);
|
|
*residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_OCTAL(divisor);
|
|
break;
|
|
default:
|
|
return -1; /* This does not happen in the current file */
|
|
}
|
|
return 0;
|
|
}
|
|
SECUREC_INLINE void SecNumber64ToStringSpecial(SecUnsignedInt64 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt64 val64 = number;
|
|
do {
|
|
SecUnsignedInt32 digit = 0; /* Ascii value of digit */
|
|
SecUnsignedInt64 quotient = 0;
|
|
if (SecU64Div32(val64, (SecUnsignedInt32)attr->radix, "ient, &digit) != 0) {
|
|
/* Just break, when enter this function, no error is returned */
|
|
break;
|
|
}
|
|
--attr->text.str;
|
|
*(attr->text.str) = attr->digits[digit];
|
|
val64 = quotient;
|
|
} while (val64 != 0);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(SECUREC_ON_64BITS) || !defined(SECUREC_VXWORKS_VERSION_5_4)
|
|
#if defined(SECUREC_USE_SPECIAL_DIV64)
|
|
/* The compiler does not provide 64 bit division problems */
|
|
SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt64 val64 = number;
|
|
do {
|
|
SecUnsignedInt64 quotient = 0;
|
|
SecUnsignedInt32 digit = 0;
|
|
SecU64Div10(val64, "ient, &digit);
|
|
--attr->text.str;
|
|
/* Just use lowerDigits for 0 - 9 */
|
|
*(attr->text.str) = g_itoaLowerDigits[digit];
|
|
val64 = quotient;
|
|
} while (val64 != 0);
|
|
}
|
|
#else
|
|
/*
|
|
* Compiler Optimized Division 10.
|
|
* The text.str point to buffer end, must be Large enough
|
|
*/
|
|
SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt64 val64 = number;
|
|
do {
|
|
--attr->text.str;
|
|
/* Just use lowerDigits for 0 - 9 */
|
|
*(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_DECIMAL];
|
|
val64 /= SECUREC_RADIX_DECIMAL;
|
|
} while (val64 != 0);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Compiler Optimized Division 8.
|
|
* The text.str point to buffer end, must be Large enough
|
|
*/
|
|
SECUREC_INLINE void SecNumber64ToOctalString(SecUnsignedInt64 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt64 val64 = number;
|
|
do {
|
|
--attr->text.str;
|
|
/* Just use lowerDigits for 0 - 9 */
|
|
*(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_OCTAL];
|
|
val64 /= SECUREC_RADIX_OCTAL;
|
|
} while (val64 != 0);
|
|
}
|
|
/*
|
|
* Compiler Optimized Division 16.
|
|
* The text.str point to buffer end, must be Large enough
|
|
*/
|
|
SECUREC_INLINE void SecNumber64ToHexString(SecUnsignedInt64 number, SecFormatAttr *attr)
|
|
{
|
|
SecUnsignedInt64 val64 = number;
|
|
do {
|
|
--attr->text.str;
|
|
*(attr->text.str) = attr->digits[val64 % SECUREC_RADIX_HEX];
|
|
val64 /= SECUREC_RADIX_HEX;
|
|
} while (val64 != 0);
|
|
}
|
|
|
|
SECUREC_INLINE void SecNumber64ToString(SecUnsignedInt64 number, SecFormatAttr *attr)
|
|
{
|
|
switch (attr->radix) {
|
|
/* The compiler will optimize div 10 */
|
|
case SECUREC_RADIX_DECIMAL:
|
|
SecNumber64ToDecString(number, attr);
|
|
break;
|
|
case SECUREC_RADIX_OCTAL:
|
|
SecNumber64ToOctalString(number, attr);
|
|
break;
|
|
case SECUREC_RADIX_HEX:
|
|
SecNumber64ToHexString(number, attr);
|
|
break;
|
|
default:
|
|
/* Do nothing */
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Converting integers to string
|
|
*/
|
|
SECUREC_INLINE void SecNumberToString(SecUnsignedInt64 number, SecFormatAttr *attr)
|
|
{
|
|
#ifdef SECUREC_ON_64BITS
|
|
SecNumber64ToString(number, attr);
|
|
#else /* For 32 bits system */
|
|
if (number <= 0xffffffffUL) { /* Use 0xffffffffUL to check if the value is in the 32-bit range */
|
|
/* In most case, the value to be converted is small value */
|
|
SecUnsignedInt32 n32Tmp = (SecUnsignedInt32)number;
|
|
SecNumber32ToString(n32Tmp, attr);
|
|
} else {
|
|
/* The value to be converted is greater than 4G */
|
|
#if defined(SECUREC_VXWORKS_VERSION_5_4)
|
|
SecNumber64ToStringSpecial(number, attr);
|
|
#else
|
|
SecNumber64ToString(number, attr);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
SECUREC_INLINE int SecIsNumberNeedTo32Bit(const SecFormatAttr *attr)
|
|
{
|
|
return (int)(((attr->flags & SECUREC_FLAG_I64) == 0) &&
|
|
#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
|
|
((attr->flags & SECUREC_FLAG_INTMAX) == 0) &&
|
|
#endif
|
|
#ifdef SECUREC_ON_64BITS
|
|
((attr->flags & SECUREC_FLAG_PTRDIFF) == 0) &&
|
|
((attr->flags & SECUREC_FLAG_SIZE) == 0) &&
|
|
#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT) /* on window 64 system sizeof long is 32bit */
|
|
((attr->flags & SECUREC_FLAG_LONG) == 0) &&
|
|
#endif
|
|
#endif
|
|
((attr->flags & SECUREC_FLAG_LONGLONG) == 0));
|
|
}
|
|
|
|
SECUREC_INLINE void SecNumberToBuffer(SecFormatAttr *attr, SecInt64 num64)
|
|
{
|
|
SecUnsignedInt64 number;
|
|
/* Check for negative; copy into number */
|
|
if ((attr->flags & SECUREC_FLAG_SIGNED) != 0 && num64 < 0) {
|
|
number = (SecUnsignedInt64)(0 - (SecUnsignedInt64)num64); /* Wrap with unsigned int64 numbers */
|
|
attr->flags |= SECUREC_FLAG_NEGATIVE;
|
|
} else {
|
|
number = (SecUnsignedInt64)num64;
|
|
}
|
|
if (SecIsNumberNeedTo32Bit(attr) != 0) {
|
|
number = (number & (SecUnsignedInt64)0xffffffffUL); /* Use 0xffffffff as 32 bit mask */
|
|
}
|
|
|
|
/* The text.str must be point to buffer.str, this pointer is used outside the function */
|
|
attr->text.str = &attr->buffer.str[SECUREC_BUFFER_SIZE];
|
|
|
|
if (number == 0) {
|
|
/* Turn off hex prefix default, and textLen is zero */
|
|
attr->prefixLen = 0;
|
|
attr->textLen = 0;
|
|
return;
|
|
}
|
|
|
|
/* Convert integer to string. It must be invoked when number > 0, otherwise the following logic is incorrect */
|
|
SecNumberToString(number, attr);
|
|
/* Compute length of number, text.str must be in buffer.str */
|
|
attr->textLen = (int)(size_t)((char *)&attr->buffer.str[SECUREC_BUFFER_SIZE] - attr->text.str);
|
|
}
|
|
|
|
/*
|
|
* Write one character to dest buffer
|
|
*/
|
|
SECUREC_INLINE void SecWriteChar(SecPrintfStream *stream, SecChar ch, int *charsOut)
|
|
{
|
|
/* Count must be reduced first, In order to identify insufficient length */
|
|
--stream->count;
|
|
if (stream->count >= 0) {
|
|
*(stream->cur) = ch;
|
|
++stream->cur;
|
|
*charsOut = *charsOut + 1;
|
|
return;
|
|
}
|
|
/* No enough length */
|
|
*charsOut = -1;
|
|
}
|
|
|
|
/*
|
|
* Write multiple identical characters.
|
|
*/
|
|
SECUREC_INLINE void SecWriteMultiChar(SecPrintfStream *stream, SecChar ch, int num, int *charsOut)
|
|
{
|
|
int count;
|
|
for (count = num; count > 0; --count) {
|
|
--stream->count; /* count may be negative,indicating insufficient space */
|
|
if (stream->count < 0) {
|
|
*charsOut = -1;
|
|
return;
|
|
}
|
|
*(stream->cur) = ch;
|
|
++stream->cur;
|
|
}
|
|
*charsOut = *charsOut + num;
|
|
}
|
|
|
|
/*
|
|
* Write string function, where this function is called, make sure that len is greater than 0
|
|
*/
|
|
SECUREC_INLINE void SecWriteString(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut)
|
|
{
|
|
const SecChar *tmp = str;
|
|
int count;
|
|
for (count = len; count > 0; --count) {
|
|
--stream->count; /* count may be negative,indicating insufficient space */
|
|
if (stream->count < 0) {
|
|
*charsOut = -1;
|
|
return;
|
|
}
|
|
*(stream->cur) = *tmp;
|
|
++stream->cur;
|
|
++tmp;
|
|
}
|
|
*charsOut = *charsOut + len;
|
|
}
|
|
|
|
/* Use loop copy char or wchar_t string */
|
|
SECUREC_INLINE void SecWriteStringByLoop(SecPrintfStream *stream, const SecChar *str, int len)
|
|
{
|
|
int i;
|
|
const SecChar *tmp = str;
|
|
for (i = 0; i < len; ++i) {
|
|
*stream->cur = *tmp;
|
|
++stream->cur;
|
|
++tmp;
|
|
}
|
|
stream->count -= len;
|
|
}
|
|
|
|
SECUREC_INLINE void SecWriteStringOpt(SecPrintfStream *stream, const SecChar *str, int len)
|
|
{
|
|
if (len < 12) { /* Performance optimization for mobile number length 12 */
|
|
SecWriteStringByLoop(stream, str, len);
|
|
} else {
|
|
size_t count = (size_t)(unsigned int)len * sizeof(SecChar);
|
|
SECUREC_MEMCPY_WARP_OPT(stream->cur, str, count);
|
|
stream->cur += len;
|
|
stream->count -= len;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Return if buffer length is enough
|
|
* The count variable can be reduced to 0, and the external function complements the \0 terminator.
|
|
*/
|
|
SECUREC_INLINE int SecIsStreamBufEnough(const SecPrintfStream *stream, int needLen)
|
|
{
|
|
return (int)(stream->count >= needLen);
|
|
}
|
|
|
|
/* Write text string */
|
|
SECUREC_INLINE void SecWriteTextOpt(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut)
|
|
{
|
|
if (SecIsStreamBufEnough(stream, len) != 0) {
|
|
SecWriteStringOpt(stream, str, len);
|
|
*charsOut += len;
|
|
} else {
|
|
SecWriteString(stream, str, len, charsOut);
|
|
}
|
|
}
|
|
|
|
/* Write left padding */
|
|
SECUREC_INLINE void SecWriteLeftPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
if ((attr->flags & (SECUREC_FLAG_LEFT | SECUREC_FLAG_LEADZERO)) == 0 && attr->padding > 0) {
|
|
/* Pad on left with blanks */
|
|
SecWriteMultiChar(stream, SECUREC_CHAR(' '), attr->padding, charsOut);
|
|
}
|
|
}
|
|
|
|
/* Write prefix */
|
|
SECUREC_INLINE void SecWritePrefix(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
if (attr->prefixLen > 0) {
|
|
SecWriteString(stream, attr->prefix, attr->prefixLen, charsOut);
|
|
}
|
|
}
|
|
|
|
/* Write leading zeros */
|
|
SECUREC_INLINE void SecWriteLeadingZero(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
if ((attr->flags & SECUREC_FLAG_LEADZERO) != 0 && (attr->flags & SECUREC_FLAG_LEFT) == 0 &&
|
|
attr->padding > 0) {
|
|
SecWriteMultiChar(stream, SECUREC_CHAR('0'), attr->padding, charsOut);
|
|
}
|
|
}
|
|
|
|
/* Write right padding */
|
|
SECUREC_INLINE void SecWriteRightPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
if (*charsOut >= 0 && (attr->flags & SECUREC_FLAG_LEFT) != 0 && attr->padding > 0) {
|
|
/* Pad on right with blanks */
|
|
SecWriteMultiChar(stream, SECUREC_CHAR(' '), attr->padding, charsOut);
|
|
}
|
|
}
|
|
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
#define SECUREC_TEXT_CHAR_PTR(text) ((text).wStr)
|
|
#define SECUREC_NEED_CONVERT_TEXT(attr) ((attr)->textIsWide == 0)
|
|
#if SECUREC_HAVE_MBTOWC
|
|
#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) SecWriteTextAfterMbtowc((stream), (attr), (charsOut))
|
|
#else
|
|
#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) (*(charsOut) = -1)
|
|
#endif
|
|
#else
|
|
#define SECUREC_TEXT_CHAR_PTR(text) ((text).str)
|
|
#define SECUREC_NEED_CONVERT_TEXT(attr) ((attr)->textIsWide != 0)
|
|
#if SECUREC_HAVE_WCTOMB
|
|
#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) SecWriteTextAfterWctomb((stream), (attr), (charsOut))
|
|
#else
|
|
#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) (*(charsOut) = -1)
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
#if SECUREC_HAVE_MBTOWC
|
|
SECUREC_INLINE void SecWriteTextAfterMbtowc(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
const char *p = attr->text.str;
|
|
int count = attr->textLen;
|
|
while (count > 0) {
|
|
wchar_t wChar = L'\0';
|
|
int retVal = mbtowc(&wChar, p, (size_t)MB_CUR_MAX);
|
|
if (retVal <= 0) {
|
|
*charsOut = -1;
|
|
break;
|
|
}
|
|
SecWriteChar(stream, wChar, charsOut);
|
|
if (*charsOut == -1) {
|
|
break;
|
|
}
|
|
p += retVal;
|
|
count -= retVal;
|
|
}
|
|
}
|
|
#endif
|
|
#else /* Not SECUREC_FOR_WCHAR */
|
|
#if SECUREC_HAVE_WCTOMB
|
|
SECUREC_INLINE void SecWriteTextAfterWctomb(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
const wchar_t *p = attr->text.wStr;
|
|
int count = attr->textLen;
|
|
while (count > 0) {
|
|
char tmpBuf[SECUREC_MB_LEN + 1];
|
|
SECUREC_MASK_MSVC_CRT_WARNING
|
|
int retVal = wctomb(tmpBuf, *p);
|
|
SECUREC_END_MASK_MSVC_CRT_WARNING
|
|
if (retVal <= 0) {
|
|
*charsOut = -1;
|
|
break;
|
|
}
|
|
SecWriteString(stream, tmpBuf, retVal, charsOut);
|
|
if (*charsOut == -1) {
|
|
break;
|
|
}
|
|
--count;
|
|
++p;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if SECUREC_ENABLE_SPRINTF_FLOAT
|
|
/*
|
|
* Write text of float
|
|
* Using independent functions to optimize the expansion of inline functions by the compiler
|
|
*/
|
|
SECUREC_INLINE void SecWriteFloatText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
#if SECUREC_HAVE_MBTOWC
|
|
SecWriteTextAfterMbtowc(stream, attr, charsOut);
|
|
#else
|
|
*charsOut = -1;
|
|
(void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */
|
|
(void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */
|
|
#endif
|
|
#else /* Not SECUREC_FOR_WCHAR */
|
|
SecWriteString(stream, attr->text.str, attr->textLen, charsOut);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/* Write text of integer or string ... */
|
|
SECUREC_INLINE void SecWriteText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
|
|
{
|
|
if (SECUREC_NEED_CONVERT_TEXT(attr)) {
|
|
SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut);
|
|
} else {
|
|
SecWriteTextOpt(stream, SECUREC_TEXT_CHAR_PTR(attr->text), attr->textLen, charsOut);
|
|
}
|
|
}
|
|
|
|
#define SECUREC_FMT_STATE_OFFSET 256
|
|
|
|
SECUREC_INLINE SecFmtState SecDecodeState(SecChar ch, SecFmtState lastState)
|
|
{
|
|
static const unsigned char stateTable[SECUREC_STATE_TABLE_SIZE] = {
|
|
/*
|
|
* Type
|
|
* 0: nospecial meaning;
|
|
* 1: '%'
|
|
* 2: '.'
|
|
* 3: '*'
|
|
* 4: '0'
|
|
* 5: '1' ... '9'
|
|
* 6: ' ', '+', '-', '#'
|
|
* 7: 'h', 'l', 'L', 'w' , 'N', 'z', 'q', 't', 'j'
|
|
* 8: 'd', 'o', 'u', 'i', 'x', 'X', 'e', 'f', 'g', 'E', 'F', 'G', 's', 'c', '[', 'p'
|
|
*/
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x00,
|
|
0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00,
|
|
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x07, 0x00, 0x07, 0x00, 0x00, 0x08,
|
|
0x08, 0x07, 0x00, 0x08, 0x07, 0x08, 0x00, 0x07, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
/* Fill zero for normal char 128 byte for 0x80 - 0xff */
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
/*
|
|
* State
|
|
* 0: normal
|
|
* 1: percent
|
|
* 2: flag
|
|
* 3: width
|
|
* 4: dot
|
|
* 5: precis
|
|
* 6: size
|
|
* 7: type
|
|
* 8: invalid
|
|
*/
|
|
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
|
|
0x01, 0x00, 0x00, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, 0x08, 0x05,
|
|
0x08, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03,
|
|
0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
|
|
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00,
|
|
0x00
|
|
};
|
|
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
/* Convert to unsigned char to clear gcc 4.3.4 warning */
|
|
unsigned char fmtType = (unsigned char)((((unsigned int)(int)(ch)) <= (unsigned int)(int)(L'~')) ? \
|
|
(stateTable[(unsigned char)(ch)]) : 0);
|
|
return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) +
|
|
(unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]);
|
|
#else
|
|
unsigned char fmtType = stateTable[(unsigned char)(ch)];
|
|
return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) +
|
|
(unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]);
|
|
#endif
|
|
}
|
|
|
|
SECUREC_INLINE void SecDecodeFlags(SecChar ch, SecFormatAttr *attr)
|
|
{
|
|
switch (ch) {
|
|
case SECUREC_CHAR(' '):
|
|
attr->flags |= SECUREC_FLAG_SIGN_SPACE;
|
|
break;
|
|
case SECUREC_CHAR('+'):
|
|
attr->flags |= SECUREC_FLAG_SIGN;
|
|
break;
|
|
case SECUREC_CHAR('-'):
|
|
attr->flags |= SECUREC_FLAG_LEFT;
|
|
break;
|
|
case SECUREC_CHAR('0'):
|
|
attr->flags |= SECUREC_FLAG_LEADZERO; /* Add zero th the front */
|
|
break;
|
|
case SECUREC_CHAR('#'):
|
|
attr->flags |= SECUREC_FLAG_ALTERNATE; /* Output %x with 0x */
|
|
break;
|
|
default:
|
|
/* Do nothing */
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Decoded size identifier in format string to Reduce the number of lines of function code
|
|
*/
|
|
SECUREC_INLINE int SecDecodeSizeI(SecFormatAttr *attr, const SecChar **format)
|
|
{
|
|
#ifdef SECUREC_ON_64BITS
|
|
attr->flags |= SECUREC_FLAG_I64; /* %I to INT64 */
|
|
#endif
|
|
if ((**format == SECUREC_CHAR('6')) && (*((*format) + 1) == SECUREC_CHAR('4'))) {
|
|
(*format) += 2; /* Add 2 to skip I64 */
|
|
attr->flags |= SECUREC_FLAG_I64; /* %I64 to INT64 */
|
|
} else if ((**format == SECUREC_CHAR('3')) && (*((*format) + 1) == SECUREC_CHAR('2'))) {
|
|
(*format) += 2; /* Add 2 to skip I32 */
|
|
attr->flags &= ~SECUREC_FLAG_I64; /* %I64 to INT32 */
|
|
} else if ((**format == SECUREC_CHAR('d')) || (**format == SECUREC_CHAR('i')) ||
|
|
(**format == SECUREC_CHAR('o')) || (**format == SECUREC_CHAR('u')) ||
|
|
(**format == SECUREC_CHAR('x')) || (**format == SECUREC_CHAR('X'))) {
|
|
/* Do nothing */
|
|
} else {
|
|
/* Compatibility code for "%I" just print I */
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Decoded size identifier in format string, and skip format to next charater
|
|
*/
|
|
SECUREC_INLINE int SecDecodeSize(SecChar ch, SecFormatAttr *attr, const SecChar **format)
|
|
{
|
|
switch (ch) {
|
|
case SECUREC_CHAR('l'):
|
|
if (**format == SECUREC_CHAR('l')) {
|
|
*format = *format + 1;
|
|
attr->flags |= SECUREC_FLAG_LONGLONG; /* For long long */
|
|
} else {
|
|
attr->flags |= SECUREC_FLAG_LONG; /* For long int or wchar_t */
|
|
}
|
|
break;
|
|
#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
|
|
case SECUREC_CHAR('z'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('Z'):
|
|
attr->flags |= SECUREC_FLAG_SIZE;
|
|
break;
|
|
case SECUREC_CHAR('j'):
|
|
attr->flags |= SECUREC_FLAG_INTMAX;
|
|
break;
|
|
#endif
|
|
case SECUREC_CHAR('t'):
|
|
attr->flags |= SECUREC_FLAG_PTRDIFF;
|
|
break;
|
|
case SECUREC_CHAR('q'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('L'):
|
|
attr->flags |= (SECUREC_FLAG_LONGLONG | SECUREC_FLAG_LONG_DOUBLE);
|
|
break;
|
|
case SECUREC_CHAR('I'):
|
|
if (SecDecodeSizeI(attr, format) != 0) {
|
|
/* Compatibility code for "%I" just print I */
|
|
return -1;
|
|
}
|
|
break;
|
|
case SECUREC_CHAR('h'):
|
|
if (**format == SECUREC_CHAR('h')) {
|
|
*format = *format + 1;
|
|
attr->flags |= SECUREC_FLAG_CHAR; /* For char */
|
|
} else {
|
|
attr->flags |= SECUREC_FLAG_SHORT; /* For short int */
|
|
}
|
|
break;
|
|
case SECUREC_CHAR('w'):
|
|
attr->flags |= SECUREC_FLAG_WIDECHAR; /* For wide char */
|
|
break;
|
|
default:
|
|
/* Do nothing */
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Decoded char type identifier
|
|
*/
|
|
SECUREC_INLINE void SecDecodeTypeC(SecFormatAttr *attr, unsigned int c)
|
|
{
|
|
attr->textLen = 1; /* Only 1 wide character */
|
|
|
|
#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && !(defined(__hpux)) && !(defined(SECUREC_ON_SOLARIS))
|
|
attr->flags &= ~SECUREC_FLAG_LEADZERO;
|
|
#endif
|
|
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
if ((attr->flags & SECUREC_FLAG_SHORT) != 0) {
|
|
/* Get multibyte character from argument */
|
|
attr->buffer.str[0] = (char)c;
|
|
attr->text.str = attr->buffer.str;
|
|
attr->textIsWide = 0;
|
|
} else {
|
|
attr->buffer.wStr[0] = (wchar_t)c;
|
|
attr->text.wStr = attr->buffer.wStr;
|
|
attr->textIsWide = 1;
|
|
}
|
|
#else /* Not SECUREC_FOR_WCHAR */
|
|
if ((attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) != 0) {
|
|
#if SECUREC_HAVE_WCHART
|
|
attr->buffer.wStr[0] = (wchar_t)c;
|
|
attr->text.wStr = attr->buffer.wStr;
|
|
attr->textIsWide = 1;
|
|
#else
|
|
attr->textLen = 0; /* Ignore unsupported characters */
|
|
attr->fldWidth = 0; /* No paddings */
|
|
#endif
|
|
} else {
|
|
/* Get multibyte character from argument */
|
|
attr->buffer.str[0] = (char)c;
|
|
attr->text.str = attr->buffer.str;
|
|
attr->textIsWide = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
#define SECUREC_IS_NARROW_STRING(attr) (((attr)->flags & SECUREC_FLAG_SHORT) != 0)
|
|
#else
|
|
#define SECUREC_IS_NARROW_STRING(attr) (((attr)->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) == 0)
|
|
#endif
|
|
|
|
SECUREC_INLINE void SecDecodeTypeSchar(SecFormatAttr *attr)
|
|
{
|
|
size_t textLen;
|
|
if (attr->text.str == NULL) {
|
|
/*
|
|
* Literal string to print null ptr, define it as array rather than const text area
|
|
* To avoid gcc warning with pointing const text with variable
|
|
*/
|
|
static char strNullString[SECUREC_NULL_STRING_SIZE] = "(null)";
|
|
attr->text.str = strNullString;
|
|
}
|
|
if (attr->precision == -1) {
|
|
/* Precision NOT assigned */
|
|
/* The strlen performance is high when the string length is greater than 32 */
|
|
textLen = strlen(attr->text.str);
|
|
if (textLen > SECUREC_STRING_MAX_LEN) {
|
|
textLen = 0;
|
|
}
|
|
} else {
|
|
/* Precision assigned */
|
|
SECUREC_CALC_STR_LEN(attr->text.str, (size_t)(unsigned int)attr->precision, &textLen);
|
|
}
|
|
attr->textLen = (int)textLen;
|
|
}
|
|
|
|
SECUREC_INLINE void SecDecodeTypeSwchar(SecFormatAttr *attr)
|
|
{
|
|
#if SECUREC_HAVE_WCHART
|
|
size_t textLen;
|
|
attr->textIsWide = 1;
|
|
if (attr->text.wStr == NULL) {
|
|
/*
|
|
* Literal string to print null ptr, define it as array rather than const text area
|
|
* To avoid gcc warning with pointing const text with variable
|
|
*/
|
|
static wchar_t wStrNullString[SECUREC_NULL_STRING_SIZE] = { L'(', L'n', L'u', L'l', L'l', L')', L'\0', L'\0' };
|
|
attr->text.wStr = wStrNullString;
|
|
}
|
|
/* The textLen in wchar_t,when precision is -1, it is unlimited */
|
|
SECUREC_CALC_WSTR_LEN(attr->text.wStr, (size_t)(unsigned int)attr->precision, &textLen);
|
|
if (textLen > SECUREC_WCHAR_STRING_MAX_LEN) {
|
|
textLen = 0;
|
|
}
|
|
attr->textLen = (int)textLen;
|
|
#else
|
|
attr->textLen = 0;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Decoded string identifier
|
|
*/
|
|
SECUREC_INLINE void SecDecodeTypeS(SecFormatAttr *attr, char *argPtr)
|
|
{
|
|
#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT))
|
|
#if (!defined(SECUREC_ON_UNIX))
|
|
attr->flags &= ~SECUREC_FLAG_LEADZERO;
|
|
#endif
|
|
#if (defined(SECUREC_FOR_WCHAR))
|
|
if ((attr->flags & SECUREC_FLAG_LONG) == 0) {
|
|
attr->flags |= SECUREC_FLAG_SHORT;
|
|
}
|
|
#endif
|
|
#endif
|
|
attr->text.str = argPtr;
|
|
if (SECUREC_IS_NARROW_STRING(attr)) {
|
|
/* The textLen now contains length in multibyte chars */
|
|
SecDecodeTypeSchar(attr);
|
|
} else {
|
|
/* The textLen now contains length in wide chars */
|
|
SecDecodeTypeSwchar(attr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check precision in format
|
|
*/
|
|
SECUREC_INLINE int SecDecodePrecision(SecChar ch, SecFormatAttr *attr)
|
|
{
|
|
if (attr->dynPrecision == 0) {
|
|
/* Add digit to current precision */
|
|
if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->precision)) {
|
|
return -1;
|
|
}
|
|
attr->precision = (int)SECUREC_MUL_TEN((unsigned int)attr->precision) +
|
|
(unsigned char)(ch - SECUREC_CHAR('0'));
|
|
} else {
|
|
if (attr->precision < 0) {
|
|
attr->precision = -1;
|
|
}
|
|
if (attr->precision > SECUREC_MAX_WIDTH_LEN) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Check width in format
|
|
*/
|
|
SECUREC_INLINE int SecDecodeWidth(SecChar ch, SecFormatAttr *attr, SecFmtState lastState)
|
|
{
|
|
if (attr->dynWidth == 0) {
|
|
if (lastState != STAT_WIDTH) {
|
|
attr->fldWidth = 0;
|
|
}
|
|
if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->fldWidth)) {
|
|
return -1;
|
|
}
|
|
attr->fldWidth = (int)SECUREC_MUL_TEN((unsigned int)attr->fldWidth) +
|
|
(unsigned char)(ch - SECUREC_CHAR('0'));
|
|
} else {
|
|
if (attr->fldWidth < 0) {
|
|
attr->flags |= SECUREC_FLAG_LEFT;
|
|
attr->fldWidth = (-attr->fldWidth);
|
|
}
|
|
if (attr->fldWidth > SECUREC_MAX_WIDTH_LEN) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* The sprintf_s function processes the wide character as a parameter for %C
|
|
* The swprintf_s function processes the multiple character as a parameter for %C
|
|
*/
|
|
SECUREC_INLINE void SecUpdateWcharFlags(SecFormatAttr *attr)
|
|
{
|
|
if ((attr->flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) == 0) {
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
attr->flags |= SECUREC_FLAG_SHORT;
|
|
#else
|
|
attr->flags |= SECUREC_FLAG_WIDECHAR;
|
|
#endif
|
|
}
|
|
}
|
|
/*
|
|
* When encountering %S, current just same as %C
|
|
*/
|
|
SECUREC_INLINE void SecUpdateWstringFlags(SecFormatAttr *attr)
|
|
{
|
|
SecUpdateWcharFlags(attr);
|
|
}
|
|
|
|
#if SECUREC_IN_KERNEL
|
|
SECUREC_INLINE void SecUpdatePointFlagsForKernel(SecFormatAttr *attr)
|
|
{
|
|
/* Width is not set */
|
|
if (attr->fldWidth <= 0) {
|
|
attr->flags |= SECUREC_FLAG_LEADZERO;
|
|
attr->fldWidth = 2 * sizeof(void *); /* 2 x byte number is the length of hex */
|
|
}
|
|
if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
|
|
/* Alternate form means '0x' prefix */
|
|
attr->prefix[0] = SECUREC_CHAR('0');
|
|
attr->prefix[1] = SECUREC_CHAR('x');
|
|
attr->prefixLen = SECUREC_PREFIX_LEN;
|
|
}
|
|
attr->flags |= SECUREC_FLAG_LONG; /* Converting a long */
|
|
}
|
|
#endif
|
|
|
|
SECUREC_INLINE void SecUpdatePointFlags(SecFormatAttr *attr)
|
|
{
|
|
attr->flags |= SECUREC_FLAG_POINTER;
|
|
#if SECUREC_IN_KERNEL
|
|
SecUpdatePointFlagsForKernel(attr);
|
|
#else
|
|
#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) && (!defined(SECUREC_ON_UNIX))
|
|
#if defined(SECUREC_VXWORKS_PLATFORM)
|
|
attr->precision = 1;
|
|
#else
|
|
attr->precision = 0;
|
|
#endif
|
|
attr->flags |= SECUREC_FLAG_ALTERNATE; /* "0x" is not default prefix in UNIX */
|
|
attr->digits = g_itoaLowerDigits;
|
|
#else /* On unix or win */
|
|
#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
|
|
attr->precision = 1;
|
|
#else
|
|
attr->precision = 2 * sizeof(void *); /* 2 x byte number is the length of hex */
|
|
#endif
|
|
#if defined(SECUREC_ON_UNIX)
|
|
attr->digits = g_itoaLowerDigits;
|
|
#else
|
|
attr->digits = g_itoaUpperDigits;
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
|
|
attr->flags &= ~SECUREC_FLAG_LEADZERO;
|
|
#endif
|
|
|
|
#ifdef SECUREC_ON_64BITS
|
|
attr->flags |= SECUREC_FLAG_I64; /* Converting an int64 */
|
|
#else
|
|
attr->flags |= SECUREC_FLAG_LONG; /* Converting a long */
|
|
#endif
|
|
/* Set up for %#p on different system */
|
|
if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
|
|
/* Alternate form means '0x' prefix */
|
|
attr->prefix[0] = SECUREC_CHAR('0');
|
|
#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM))
|
|
attr->prefix[1] = SECUREC_CHAR('x');
|
|
#else
|
|
attr->prefix[1] = (SecChar)(attr->digits[SECUREC_NUMBER_OF_X]);
|
|
#endif
|
|
#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
|
|
attr->prefixLen = 0;
|
|
#else
|
|
attr->prefixLen = SECUREC_PREFIX_LEN;
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
SECUREC_INLINE void SecUpdateXpxFlags(SecFormatAttr *attr, SecChar ch)
|
|
{
|
|
/* Use unsigned lower hex output for 'x' */
|
|
attr->digits = g_itoaLowerDigits;
|
|
attr->radix = SECUREC_RADIX_HEX;
|
|
switch (ch) {
|
|
case SECUREC_CHAR('p'):
|
|
/* Print a pointer */
|
|
SecUpdatePointFlags(attr);
|
|
break;
|
|
case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */
|
|
/* Unsigned upper hex output */
|
|
attr->digits = g_itoaUpperDigits;
|
|
/* fall-through */ /* FALLTHRU */
|
|
default:
|
|
/* For %#x or %#X */
|
|
if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
|
|
/* Alternate form means '0x' prefix */
|
|
attr->prefix[0] = SECUREC_CHAR('0');
|
|
attr->prefix[1] = (SecChar)(attr->digits[SECUREC_NUMBER_OF_X]);
|
|
attr->prefixLen = SECUREC_PREFIX_LEN;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
SECUREC_INLINE void SecUpdateOudiFlags(SecFormatAttr *attr, SecChar ch)
|
|
{
|
|
/* Do not set digits here */
|
|
switch (ch) {
|
|
case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */
|
|
/* For signed decimal output */
|
|
attr->flags |= SECUREC_FLAG_SIGNED;
|
|
/* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('u'):
|
|
attr->radix = SECUREC_RADIX_DECIMAL;
|
|
attr->digits = g_itoaLowerDigits;
|
|
break;
|
|
case SECUREC_CHAR('o'):
|
|
/* For unsigned octal output */
|
|
attr->radix = SECUREC_RADIX_OCTAL;
|
|
attr->digits = g_itoaLowerDigits;
|
|
if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
|
|
/* Alternate form means force a leading 0 */
|
|
attr->flags |= SECUREC_FLAG_FORCE_OCTAL;
|
|
}
|
|
break;
|
|
default:
|
|
/* Do nothing */
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if SECUREC_ENABLE_SPRINTF_FLOAT
|
|
SECUREC_INLINE void SecFreeFloatBuffer(SecFloatAdapt *floatAdapt)
|
|
{
|
|
if (floatAdapt->floatBuffer != NULL) {
|
|
SECUREC_FREE(floatAdapt->floatBuffer);
|
|
}
|
|
if (floatAdapt->allocatedFmtStr != NULL) {
|
|
SECUREC_FREE(floatAdapt->allocatedFmtStr);
|
|
}
|
|
floatAdapt->floatBuffer = NULL;
|
|
floatAdapt->allocatedFmtStr = NULL;
|
|
floatAdapt->fmtStr = NULL;
|
|
floatAdapt->bufferSize = 0;
|
|
}
|
|
|
|
SECUREC_INLINE void SecSeekToFrontPercent(const SecChar **format)
|
|
{
|
|
const SecChar *fmt = *format;
|
|
while (*fmt != SECUREC_CHAR('%')) { /* Must meet '%' */
|
|
--fmt;
|
|
}
|
|
*format = fmt;
|
|
}
|
|
|
|
/* Init float format, return 0 is OK */
|
|
SECUREC_INLINE int SecInitFloatFmt(SecFloatAdapt *floatFmt, const SecChar *format)
|
|
{
|
|
const SecChar *fmt = format - 2; /* Sub 2 to the position before 'f' or 'g' */
|
|
int fmtStrLen;
|
|
int i;
|
|
|
|
SecSeekToFrontPercent(&fmt);
|
|
/* Now fmt point to '%' */
|
|
fmtStrLen = (int)(size_t)(format - fmt) + 1; /* With ending terminator */
|
|
if (fmtStrLen > (int)sizeof(floatFmt->buffer)) {
|
|
/* When buffer is NOT enough, alloc a new buffer */
|
|
floatFmt->allocatedFmtStr = (char *)SECUREC_MALLOC((size_t)((unsigned int)fmtStrLen));
|
|
if (floatFmt->allocatedFmtStr == NULL) {
|
|
return -1;
|
|
}
|
|
floatFmt->fmtStr = floatFmt->allocatedFmtStr;
|
|
} else {
|
|
floatFmt->fmtStr = floatFmt->buffer;
|
|
floatFmt->allocatedFmtStr = NULL; /* Must set to NULL, later code free memory based on this identity */
|
|
}
|
|
|
|
for (i = 0; i < fmtStrLen - 1; ++i) {
|
|
/* Convert wchar to char */
|
|
floatFmt->fmtStr[i] = (char)(fmt[i]); /* Copy the format string */
|
|
}
|
|
floatFmt->fmtStr[fmtStrLen - 1] = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Init float buffer and format, return 0 is OK */
|
|
SECUREC_INLINE int SecInitFloatBuffer(SecFloatAdapt *floatAdapt, const SecChar *format, SecFormatAttr *attr)
|
|
{
|
|
floatAdapt->allocatedFmtStr = NULL;
|
|
floatAdapt->fmtStr = NULL;
|
|
floatAdapt->floatBuffer = NULL;
|
|
/* Compute the precision value */
|
|
if (attr->precision < 0) {
|
|
attr->precision = SECUREC_FLOAT_DEFAULT_PRECISION;
|
|
}
|
|
/*
|
|
* Calc buffer size to store double value
|
|
* The maximum length of SECUREC_MAX_WIDTH_LEN is enough
|
|
*/
|
|
if ((attr->flags & SECUREC_FLAG_LONG_DOUBLE) != 0) {
|
|
if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE_LB)) {
|
|
return -1;
|
|
}
|
|
/* Long double needs to meet the basic print length */
|
|
floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE_LB + attr->precision + SECUREC_FLOAT_BUF_EXT;
|
|
} else {
|
|
if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE)) {
|
|
return -1;
|
|
}
|
|
/* Double needs to meet the basic print length */
|
|
floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE + attr->precision + SECUREC_FLOAT_BUF_EXT;
|
|
}
|
|
if (attr->fldWidth > floatAdapt->bufferSize) {
|
|
floatAdapt->bufferSize = attr->fldWidth + SECUREC_FLOAT_BUF_EXT;
|
|
}
|
|
|
|
if (floatAdapt->bufferSize > SECUREC_BUFFER_SIZE) {
|
|
/* The current value of SECUREC_BUFFER_SIZE could not store the formatted float string */
|
|
floatAdapt->floatBuffer = (char *)SECUREC_MALLOC(((size_t)(unsigned int)floatAdapt->bufferSize));
|
|
if (floatAdapt->floatBuffer == NULL) {
|
|
return -1;
|
|
}
|
|
attr->text.str = floatAdapt->floatBuffer;
|
|
} else {
|
|
attr->text.str = attr->buffer.str; /* Output buffer for float string with default size */
|
|
}
|
|
|
|
if (SecInitFloatFmt(floatAdapt, format) != 0) {
|
|
if (floatAdapt->floatBuffer != NULL) {
|
|
SECUREC_FREE(floatAdapt->floatBuffer);
|
|
floatAdapt->floatBuffer = NULL;
|
|
}
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
SECUREC_INLINE SecInt64 SecUpdateNegativeChar(SecFormatAttr *attr, char ch)
|
|
{
|
|
SecInt64 num64 = ch; /* Sign extend */
|
|
if (num64 >= 128) { /* 128 on some platform, char is always unsigned */
|
|
unsigned char tmp = (unsigned char)(~((unsigned char)ch));
|
|
num64 = tmp + 1;
|
|
attr->flags |= SECUREC_FLAG_NEGATIVE;
|
|
}
|
|
return num64;
|
|
}
|
|
|
|
/*
|
|
* If the precision is not satisfied, zero is added before the string
|
|
*/
|
|
SECUREC_INLINE void SecNumberSatisfyPrecision(SecFormatAttr *attr)
|
|
{
|
|
int precision;
|
|
if (attr->precision < 0) {
|
|
precision = 1; /* Default precision 1 */
|
|
} else {
|
|
#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
|
|
attr->flags &= ~SECUREC_FLAG_LEADZERO;
|
|
#else
|
|
if ((attr->flags & SECUREC_FLAG_POINTER) == 0) {
|
|
attr->flags &= ~SECUREC_FLAG_LEADZERO;
|
|
}
|
|
#endif
|
|
if (attr->precision > SECUREC_MAX_PRECISION) {
|
|
attr->precision = SECUREC_MAX_PRECISION;
|
|
}
|
|
precision = attr->precision;
|
|
}
|
|
while (attr->textLen < precision) {
|
|
--attr->text.str;
|
|
*(attr->text.str) = '0';
|
|
++attr->textLen;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add leading zero for %#o
|
|
*/
|
|
SECUREC_INLINE void SecNumberForceOctal(SecFormatAttr *attr)
|
|
{
|
|
/* Force a leading zero if FORCEOCTAL flag set */
|
|
if ((attr->flags & SECUREC_FLAG_FORCE_OCTAL) != 0 &&
|
|
(attr->textLen == 0 || attr->text.str[0] != '0')) {
|
|
--attr->text.str;
|
|
*(attr->text.str) = '0';
|
|
++attr->textLen;
|
|
}
|
|
}
|
|
|
|
SECUREC_INLINE void SecUpdateSignedNumberPrefix(SecFormatAttr *attr)
|
|
{
|
|
if ((attr->flags & SECUREC_FLAG_SIGNED) == 0) {
|
|
return;
|
|
}
|
|
if ((attr->flags & SECUREC_FLAG_NEGATIVE) != 0) {
|
|
/* Prefix is '-' */
|
|
attr->prefix[0] = SECUREC_CHAR('-');
|
|
attr->prefixLen = 1;
|
|
return;
|
|
}
|
|
if ((attr->flags & SECUREC_FLAG_SIGN) != 0) {
|
|
/* Prefix is '+' */
|
|
attr->prefix[0] = SECUREC_CHAR('+');
|
|
attr->prefixLen = 1;
|
|
return;
|
|
}
|
|
if ((attr->flags & SECUREC_FLAG_SIGN_SPACE) != 0) {
|
|
/* Prefix is ' ' */
|
|
attr->prefix[0] = SECUREC_CHAR(' ');
|
|
attr->prefixLen = 1;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
SECUREC_INLINE void SecNumberCompatZero(SecFormatAttr *attr)
|
|
{
|
|
#if SECUREC_IN_KERNEL
|
|
if ((attr->flags & SECUREC_FLAG_POINTER) != 0) {
|
|
static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(null)";
|
|
attr->text.str = strNullPointer;
|
|
attr->textLen = 6; /* Length of (null) is 6 */
|
|
attr->flags &= ~SECUREC_FLAG_LEADZERO;
|
|
attr->prefixLen = 0;
|
|
if (attr->precision >= 0 && attr->precision < attr->textLen) {
|
|
attr->textLen = attr->precision;
|
|
}
|
|
}
|
|
if ((attr->flags & SECUREC_FLAG_POINTER) == 0 && attr->radix == SECUREC_RADIX_HEX &&
|
|
(attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
|
|
/* Add 0x prefix for %x or %X, the prefix string has been set before */
|
|
attr->prefixLen = SECUREC_PREFIX_LEN;
|
|
}
|
|
#elif defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && (!defined(SECUREC_ON_UNIX))
|
|
if ((attr->flags & SECUREC_FLAG_POINTER) != 0) {
|
|
static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(nil)";
|
|
attr->text.str = strNullPointer;
|
|
attr->textLen = 5; /* Length of (nil) is 5 */
|
|
attr->flags &= ~SECUREC_FLAG_LEADZERO;
|
|
}
|
|
#elif defined(SECUREC_VXWORKS_PLATFORM) || defined(__hpux)
|
|
if ((attr->flags & SECUREC_FLAG_POINTER) != 0 && (attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
|
|
/* Add 0x prefix for %p, the prefix string has been set before */
|
|
attr->prefixLen = SECUREC_PREFIX_LEN;
|
|
}
|
|
#endif
|
|
(void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */
|
|
}
|
|
|
|
/*
|
|
* Formatting output core function
|
|
*/
|
|
SECUREC_INLINE int SecOutput(SecPrintfStream *stream, const SecChar *cFormat, va_list argList)
|
|
{
|
|
const SecChar *format = cFormat;
|
|
int charsOut; /* Characters written */
|
|
int noOutput = 0; /* Must be initialized or compiler alerts */
|
|
SecFmtState state;
|
|
SecFormatAttr formatAttr;
|
|
|
|
formatAttr.flags = 0;
|
|
formatAttr.textIsWide = 0; /* Flag for buffer contains wide chars */
|
|
formatAttr.fldWidth = 0;
|
|
formatAttr.precision = 0;
|
|
formatAttr.dynWidth = 0;
|
|
formatAttr.dynPrecision = 0;
|
|
formatAttr.digits = g_itoaUpperDigits;
|
|
formatAttr.radix = SECUREC_RADIX_DECIMAL;
|
|
formatAttr.padding = 0;
|
|
formatAttr.textLen = 0;
|
|
formatAttr.text.str = NULL;
|
|
formatAttr.prefixLen = 0;
|
|
formatAttr.prefix[0] = SECUREC_CHAR('\0');
|
|
formatAttr.prefix[1] = SECUREC_CHAR('\0');
|
|
charsOut = 0;
|
|
state = STAT_NORMAL; /* Starting state */
|
|
|
|
/* Loop each format character */
|
|
while (*format != SECUREC_CHAR('\0') && charsOut >= 0) {
|
|
SecFmtState lastState = state;
|
|
SecChar ch = *format; /* Currently read character */
|
|
++format;
|
|
state = SecDecodeState(ch, lastState);
|
|
switch (state) {
|
|
case STAT_NORMAL:
|
|
SecWriteChar(stream, ch, &charsOut);
|
|
continue;
|
|
case STAT_PERCENT:
|
|
/* Set default values */
|
|
noOutput = 0;
|
|
formatAttr.prefixLen = 0;
|
|
formatAttr.textLen = 0;
|
|
formatAttr.flags = 0;
|
|
formatAttr.fldWidth = 0;
|
|
formatAttr.precision = -1;
|
|
formatAttr.textIsWide = 0;
|
|
formatAttr.dynWidth = 0;
|
|
formatAttr.dynPrecision = 0;
|
|
break;
|
|
case STAT_FLAG:
|
|
/* Set flag based on which flag character */
|
|
SecDecodeFlags(ch, &formatAttr);
|
|
break;
|
|
case STAT_WIDTH:
|
|
/* Update width value */
|
|
if (ch == SECUREC_CHAR('*')) {
|
|
/* get width from arg list */
|
|
formatAttr.fldWidth = (int)va_arg(argList, int);
|
|
formatAttr.dynWidth = 1;
|
|
}
|
|
if (SecDecodeWidth(ch, &formatAttr, lastState) != 0) {
|
|
return -1;
|
|
}
|
|
break;
|
|
case STAT_DOT:
|
|
formatAttr.precision = 0;
|
|
break;
|
|
case STAT_PRECIS:
|
|
/* Update precision value */
|
|
if (ch == SECUREC_CHAR('*')) {
|
|
/* Get precision from arg list */
|
|
formatAttr.precision = (int)va_arg(argList, int);
|
|
formatAttr.dynPrecision = 1;
|
|
}
|
|
if (SecDecodePrecision(ch, &formatAttr) != 0) {
|
|
return -1;
|
|
}
|
|
break;
|
|
case STAT_SIZE:
|
|
/* Read a size specifier, set the formatAttr.flags based on it, and skip format to next character */
|
|
if (SecDecodeSize(ch, &formatAttr, &format) != 0) {
|
|
/* Compatibility code for "%I" just print I */
|
|
SecWriteChar(stream, ch, &charsOut);
|
|
state = STAT_NORMAL;
|
|
continue;
|
|
}
|
|
break;
|
|
case STAT_TYPE:
|
|
switch (ch) {
|
|
case SECUREC_CHAR('C'): /* Wide char */
|
|
SecUpdateWcharFlags(&formatAttr);
|
|
/* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('c'): {
|
|
unsigned int cValue = (unsigned int)va_arg(argList, int);
|
|
SecDecodeTypeC(&formatAttr, cValue);
|
|
break;
|
|
}
|
|
case SECUREC_CHAR('S'): /* Wide char string */
|
|
SecUpdateWstringFlags(&formatAttr);
|
|
/* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('s'): {
|
|
char *argPtr = (char *)va_arg(argList, char *);
|
|
SecDecodeTypeS(&formatAttr, argPtr);
|
|
break;
|
|
}
|
|
case SECUREC_CHAR('G'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('g'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('E'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('e'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('f'): {
|
|
#if SECUREC_ENABLE_SPRINTF_FLOAT
|
|
/* Add following code to call system sprintf API for float number */
|
|
SecFloatAdapt floatAdapt;
|
|
noOutput = 1; /* It's no more data needs to be written */
|
|
|
|
/* Now format is pointer to the next character of 'f' */
|
|
if (SecInitFloatBuffer(&floatAdapt, format, &formatAttr) != 0) {
|
|
break;
|
|
}
|
|
|
|
if ((formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) != 0) {
|
|
#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
|
|
long double tmp = (long double)va_arg(argList, long double);
|
|
SecFormatLongDouble(&formatAttr, &floatAdapt, tmp);
|
|
#else
|
|
double tmp = (double)va_arg(argList, double);
|
|
SecFormatDouble(&formatAttr, &floatAdapt, tmp);
|
|
#endif
|
|
} else {
|
|
double tmp = (double)va_arg(argList, double);
|
|
SecFormatDouble(&formatAttr, &floatAdapt, tmp);
|
|
}
|
|
|
|
/* Only need write formatted float string */
|
|
SecWriteFloatText(stream, &formatAttr, &charsOut);
|
|
SecFreeFloatBuffer(&floatAdapt);
|
|
break;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('p'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('x'): /* fall-through */ /* FALLTHRU */
|
|
SecUpdateXpxFlags(&formatAttr, ch);
|
|
/* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('u'): /* fall-through */ /* FALLTHRU */
|
|
case SECUREC_CHAR('o'): {
|
|
SecInt64 num64;
|
|
SecUpdateOudiFlags(&formatAttr, ch);
|
|
/* Read argument into variable num64. Be careful, depend on the order of judgment */
|
|
if ((formatAttr.flags & SECUREC_FLAG_I64) != 0 ||
|
|
(formatAttr.flags & SECUREC_FLAG_LONGLONG) != 0) {
|
|
num64 = (SecInt64)va_arg(argList, SecInt64); /* Maximum Bit Width sign bit unchanged */
|
|
} else if ((formatAttr.flags & SECUREC_FLAG_LONG) != 0) {
|
|
num64 = SECUREC_GET_LONG_FROM_ARG(formatAttr);
|
|
} else if ((formatAttr.flags & SECUREC_FLAG_CHAR) != 0) {
|
|
num64 = SECUREC_GET_CHAR_FROM_ARG(formatAttr);
|
|
} else if ((formatAttr.flags & SECUREC_FLAG_SHORT) != 0) {
|
|
num64 = SECUREC_GET_SHORT_FROM_ARG(formatAttr);
|
|
#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
|
|
} else if ((formatAttr.flags & SECUREC_FLAG_PTRDIFF) != 0) {
|
|
num64 = (ptrdiff_t)va_arg(argList, ptrdiff_t); /* Sign extend */
|
|
} else if ((formatAttr.flags & SECUREC_FLAG_SIZE) != 0) {
|
|
num64 = SECUREC_GET_SIZE_FROM_ARG(formatAttr);
|
|
} else if ((formatAttr.flags & SECUREC_FLAG_INTMAX) != 0) {
|
|
num64 = (SecInt64)va_arg(argList, SecInt64);
|
|
#endif
|
|
} else {
|
|
num64 = SECUREC_GET_INT_FROM_ARG(formatAttr);
|
|
}
|
|
|
|
/* The order of the following calls must be correct */
|
|
SecNumberToBuffer(&formatAttr, num64);
|
|
SecNumberSatisfyPrecision(&formatAttr);
|
|
SecNumberForceOctal(&formatAttr);
|
|
SecUpdateSignedNumberPrefix(&formatAttr);
|
|
if (num64 == 0) {
|
|
SecNumberCompatZero(&formatAttr);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
/* Do nothing */
|
|
break;
|
|
}
|
|
|
|
if (noOutput == 0) {
|
|
/* Calculate amount of padding */
|
|
formatAttr.padding = (formatAttr.fldWidth - formatAttr.textLen) - formatAttr.prefixLen;
|
|
|
|
/* Put out the padding, prefix, and text, in the correct order */
|
|
SecWriteLeftPadding(stream, &formatAttr, &charsOut);
|
|
SecWritePrefix(stream, &formatAttr, &charsOut);
|
|
SecWriteLeadingZero(stream, &formatAttr, &charsOut);
|
|
SecWriteText(stream, &formatAttr, &charsOut);
|
|
SecWriteRightPadding(stream, &formatAttr, &charsOut);
|
|
}
|
|
break;
|
|
case STAT_INVALID: /* fall-through */ /* FALLTHRU */
|
|
default:
|
|
return -1; /* Input format is wrong(STAT_INVALID), directly return */
|
|
}
|
|
}
|
|
|
|
if (state != STAT_NORMAL && state != STAT_TYPE) {
|
|
return -1;
|
|
}
|
|
|
|
return charsOut; /* The number of characters written */
|
|
}
|
|
|
|
/*
|
|
* Output one zero character zero into the SecPrintfStream structure
|
|
* If there is not enough space, make sure f->count is less than 0
|
|
*/
|
|
SECUREC_INLINE int SecPutZeroChar(SecPrintfStream *stream)
|
|
{
|
|
--stream->count;
|
|
if (stream->count >= 0) {
|
|
*(stream->cur) = SECUREC_CHAR('\0');
|
|
++stream->cur;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Multi character formatted output implementation
|
|
*/
|
|
#ifdef SECUREC_FOR_WCHAR
|
|
int SecVswprintfImpl(wchar_t *string, size_t count, const wchar_t *format, va_list argList)
|
|
#else
|
|
int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList)
|
|
#endif
|
|
{
|
|
SecPrintfStream stream;
|
|
int retVal;
|
|
|
|
stream.count = (int)count; /* The count include \0 character, must be greater than zero */
|
|
stream.cur = string;
|
|
|
|
retVal = SecOutput(&stream, format, argList);
|
|
if (retVal >= 0) {
|
|
if (SecPutZeroChar(&stream) == 0) {
|
|
return retVal;
|
|
}
|
|
}
|
|
if (stream.count < 0) {
|
|
/* The buffer was too small, then truncate */
|
|
string[count - 1] = SECUREC_CHAR('\0');
|
|
return SECUREC_PRINTF_TRUNCATE;
|
|
}
|
|
string[0] = SECUREC_CHAR('\0'); /* Empty the dest string */
|
|
return -1;
|
|
}
|
|
#endif /* OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 */
|
|
|