• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2014-2021. All rights reserved.
3 * Licensed under Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 *          http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 * Description: Used by secureprintoutput_a.c and secureprintoutput_w.c to include.
12 *              This file provides a template function for ANSI and UNICODE compiling
13 *              by different type definition. The functions of SecOutputS or
14 *              SecOutputSW  provides internal implementation for printf family API, such as sprintf, swprintf_s.
15 * Create: 2014-02-25
16 * Notes: see www.cplusplus.com/reference/cstdio/printf/
17 */
18/*
19 * [Standardize-exceptions] Use unsafe function: Portability
20 * [reason] Use unsafe function to implement security function to maintain platform compatibility.
21 *          And sufficient input validation is performed before calling
22 */
23#ifndef OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
24#define OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5
25
26#ifndef SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
27/* Some compilers do not support long double */
28#define SECUREC_ENABLE_SPRINTF_LONG_DOUBLE 1
29#endif
30
31#define SECUREC_NULL_STRING_SIZE            8
32#define SECUREC_STATE_TABLE_SIZE            337
33
34#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)
35#define SECUREC_DIV_QUOTIENT_OCTAL(val64)     ((val64) >> 3ULL)
36#define SECUREC_DIV_RESIDUE_OCTAL(val64)      ((val64) & 7ULL)
37
38#define SECUREC_DIV_QUOTIENT_HEX(val64)       ((val64) >> 4ULL)
39#define SECUREC_DIV_RESIDUE_HEX(val64)        ((val64) & 0xfULL)
40#endif
41
42#define SECUREC_RADIX_OCTAL                 8U
43#define SECUREC_RADIX_DECIMAL               10U
44#define SECUREC_RADIX_HEX                   16U
45#define SECUREC_PREFIX_LEN                  2
46/* Size include '+' and '\0' */
47#define SECUREC_FLOAT_BUF_EXT               2
48
49/* Sign extend or Zero-extend */
50#define SECUREC_GET_LONG_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
51    (SecInt64)(long)va_arg(argList, long) : \
52    (SecInt64)(unsigned long)va_arg(argList, long))
53
54/* Sign extend or Zero-extend */
55#define SECUREC_GET_CHAR_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
56    SecUpdateNegativeChar(&(attr), ((char)va_arg(argList, int))) : \
57    (SecInt64)(unsigned char)va_arg(argList, int))
58
59/* Sign extend or Zero-extend */
60#define SECUREC_GET_SHORT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
61    (SecInt64)(short)va_arg(argList, int) : \
62    (SecInt64)(unsigned short)va_arg(argList, int))
63
64/* Sign extend or Zero-extend */
65#define SECUREC_GET_INT_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
66    (SecInt64)(int)va_arg(argList, int) : \
67    (SecInt64)(unsigned int)va_arg(argList, int))
68
69#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
70/* Sign extend or Zero-extend. No suitable macros were found to handle the branch */
71#define SECUREC_GET_SIZE_FROM_ARG(attr) ((((attr).flags & SECUREC_FLAG_SIGNED) != 0) ? \
72    ((SecIsSameSize(sizeof(size_t), sizeof(long)) != 0) ? (SecInt64)(long)va_arg(argList, long) : \
73    ((SecIsSameSize(sizeof(size_t), sizeof(long long)) != 0) ? (SecInt64)(long long)va_arg(argList, long long) : \
74    (SecInt64)(int)va_arg(argList, int))) : \
75    (SecInt64)(size_t)va_arg(argList, size_t))
76#endif
77
78/* Format output buffer pointer and available size */
79typedef struct {
80    int count;
81    SecChar *cur;
82} SecPrintfStream;
83
84typedef union {
85    /* Integer formatting refers to the end of the buffer, plus 1 to prevent tool alarms */
86    char str[SECUREC_BUFFER_SIZE + 1];
87#if SECUREC_HAVE_WCHART
88    wchar_t wStr[SECUREC_WCHAR_BUFFER_SIZE]; /* Just for %lc */
89#endif
90} SecBuffer;
91
92typedef union {
93    char *str;                  /* Not a null terminated  string */
94#if SECUREC_HAVE_WCHART
95    wchar_t *wStr;
96#endif
97} SecFormatBuf;
98
99typedef struct {
100    const char *digits;                 /* Point to the hexadecimal subset */
101    SecFormatBuf text;                  /* Point to formatted string */
102    int textLen;                        /* Length of the text */
103    int textIsWide;                     /* Flag for text is wide chars ; 0 is not wide char */
104    unsigned int radix;                 /* Use for output number , default set to 10 */
105    unsigned int flags;
106    int fldWidth;
107    int precision;
108    int dynWidth;                       /* %*   1 width from variable parameter ;0 not */
109    int dynPrecision;                   /* %.*  1 precision from variable parameter ;0 not */
110    int padding;                        /* Padding len */
111    int prefixLen;                      /* Length of prefix, 0 or 1 or 2 */
112    SecChar prefix[SECUREC_PREFIX_LEN]; /* Prefix is  0 or 0x */
113    SecBuffer buffer;
114} SecFormatAttr;
115
116#if SECUREC_ENABLE_SPRINTF_FLOAT
117#ifdef SECUREC_STACK_SIZE_LESS_THAN_1K
118#define SECUREC_FMT_STR_LEN                 8
119#else
120#define SECUREC_FMT_STR_LEN                 16
121#endif
122typedef struct {
123    char buffer[SECUREC_FMT_STR_LEN];
124    char *fmtStr;                     /* Initialization must point to buffer */
125    char *allocatedFmtStr;            /* Initialization must be NULL  to store allocated point */
126    char *floatBuffer;                /* Use heap memory if the SecFormatAttr.buffer is not enough */
127    int bufferSize;                   /* The size of floatBuffer */
128} SecFloatAdapt;
129#endif
130
131/* Use 20 to Align the data */
132#define SECUREC_DIGITS_BUF_SIZE  20
133/* The serial number of 'x' or 'X' is 16 */
134#define SECUREC_NUMBER_OF_X  16
135/* Some systems can not use pointers to point to string literals, but can use string arrays. */
136/* For example, when handling code under uboot, there is a problem with the pointer */
137static const char g_itoaUpperDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789ABCDEFX";
138static const char g_itoaLowerDigits[SECUREC_DIGITS_BUF_SIZE] = "0123456789abcdefx";
139
140#if SECUREC_ENABLE_SPRINTF_FLOAT
141/* Call system sprintf to format float value */
142SECUREC_INLINE int SecFormatFloat(char *strDest, const char *format, ...)
143{
144    int ret;                    /* If initialization causes  e838 */
145    va_list argList;
146
147    va_start(argList, format);
148    SECUREC_MASK_VSPRINTF_WARNING
149    ret = vsprintf(strDest, format, argList);
150    SECUREC_END_MASK_VSPRINTF_WARNING
151    va_end(argList);
152    (void)argList; /* To clear e438 last value assigned not used , the compiler will optimize this code */
153
154    return ret;
155}
156
157#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
158/* Out put long double value to dest */
159SECUREC_INLINE void SecFormatLongDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, long double ldValue)
160{
161    int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth);
162    if (attr->dynWidth != 0 && attr->dynPrecision != 0) {
163        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, ldValue);
164    } else if (attr->dynWidth != 0) {
165        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, ldValue);
166    } else if (attr->dynPrecision != 0) {
167        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, ldValue);
168    } else {
169        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, ldValue);
170    }
171    if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) {
172        attr->textLen = 0;
173    }
174}
175#endif
176
177/* Out put double value to dest */
178SECUREC_INLINE void SecFormatDouble(SecFormatAttr *attr, const SecFloatAdapt *floatAdapt, double dValue)
179{
180    int fldWidth = (((attr->flags & SECUREC_FLAG_LEFT) != 0) ? (-attr->fldWidth) : attr->fldWidth);
181    if (attr->dynWidth != 0 && attr->dynPrecision != 0) {
182        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, attr->precision, dValue);
183    } else if (attr->dynWidth != 0) {
184        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, fldWidth, dValue);
185    } else if (attr->dynPrecision != 0) {
186        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, attr->precision, dValue);
187    } else {
188        attr->textLen = SecFormatFloat(attr->text.str, floatAdapt->fmtStr, dValue);
189    }
190    if (attr->textLen < 0 || attr->textLen >= floatAdapt->bufferSize) {
191        attr->textLen = 0;
192    }
193}
194#endif
195
196#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
197/* To clear e506 warning */
198SECUREC_INLINE int SecIsSameSize(size_t sizeA, size_t sizeB)
199{
200    return (int)(sizeA == sizeB);
201}
202#endif
203
204#ifndef SECUREC_ON_64BITS
205/*
206 * Compiler Optimized Division 8.
207 * The text.str point to buffer end, must be Large enough
208 */
209SECUREC_INLINE void SecNumber32ToOctalString(SecUnsignedInt32 number, SecFormatAttr *attr)
210{
211    SecUnsignedInt32 val32 = number;
212    do {
213        --attr->text.str;
214        /* Just use lowerDigits for 0 - 9 */
215        *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_OCTAL];
216        val32 /= SECUREC_RADIX_OCTAL;
217    } while (val32 != 0);
218}
219
220#ifdef _AIX
221/*
222 * Compiler Optimized Division 10.
223 * The text.str point to buffer end, must be Large enough
224 */
225SECUREC_INLINE void SecNumber32ToDecString(SecUnsignedInt32 number, SecFormatAttr *attr)
226{
227    SecUnsignedInt32 val32 = number;
228    do {
229        --attr->text.str;
230        /* Just use lowerDigits for 0 - 9 */
231        *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL];
232        val32 /= SECUREC_RADIX_DECIMAL;
233    } while (val32 != 0);
234}
235#endif
236/*
237 * Compiler Optimized Division 16.
238 * The text.str point to buffer end, must be Large enough
239 */
240SECUREC_INLINE void SecNumber32ToHexString(SecUnsignedInt32 number, SecFormatAttr *attr)
241{
242    SecUnsignedInt32 val32 = number;
243    do {
244        --attr->text.str;
245        *(attr->text.str) = attr->digits[val32 % SECUREC_RADIX_HEX];
246        val32 /= SECUREC_RADIX_HEX;
247    } while (val32 != 0);
248}
249
250#ifndef _AIX
251/* Use fast div 10 */
252SECUREC_INLINE void SecNumber32ToDecStringFast(SecUnsignedInt32 number, SecFormatAttr *attr)
253{
254    SecUnsignedInt32 val32 = number;
255    do {
256        SecUnsignedInt32 quotient;
257        SecUnsignedInt32 remain;
258        --attr->text.str;
259        *(attr->text.str) = g_itoaLowerDigits[val32 % SECUREC_RADIX_DECIMAL];
260        quotient = (val32 >> 1U) + (val32 >> 2U); /* Fast div  magic 2 */
261        quotient = quotient + (quotient >> 4U); /* Fast div  magic 4 */
262        quotient = quotient + (quotient >> 8U); /* Fast div  magic 8 */
263        quotient = quotient + (quotient >> 16U); /* Fast div  magic 16 */
264        quotient = quotient >> 3U; /* Fast div  magic 3 */
265        remain = val32 - SECUREC_MUL_TEN(quotient);
266        val32 = (remain > 9U) ? (quotient + 1U) : quotient; /* Fast div  magic 9 */
267    } while (val32 != 0);
268}
269#endif
270
271SECUREC_INLINE void SecNumber32ToString(SecUnsignedInt32 number, SecFormatAttr *attr)
272{
273    switch (attr->radix) {
274        case SECUREC_RADIX_HEX:
275            SecNumber32ToHexString(number, attr);
276            break;
277        case SECUREC_RADIX_OCTAL:
278            SecNumber32ToOctalString(number, attr);
279            break;
280        case SECUREC_RADIX_DECIMAL:
281#ifdef _AIX
282            /* The compiler will optimize div 10 */
283            SecNumber32ToDecString(number, attr);
284#else
285            SecNumber32ToDecStringFast(number, attr);
286#endif
287            break;
288        default:
289            /* Do nothing */
290            break;
291    }
292}
293#endif
294
295#if defined(SECUREC_USE_SPECIAL_DIV64) || (defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS))
296/*
297 * This function just to clear warning, on sume vxworks compiler shift 32 bit make warnings
298 */
299SECUREC_INLINE SecUnsignedInt64 SecU64Shr32(SecUnsignedInt64 number)
300{
301    return (((number) >> 16U) >> 16U); /* Two shifts of 16 bits to realize shifts of 32 bits */
302}
303/*
304 * Fast divide by 10 algorithm.
305 * Calculation divisor multiply  0xcccccccccccccccdULL, resultHi64 >> 3 as quotient
306 */
307SECUREC_INLINE void SecU64Div10(SecUnsignedInt64 divisor, SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue)
308{
309    SecUnsignedInt64 mask = 0xffffffffULL; /* Use 0xffffffffULL as 32 bit mask */
310    SecUnsignedInt64 magicHi = 0xccccccccULL; /* Fast divide 10 magic numbers high 32bit 0xccccccccULL */
311    SecUnsignedInt64 magicLow = 0xcccccccdULL; /* Fast divide 10 magic numbers low 32bit  0xcccccccdULL */
312    SecUnsignedInt64 divisorHi = (SecUnsignedInt64)(SecU64Shr32(divisor)); /* High 32 bit use  */
313    SecUnsignedInt64 divisorLow = (SecUnsignedInt64)(divisor & mask); /* Low 32 bit mask */
314    SecUnsignedInt64 factorHi = divisorHi * magicHi;
315    SecUnsignedInt64 factorLow1 = divisorHi * magicLow;
316    SecUnsignedInt64 factorLow2 = divisorLow * magicHi;
317    SecUnsignedInt64 factorLow3 = divisorLow * magicLow;
318    SecUnsignedInt64 carry = (factorLow1 & mask) + (factorLow2 & mask) + SecU64Shr32(factorLow3);
319    SecUnsignedInt64 resultHi64 = factorHi + SecU64Shr32(factorLow1) + SecU64Shr32(factorLow2) + SecU64Shr32(carry);
320
321    *quotient = resultHi64 >> 3U; /* Fast divide 10 magic numbers 3 */
322    *residue = (SecUnsignedInt32)(divisor - ((*quotient) * 10)); /* Quotient mul 10 */
323    return;
324}
325#if defined(SECUREC_VXWORKS_VERSION_5_4) && !defined(SECUREC_ON_64BITS)
326/*
327 * Divide function for VXWORKS
328 */
329SECUREC_INLINE int SecU64Div32(SecUnsignedInt64 divisor, SecUnsignedInt32 radix,
330    SecUnsignedInt64 *quotient, SecUnsignedInt32 *residue)
331{
332    switch (radix) {
333        case SECUREC_RADIX_DECIMAL:
334            SecU64Div10(divisor, quotient, residue);
335            break;
336        case SECUREC_RADIX_HEX:
337            *quotient = SECUREC_DIV_QUOTIENT_HEX(divisor);
338            *residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_HEX(divisor);
339            break;
340        case SECUREC_RADIX_OCTAL:
341            *quotient = SECUREC_DIV_QUOTIENT_OCTAL(divisor);
342            *residue = (SecUnsignedInt32)SECUREC_DIV_RESIDUE_OCTAL(divisor);
343            break;
344        default:
345            return -1; /* This does not happen in the current file */
346    }
347    return 0;
348}
349SECUREC_INLINE void SecNumber64ToStringSpecial(SecUnsignedInt64 number, SecFormatAttr *attr)
350{
351    SecUnsignedInt64 val64 = number;
352    do {
353        SecUnsignedInt32 digit = 0; /* Ascii value of digit */
354        SecUnsignedInt64 quotient = 0;
355        if (SecU64Div32(val64, (SecUnsignedInt32)attr->radix, &quotient, &digit) != 0) {
356            /* Just break, when enter this function, no error is returned */
357            break;
358        }
359        --attr->text.str;
360        *(attr->text.str) = attr->digits[digit];
361        val64 = quotient;
362    } while (val64 != 0);
363}
364#endif
365#endif
366
367#if defined(SECUREC_ON_64BITS) || !defined(SECUREC_VXWORKS_VERSION_5_4)
368#if defined(SECUREC_USE_SPECIAL_DIV64)
369/* The compiler does not provide 64 bit division problems */
370SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr)
371{
372    SecUnsignedInt64 val64 = number;
373    do {
374        SecUnsignedInt64 quotient = 0;
375        SecUnsignedInt32 digit = 0;
376        SecU64Div10(val64, &quotient, &digit);
377        --attr->text.str;
378        /* Just use lowerDigits for 0 - 9 */
379        *(attr->text.str) = g_itoaLowerDigits[digit];
380        val64 = quotient;
381    } while (val64 != 0);
382}
383#else
384/*
385 * Compiler Optimized Division 10.
386 * The text.str point to buffer end, must be Large enough
387 */
388SECUREC_INLINE void SecNumber64ToDecString(SecUnsignedInt64 number, SecFormatAttr *attr)
389{
390    SecUnsignedInt64 val64 = number;
391    do {
392        --attr->text.str;
393        /* Just use lowerDigits for 0 - 9 */
394        *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_DECIMAL];
395        val64 /= SECUREC_RADIX_DECIMAL;
396    } while (val64 != 0);
397}
398#endif
399
400/*
401 * Compiler Optimized Division 8.
402 * The text.str point to buffer end, must be Large enough
403 */
404SECUREC_INLINE void SecNumber64ToOctalString(SecUnsignedInt64 number, SecFormatAttr *attr)
405{
406    SecUnsignedInt64 val64 = number;
407    do {
408        --attr->text.str;
409        /* Just use lowerDigits for 0 - 9 */
410        *(attr->text.str) = g_itoaLowerDigits[val64 % SECUREC_RADIX_OCTAL];
411        val64 /= SECUREC_RADIX_OCTAL;
412    } while (val64 != 0);
413}
414/*
415 * Compiler Optimized Division 16.
416 * The text.str point to buffer end, must be Large enough
417 */
418SECUREC_INLINE void SecNumber64ToHexString(SecUnsignedInt64 number, SecFormatAttr *attr)
419{
420    SecUnsignedInt64 val64 = number;
421    do {
422        --attr->text.str;
423        *(attr->text.str) = attr->digits[val64 % SECUREC_RADIX_HEX];
424        val64 /= SECUREC_RADIX_HEX;
425    } while (val64 != 0);
426}
427
428SECUREC_INLINE void SecNumber64ToString(SecUnsignedInt64 number, SecFormatAttr *attr)
429{
430    switch (attr->radix) {
431        /* The compiler will optimize div 10 */
432        case SECUREC_RADIX_DECIMAL:
433            SecNumber64ToDecString(number, attr);
434            break;
435        case SECUREC_RADIX_OCTAL:
436            SecNumber64ToOctalString(number, attr);
437            break;
438        case SECUREC_RADIX_HEX:
439            SecNumber64ToHexString(number, attr);
440            break;
441        default:
442            /* Do nothing */
443            break;
444    }
445}
446#endif
447
448/*
449 * Converting integers to string
450 */
451SECUREC_INLINE void SecNumberToString(SecUnsignedInt64 number, SecFormatAttr *attr)
452{
453#ifdef SECUREC_ON_64BITS
454    SecNumber64ToString(number, attr);
455#else /* For 32 bits system */
456    if (number <= 0xffffffffUL) { /* Use 0xffffffffUL to check if the value is in the 32-bit range */
457        /* In most case, the value to be converted is small value */
458        SecUnsignedInt32 n32Tmp = (SecUnsignedInt32)number;
459        SecNumber32ToString(n32Tmp, attr);
460    } else {
461        /* The value to be converted is greater than 4G */
462#if defined(SECUREC_VXWORKS_VERSION_5_4)
463        SecNumber64ToStringSpecial(number, attr);
464#else
465        SecNumber64ToString(number, attr);
466#endif
467    }
468#endif
469}
470
471SECUREC_INLINE int SecIsNumberNeedTo32Bit(const SecFormatAttr *attr)
472{
473    return (int)(((attr->flags & SECUREC_FLAG_I64) == 0) &&
474#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
475            ((attr->flags & SECUREC_FLAG_INTMAX) == 0) &&
476#endif
477#ifdef SECUREC_ON_64BITS
478            ((attr->flags & SECUREC_FLAG_PTRDIFF) == 0) &&
479            ((attr->flags & SECUREC_FLAG_SIZE) == 0) &&
480#if !defined(SECUREC_COMPATIBLE_WIN_FORMAT)  /* on window 64 system sizeof long is 32bit */
481            ((attr->flags & SECUREC_FLAG_LONG) == 0) &&
482#endif
483#endif
484            ((attr->flags & SECUREC_FLAG_LONGLONG) == 0));
485}
486
487SECUREC_INLINE void SecNumberToBuffer(SecFormatAttr *attr, SecInt64 num64)
488{
489    SecUnsignedInt64 number;
490    /* Check for negative; copy into number */
491    if ((attr->flags & SECUREC_FLAG_SIGNED) != 0 && num64 < 0) {
492        number = (SecUnsignedInt64)(0 - (SecUnsignedInt64)num64); /* Wrap with unsigned int64 numbers */
493        attr->flags |= SECUREC_FLAG_NEGATIVE;
494    } else {
495        number = (SecUnsignedInt64)num64;
496    }
497    if (SecIsNumberNeedTo32Bit(attr) != 0) {
498        number = (number & (SecUnsignedInt64)0xffffffffUL);  /* Use 0xffffffff as 32 bit mask */
499    }
500
501    /* The text.str must be point to buffer.str, this pointer is used outside the function */
502    attr->text.str = &attr->buffer.str[SECUREC_BUFFER_SIZE];
503
504    if (number == 0) {
505        /* Turn off hex prefix default, and textLen is zero */
506        attr->prefixLen = 0;
507        attr->textLen = 0;
508        return;
509    }
510
511    /* Convert integer to string. It must be invoked when number > 0, otherwise the following logic is incorrect */
512    SecNumberToString(number, attr);
513    /* Compute length of number,  text.str must be in buffer.str */
514    attr->textLen = (int)(size_t)((char *)&attr->buffer.str[SECUREC_BUFFER_SIZE] - attr->text.str);
515}
516
517/*
518 * Write one character to dest buffer
519 */
520SECUREC_INLINE void SecWriteChar(SecPrintfStream *stream, SecChar ch, int *charsOut)
521{
522    /* Count must be reduced first, In order to identify insufficient length */
523    --stream->count;
524    if (stream->count >= 0) {
525        *(stream->cur) = ch;
526        ++stream->cur;
527        *charsOut = *charsOut + 1;
528        return;
529    }
530    /* No enough length */
531    *charsOut = -1;
532}
533
534/*
535* Write multiple identical characters.
536*/
537SECUREC_INLINE void SecWriteMultiChar(SecPrintfStream *stream, SecChar ch, int num, int *charsOut)
538{
539    int count;
540    for (count = num; count > 0; --count) {
541        --stream->count; /* count may be negative,indicating insufficient space */
542        if (stream->count < 0) {
543            *charsOut = -1;
544            return;
545        }
546        *(stream->cur) = ch;
547        ++stream->cur;
548    }
549    *charsOut = *charsOut + num;
550}
551
552/*
553* Write string function, where this function is called, make sure that len is greater than 0
554*/
555SECUREC_INLINE void SecWriteString(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut)
556{
557    const SecChar *tmp = str;
558    int count;
559    for (count = len; count > 0; --count) {
560        --stream->count; /* count may be negative,indicating insufficient space */
561        if (stream->count < 0) {
562            *charsOut = -1;
563            return;
564        }
565        *(stream->cur) = *tmp;
566        ++stream->cur;
567        ++tmp;
568    }
569    *charsOut = *charsOut + len;
570}
571
572/* Use loop copy char or wchar_t string */
573SECUREC_INLINE void SecWriteStringByLoop(SecPrintfStream *stream, const SecChar *str, int len)
574{
575    int i;
576    const SecChar *tmp = str;
577    for (i = 0; i < len; ++i) {
578        *stream->cur = *tmp;
579        ++stream->cur;
580        ++tmp;
581    }
582    stream->count -= len;
583}
584
585SECUREC_INLINE void SecWriteStringOpt(SecPrintfStream *stream, const SecChar *str, int len)
586{
587    if (len < 12) { /* Performance optimization for mobile number length 12 */
588        SecWriteStringByLoop(stream, str, len);
589    } else {
590        size_t count = (size_t)(unsigned int)len * sizeof(SecChar);
591        SECUREC_MEMCPY_WARP_OPT(stream->cur, str, count);
592        stream->cur += len;
593        stream->count -= len;
594    }
595}
596
597/*
598 * Return if buffer length is enough
599 * The count variable can be reduced to 0, and the external function complements the \0 terminator.
600 */
601SECUREC_INLINE int SecIsStreamBufEnough(const SecPrintfStream *stream, int needLen)
602{
603    return (int)(stream->count >= needLen);
604}
605
606/* Write text string */
607SECUREC_INLINE void SecWriteTextOpt(SecPrintfStream *stream, const SecChar *str, int len, int *charsOut)
608{
609    if (SecIsStreamBufEnough(stream, len) != 0) {
610        SecWriteStringOpt(stream, str, len);
611        *charsOut += len;
612    } else {
613        SecWriteString(stream, str, len, charsOut);
614    }
615}
616
617/* Write left padding */
618SECUREC_INLINE void SecWriteLeftPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
619{
620    if ((attr->flags & (SECUREC_FLAG_LEFT | SECUREC_FLAG_LEADZERO)) == 0 && attr->padding > 0) {
621        /* Pad on left with blanks */
622        SecWriteMultiChar(stream, SECUREC_CHAR(' '), attr->padding, charsOut);
623    }
624}
625
626/* Write prefix */
627SECUREC_INLINE void SecWritePrefix(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
628{
629    if (attr->prefixLen > 0) {
630        SecWriteString(stream, attr->prefix, attr->prefixLen, charsOut);
631    }
632}
633
634/* Write leading zeros */
635SECUREC_INLINE void SecWriteLeadingZero(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
636{
637    if ((attr->flags & SECUREC_FLAG_LEADZERO) != 0 && (attr->flags & SECUREC_FLAG_LEFT) == 0 &&
638        attr->padding > 0) {
639        SecWriteMultiChar(stream, SECUREC_CHAR('0'), attr->padding, charsOut);
640    }
641}
642
643/* Write right padding */
644SECUREC_INLINE void SecWriteRightPadding(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
645{
646    if (*charsOut >= 0 && (attr->flags & SECUREC_FLAG_LEFT) != 0 && attr->padding > 0) {
647        /* Pad on right with blanks */
648        SecWriteMultiChar(stream, SECUREC_CHAR(' '), attr->padding, charsOut);
649    }
650}
651
652#ifdef SECUREC_FOR_WCHAR
653#define SECUREC_TEXT_CHAR_PTR(text)  ((text).wStr)
654#define SECUREC_NEED_CONVERT_TEXT(attr) ((attr)->textIsWide == 0)
655#if SECUREC_HAVE_MBTOWC
656#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) SecWriteTextAfterMbtowc((stream), (attr), (charsOut))
657#else
658#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) (*(charsOut) = -1)
659#endif
660#else
661#define SECUREC_TEXT_CHAR_PTR(text)  ((text).str)
662#define SECUREC_NEED_CONVERT_TEXT(attr) ((attr)->textIsWide != 0)
663#if SECUREC_HAVE_WCTOMB
664#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) SecWriteTextAfterWctomb((stream), (attr), (charsOut))
665#else
666#define SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut) (*(charsOut) = -1)
667#endif
668#endif
669
670#ifdef SECUREC_FOR_WCHAR
671#if SECUREC_HAVE_MBTOWC
672SECUREC_INLINE void SecWriteTextAfterMbtowc(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
673{
674    const char *p = attr->text.str;
675    int count = attr->textLen;
676    while (count > 0) {
677        wchar_t wChar = L'\0';
678        int retVal = mbtowc(&wChar, p, (size_t)MB_CUR_MAX);
679        if (retVal <= 0) {
680            *charsOut = -1;
681            break;
682        }
683        SecWriteChar(stream, wChar, charsOut);
684        if (*charsOut == -1) {
685            break;
686        }
687        p += retVal;
688        count -= retVal;
689    }
690}
691#endif
692#else  /* Not SECUREC_FOR_WCHAR */
693#if SECUREC_HAVE_WCTOMB
694SECUREC_INLINE void SecWriteTextAfterWctomb(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
695{
696    const wchar_t *p = attr->text.wStr;
697    int count = attr->textLen;
698    while (count > 0) {
699        char tmpBuf[SECUREC_MB_LEN + 1];
700        SECUREC_MASK_MSVC_CRT_WARNING
701        int retVal = wctomb(tmpBuf, *p);
702        SECUREC_END_MASK_MSVC_CRT_WARNING
703        if (retVal <= 0) {
704            *charsOut = -1;
705            break;
706        }
707        SecWriteString(stream, tmpBuf, retVal, charsOut);
708        if (*charsOut == -1) {
709            break;
710        }
711        --count;
712        ++p;
713    }
714}
715#endif
716#endif
717
718#if SECUREC_ENABLE_SPRINTF_FLOAT
719/*
720 * Write text of float
721 * Using independent functions to optimize the expansion of inline functions by the compiler
722 */
723SECUREC_INLINE void SecWriteFloatText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
724{
725#ifdef SECUREC_FOR_WCHAR
726#if SECUREC_HAVE_MBTOWC
727    SecWriteTextAfterMbtowc(stream, attr, charsOut);
728#else
729    *charsOut = -1;
730    (void)stream; /* To clear e438 last value assigned not used , the compiler will optimize this code */
731    (void)attr;   /* To clear e438 last value assigned not used , the compiler will optimize this code */
732#endif
733#else /* Not SECUREC_FOR_WCHAR */
734    SecWriteString(stream, attr->text.str, attr->textLen, charsOut);
735#endif
736}
737#endif
738
739/* Write text of integer or string ... */
740SECUREC_INLINE void SecWriteText(SecPrintfStream *stream, const SecFormatAttr *attr, int *charsOut)
741{
742    if (SECUREC_NEED_CONVERT_TEXT(attr)) {
743        SECUREC_WRITE_TEXT_AFTER_CONVERT(stream, attr, charsOut);
744    } else {
745        SecWriteTextOpt(stream, SECUREC_TEXT_CHAR_PTR(attr->text), attr->textLen, charsOut);
746    }
747}
748
749#define SECUREC_FMT_STATE_OFFSET  256
750
751SECUREC_INLINE SecFmtState SecDecodeState(SecChar ch, SecFmtState lastState)
752{
753    static const unsigned char stateTable[SECUREC_STATE_TABLE_SIZE] = {
754        /*
755         * Type
756         * 0:    nospecial meaning;
757         * 1:    '%'
758         * 2:    '.'
759         * 3:    '*'
760         * 4:    '0'
761         * 5:    '1' ... '9'
762         * 6:    ' ', '+', '-', '#'
763         * 7:    'h', 'l', 'L', 'w' , 'N', 'z', 'q', 't', 'j'
764         * 8:    'd', 'o', 'u', 'i', 'x', 'X', 'e', 'f', 'g', 'E', 'F', 'G', 's', 'c', '[', 'p'
765         */
766        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768        0x06, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x06, 0x02, 0x00,
769        0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
770        0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x08, 0x08, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00,
771        0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
772        0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x08, 0x07, 0x00, 0x07, 0x00, 0x00, 0x08,
773        0x08, 0x07, 0x00, 0x08, 0x07, 0x08, 0x00, 0x07, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
774        /* Fill zero  for normal char 128 byte for 0x80 - 0xff */
775        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783        /*
784         * State
785         * 0: normal
786         * 1: percent
787         * 2: flag
788         * 3: width
789         * 4: dot
790         * 5: precis
791         * 6: size
792         * 7: type
793         * 8: invalid
794         */
795        0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x01, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
796        0x01, 0x00, 0x00, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03, 0x08, 0x05,
797        0x08, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x03, 0x03,
798        0x03, 0x05, 0x05, 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
799        0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00,
800        0x00
801    };
802
803#ifdef SECUREC_FOR_WCHAR
804    /* Convert to unsigned char to clear gcc 4.3.4 warning */
805    unsigned char fmtType = (unsigned char)((((unsigned int)(int)(ch)) <= (unsigned int)(int)(L'~')) ? \
806        (stateTable[(unsigned char)(ch)]) : 0);
807    return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) +
808        (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]);
809#else
810    unsigned char fmtType = stateTable[(unsigned char)(ch)];
811    return (SecFmtState)(stateTable[fmtType * ((unsigned char)STAT_INVALID + 1) +
812        (unsigned char)(lastState) + SECUREC_FMT_STATE_OFFSET]);
813#endif
814}
815
816SECUREC_INLINE void SecDecodeFlags(SecChar ch, SecFormatAttr *attr)
817{
818    switch (ch) {
819        case SECUREC_CHAR(' '):
820            attr->flags |= SECUREC_FLAG_SIGN_SPACE;
821            break;
822        case SECUREC_CHAR('+'):
823            attr->flags |= SECUREC_FLAG_SIGN;
824            break;
825        case SECUREC_CHAR('-'):
826            attr->flags |= SECUREC_FLAG_LEFT;
827            break;
828        case SECUREC_CHAR('0'):
829            attr->flags |= SECUREC_FLAG_LEADZERO;   /* Add zero th the front */
830            break;
831        case SECUREC_CHAR('#'):
832            attr->flags |= SECUREC_FLAG_ALTERNATE;  /* Output %x with 0x */
833            break;
834        default:
835            /* Do nothing */
836            break;
837    }
838    return;
839}
840
841/*
842 * Decoded size identifier in format string to Reduce the number of lines of function code
843 */
844SECUREC_INLINE int SecDecodeSizeI(SecFormatAttr *attr, const SecChar **format)
845{
846#ifdef SECUREC_ON_64BITS
847    attr->flags |= SECUREC_FLAG_I64;    /* %I  to  INT64 */
848#endif
849    if ((**format == SECUREC_CHAR('6')) && (*((*format) + 1) == SECUREC_CHAR('4'))) {
850        (*format) += 2; /* Add 2 to skip I64 */
851        attr->flags |= SECUREC_FLAG_I64;    /* %I64  to  INT64 */
852    } else if ((**format == SECUREC_CHAR('3')) && (*((*format) + 1) == SECUREC_CHAR('2'))) {
853        (*format) += 2; /* Add 2 to skip I32 */
854        attr->flags &= ~SECUREC_FLAG_I64;   /* %I64  to  INT32 */
855    } else if ((**format == SECUREC_CHAR('d')) || (**format == SECUREC_CHAR('i')) ||
856        (**format == SECUREC_CHAR('o')) || (**format == SECUREC_CHAR('u')) ||
857        (**format == SECUREC_CHAR('x')) || (**format == SECUREC_CHAR('X'))) {
858        /* Do nothing */
859    } else {
860        /* Compatibility  code for "%I" just print I */
861        return -1;
862    }
863    return 0;
864}
865
866/*
867 * Decoded size identifier in format string, and skip format to next charater
868 */
869SECUREC_INLINE int SecDecodeSize(SecChar ch, SecFormatAttr *attr, const SecChar **format)
870{
871    switch (ch) {
872        case SECUREC_CHAR('l'):
873            if (**format == SECUREC_CHAR('l')) {
874                *format = *format + 1;
875                attr->flags |= SECUREC_FLAG_LONGLONG; /* For long long */
876            } else {
877                attr->flags |= SECUREC_FLAG_LONG;     /* For long int or wchar_t */
878            }
879            break;
880#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
881        case SECUREC_CHAR('z'): /* fall-through */ /* FALLTHRU */
882        case SECUREC_CHAR('Z'):
883            attr->flags |= SECUREC_FLAG_SIZE;
884            break;
885        case SECUREC_CHAR('j'):
886            attr->flags |= SECUREC_FLAG_INTMAX;
887            break;
888#endif
889        case SECUREC_CHAR('t'):
890            attr->flags |= SECUREC_FLAG_PTRDIFF;
891            break;
892        case SECUREC_CHAR('q'): /* fall-through */ /* FALLTHRU */
893        case SECUREC_CHAR('L'):
894            attr->flags |= (SECUREC_FLAG_LONGLONG | SECUREC_FLAG_LONG_DOUBLE);
895            break;
896        case SECUREC_CHAR('I'):
897            if (SecDecodeSizeI(attr, format) != 0) {
898                /* Compatibility  code for "%I" just print I */
899                return -1;
900            }
901            break;
902        case SECUREC_CHAR('h'):
903            if (**format == SECUREC_CHAR('h')) {
904                *format = *format + 1;
905                attr->flags |= SECUREC_FLAG_CHAR;   /* For char */
906            } else {
907                attr->flags |= SECUREC_FLAG_SHORT;  /* For short int */
908            }
909            break;
910        case SECUREC_CHAR('w'):
911            attr->flags |= SECUREC_FLAG_WIDECHAR;   /* For wide char */
912            break;
913        default:
914            /* Do nothing */
915            break;
916    }
917    return 0;
918}
919
920/*
921 * Decoded char type identifier
922 */
923SECUREC_INLINE void SecDecodeTypeC(SecFormatAttr *attr, unsigned int c)
924{
925    attr->textLen = 1; /* Only 1 wide character */
926
927#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) && !(defined(__hpux)) && !(defined(SECUREC_ON_SOLARIS))
928    attr->flags &= ~SECUREC_FLAG_LEADZERO;
929#endif
930
931#ifdef SECUREC_FOR_WCHAR
932    if ((attr->flags & SECUREC_FLAG_SHORT) != 0) {
933        /* Get  multibyte character from argument */
934        attr->buffer.str[0] = (char)c;
935        attr->text.str = attr->buffer.str;
936        attr->textIsWide = 0;
937    } else {
938        attr->buffer.wStr[0] = (wchar_t)c;
939        attr->text.wStr = attr->buffer.wStr;
940        attr->textIsWide = 1;
941    }
942#else /* Not SECUREC_FOR_WCHAR */
943    if ((attr->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) != 0) {
944#if SECUREC_HAVE_WCHART
945        attr->buffer.wStr[0] = (wchar_t)c;
946        attr->text.wStr = attr->buffer.wStr;
947        attr->textIsWide = 1;
948#else
949        attr->textLen = 0; /* Ignore unsupported characters */
950        attr->fldWidth = 0; /* No paddings  */
951#endif
952    } else {
953        /* Get  multibyte character from argument */
954        attr->buffer.str[0] = (char)c;
955        attr->text.str = attr->buffer.str;
956        attr->textIsWide = 0;
957    }
958#endif
959}
960
961#ifdef SECUREC_FOR_WCHAR
962#define SECUREC_IS_NARROW_STRING(attr) (((attr)->flags & SECUREC_FLAG_SHORT) != 0)
963#else
964#define SECUREC_IS_NARROW_STRING(attr) (((attr)->flags & (SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) == 0)
965#endif
966
967SECUREC_INLINE void SecDecodeTypeSchar(SecFormatAttr *attr)
968{
969    size_t textLen;
970    if (attr->text.str == NULL) {
971        /*
972         * Literal string to print null ptr, define it as array rather than const text area
973         * To avoid gcc warning with pointing const text with variable
974         */
975        static char strNullString[SECUREC_NULL_STRING_SIZE] = "(null)";
976        attr->text.str = strNullString;
977    }
978    if (attr->precision == -1) {
979        /* Precision NOT assigned */
980        /* The strlen performance is high when the string length is greater than 32 */
981        textLen = strlen(attr->text.str);
982        if (textLen > SECUREC_STRING_MAX_LEN) {
983            textLen = 0;
984        }
985    } else {
986        /* Precision assigned */
987        SECUREC_CALC_STR_LEN(attr->text.str, (size_t)(unsigned int)attr->precision, &textLen);
988    }
989    attr->textLen = (int)textLen;
990}
991
992SECUREC_INLINE void SecDecodeTypeSwchar(SecFormatAttr *attr)
993{
994#if SECUREC_HAVE_WCHART
995    size_t textLen;
996    attr->textIsWide = 1;
997    if (attr->text.wStr == NULL) {
998        /*
999         * Literal string to print null ptr, define it as array rather than const text area
1000         * To avoid gcc warning with pointing const text with variable
1001         */
1002        static wchar_t wStrNullString[SECUREC_NULL_STRING_SIZE] = { L'(', L'n', L'u', L'l', L'l', L')', L'\0', L'\0' };
1003        attr->text.wStr = wStrNullString;
1004    }
1005    /* The textLen in wchar_t,when precision is -1, it is unlimited  */
1006    SECUREC_CALC_WSTR_LEN(attr->text.wStr, (size_t)(unsigned int)attr->precision, &textLen);
1007    if (textLen > SECUREC_WCHAR_STRING_MAX_LEN) {
1008        textLen = 0;
1009    }
1010    attr->textLen = (int)textLen;
1011#else
1012    attr->textLen = 0;
1013#endif
1014}
1015
1016/*
1017 * Decoded string identifier
1018 */
1019SECUREC_INLINE void SecDecodeTypeS(SecFormatAttr *attr, char *argPtr)
1020{
1021#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT))
1022#if (!defined(SECUREC_ON_UNIX))
1023    attr->flags &= ~SECUREC_FLAG_LEADZERO;
1024#endif
1025#if (defined(SECUREC_FOR_WCHAR))
1026    if ((attr->flags & SECUREC_FLAG_LONG) == 0) {
1027        attr->flags |= SECUREC_FLAG_SHORT;
1028    }
1029#endif
1030#endif
1031    attr->text.str = argPtr;
1032    if (SECUREC_IS_NARROW_STRING(attr)) {
1033        /* The textLen now contains length in multibyte chars */
1034        SecDecodeTypeSchar(attr);
1035    } else {
1036        /* The textLen now contains length in wide chars */
1037        SecDecodeTypeSwchar(attr);
1038    }
1039}
1040
1041/*
1042 * Check precision in format
1043 */
1044SECUREC_INLINE int SecDecodePrecision(SecChar ch, SecFormatAttr *attr)
1045{
1046    if (attr->dynPrecision == 0) {
1047        /* Add digit to current precision */
1048        if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->precision)) {
1049            return -1;
1050        }
1051        attr->precision = (int)SECUREC_MUL_TEN((unsigned int)attr->precision) +
1052            (unsigned char)(ch - SECUREC_CHAR('0'));
1053    } else {
1054        if (attr->precision < 0) {
1055            attr->precision = -1;
1056        }
1057        if (attr->precision > SECUREC_MAX_WIDTH_LEN) {
1058            return -1;
1059        }
1060    }
1061    return 0;
1062}
1063
1064/*
1065 * Check width in format
1066 */
1067SECUREC_INLINE int SecDecodeWidth(SecChar ch, SecFormatAttr *attr, SecFmtState lastState)
1068{
1069    if (attr->dynWidth == 0) {
1070        if (lastState != STAT_WIDTH) {
1071            attr->fldWidth = 0;
1072        }
1073        if (SECUREC_MUL_TEN_ADD_BEYOND_MAX(attr->fldWidth)) {
1074            return -1;
1075        }
1076        attr->fldWidth = (int)SECUREC_MUL_TEN((unsigned int)attr->fldWidth) +
1077            (unsigned char)(ch - SECUREC_CHAR('0'));
1078    } else {
1079        if (attr->fldWidth < 0) {
1080            attr->flags |= SECUREC_FLAG_LEFT;
1081            attr->fldWidth = (-attr->fldWidth);
1082        }
1083        if (attr->fldWidth > SECUREC_MAX_WIDTH_LEN) {
1084            return -1;
1085        }
1086    }
1087    return 0;
1088}
1089
1090/*
1091 * The sprintf_s function processes the wide character as a parameter for %C
1092 * The swprintf_s function processes the multiple character as a parameter for %C
1093 */
1094SECUREC_INLINE void SecUpdateWcharFlags(SecFormatAttr *attr)
1095{
1096    if ((attr->flags & (SECUREC_FLAG_SHORT | SECUREC_FLAG_LONG | SECUREC_FLAG_WIDECHAR)) == 0) {
1097#ifdef SECUREC_FOR_WCHAR
1098        attr->flags |= SECUREC_FLAG_SHORT;
1099#else
1100        attr->flags |= SECUREC_FLAG_WIDECHAR;
1101#endif
1102    }
1103}
1104/*
1105 * When encountering %S, current just same as %C
1106 */
1107SECUREC_INLINE void SecUpdateWstringFlags(SecFormatAttr *attr)
1108{
1109    SecUpdateWcharFlags(attr);
1110}
1111
1112#if SECUREC_IN_KERNEL
1113SECUREC_INLINE void SecUpdatePointFlagsForKernel(SecFormatAttr *attr)
1114{
1115    /* Width is not set */
1116    if (attr->fldWidth <= 0) {
1117        attr->flags |= SECUREC_FLAG_LEADZERO;
1118        attr->fldWidth = 2 * sizeof(void *);  /* 2 x byte number is the length of hex */
1119    }
1120    if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
1121        /* Alternate form means '0x' prefix */
1122        attr->prefix[0] = SECUREC_CHAR('0');
1123        attr->prefix[1] = SECUREC_CHAR('x');
1124        attr->prefixLen = SECUREC_PREFIX_LEN;
1125    }
1126    attr->flags |= SECUREC_FLAG_LONG;  /* Converting a long */
1127}
1128#endif
1129
1130SECUREC_INLINE void SecUpdatePointFlags(SecFormatAttr *attr)
1131{
1132    attr->flags |= SECUREC_FLAG_POINTER;
1133#if SECUREC_IN_KERNEL
1134    SecUpdatePointFlagsForKernel(attr);
1135#else
1136#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) && (!defined(SECUREC_ON_UNIX))
1137#if defined(SECUREC_VXWORKS_PLATFORM)
1138    attr->precision = 1;
1139#else
1140    attr->precision = 0;
1141#endif
1142    attr->flags |= SECUREC_FLAG_ALTERNATE; /* "0x" is not default prefix in UNIX */
1143    attr->digits = g_itoaLowerDigits;
1144#else /* On unix or win */
1145#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
1146    attr->precision = 1;
1147#else
1148    attr->precision = 2 * sizeof(void *);  /* 2 x byte number is the length of hex */
1149#endif
1150#if defined(SECUREC_ON_UNIX)
1151    attr->digits = g_itoaLowerDigits;
1152#else
1153    attr->digits = g_itoaUpperDigits;
1154#endif
1155#endif
1156
1157#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
1158    attr->flags &= ~SECUREC_FLAG_LEADZERO;
1159#endif
1160
1161#ifdef SECUREC_ON_64BITS
1162    attr->flags |= SECUREC_FLAG_I64;   /* Converting an int64 */
1163#else
1164    attr->flags |= SECUREC_FLAG_LONG;  /* Converting a long */
1165#endif
1166    /* Set up for %#p on different system */
1167    if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
1168        /* Alternate form means '0x' prefix */
1169        attr->prefix[0] = SECUREC_CHAR('0');
1170#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM))
1171        attr->prefix[1] = SECUREC_CHAR('x');
1172#else
1173        attr->prefix[1] = (SecChar)(attr->digits[SECUREC_NUMBER_OF_X]);
1174#endif
1175#if defined(_AIX) || defined(SECUREC_ON_SOLARIS)
1176        attr->prefixLen = 0;
1177#else
1178        attr->prefixLen = SECUREC_PREFIX_LEN;
1179#endif
1180    }
1181#endif
1182}
1183
1184SECUREC_INLINE void SecUpdateXpxFlags(SecFormatAttr *attr, SecChar ch)
1185{
1186    /* Use unsigned lower hex output for 'x' */
1187    attr->digits = g_itoaLowerDigits;
1188    attr->radix = SECUREC_RADIX_HEX;
1189    switch (ch) {
1190        case SECUREC_CHAR('p'):
1191            /* Print a pointer */
1192            SecUpdatePointFlags(attr);
1193            break;
1194        case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */
1195            /* Unsigned upper hex output */
1196            attr->digits = g_itoaUpperDigits;
1197            /* fall-through */ /* FALLTHRU */
1198        default:
1199            /* For %#x or %#X */
1200            if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
1201                /* Alternate form means '0x' prefix */
1202                attr->prefix[0] = SECUREC_CHAR('0');
1203                attr->prefix[1] = (SecChar)(attr->digits[SECUREC_NUMBER_OF_X]);
1204                attr->prefixLen = SECUREC_PREFIX_LEN;
1205            }
1206            break;
1207    }
1208}
1209
1210SECUREC_INLINE void SecUpdateOudiFlags(SecFormatAttr *attr, SecChar ch)
1211{
1212    /* Do not set digits here */
1213    switch (ch) {
1214        case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */
1215        case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */
1216            /* For signed decimal output */
1217            attr->flags |= SECUREC_FLAG_SIGNED;
1218            /* fall-through */ /* FALLTHRU */
1219        case SECUREC_CHAR('u'):
1220            attr->radix = SECUREC_RADIX_DECIMAL;
1221            attr->digits = g_itoaLowerDigits;
1222            break;
1223        case SECUREC_CHAR('o'):
1224            /* For unsigned octal output */
1225            attr->radix = SECUREC_RADIX_OCTAL;
1226            attr->digits = g_itoaLowerDigits;
1227            if ((attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
1228                /* Alternate form means force a leading 0 */
1229                attr->flags |= SECUREC_FLAG_FORCE_OCTAL;
1230            }
1231            break;
1232        default:
1233            /* Do nothing */
1234            break;
1235    }
1236}
1237
1238#if SECUREC_ENABLE_SPRINTF_FLOAT
1239SECUREC_INLINE void SecFreeFloatBuffer(SecFloatAdapt *floatAdapt)
1240{
1241    if (floatAdapt->floatBuffer != NULL) {
1242        SECUREC_FREE(floatAdapt->floatBuffer);
1243    }
1244    if (floatAdapt->allocatedFmtStr != NULL) {
1245        SECUREC_FREE(floatAdapt->allocatedFmtStr);
1246    }
1247    floatAdapt->floatBuffer = NULL;
1248    floatAdapt->allocatedFmtStr = NULL;
1249    floatAdapt->fmtStr = NULL;
1250    floatAdapt->bufferSize = 0;
1251}
1252
1253SECUREC_INLINE void SecSeekToFrontPercent(const SecChar **format)
1254{
1255    const SecChar *fmt = *format;
1256    while (*fmt != SECUREC_CHAR('%')) { /* Must meet '%' */
1257        --fmt;
1258    }
1259    *format = fmt;
1260}
1261
1262/* Init float format, return 0 is OK */
1263SECUREC_INLINE int SecInitFloatFmt(SecFloatAdapt *floatFmt, const SecChar *format)
1264{
1265    const SecChar *fmt = format - 2;  /* Sub 2 to the position before 'f' or 'g' */
1266    int fmtStrLen;
1267    int i;
1268
1269    SecSeekToFrontPercent(&fmt);
1270    /* Now fmt point to '%' */
1271    fmtStrLen = (int)(size_t)(format - fmt) + 1;   /* With ending terminator */
1272    if (fmtStrLen > (int)sizeof(floatFmt->buffer)) {
1273        /* When buffer is NOT enough, alloc a new buffer */
1274        floatFmt->allocatedFmtStr = (char *)SECUREC_MALLOC((size_t)((unsigned int)fmtStrLen));
1275        if (floatFmt->allocatedFmtStr == NULL) {
1276            return -1;
1277        }
1278        floatFmt->fmtStr = floatFmt->allocatedFmtStr;
1279    } else {
1280        floatFmt->fmtStr = floatFmt->buffer;
1281        floatFmt->allocatedFmtStr = NULL; /* Must set to NULL, later code free memory based on this identity */
1282    }
1283
1284    for (i = 0; i < fmtStrLen - 1; ++i) {
1285        /* Convert wchar to char */
1286        floatFmt->fmtStr[i] = (char)(fmt[i]);  /* Copy the format string */
1287    }
1288    floatFmt->fmtStr[fmtStrLen - 1] = '\0';
1289
1290    return 0;
1291}
1292
1293/* Init float buffer and format, return 0 is OK */
1294SECUREC_INLINE int SecInitFloatBuffer(SecFloatAdapt *floatAdapt, const SecChar *format, SecFormatAttr *attr)
1295{
1296    floatAdapt->allocatedFmtStr = NULL;
1297    floatAdapt->fmtStr = NULL;
1298    floatAdapt->floatBuffer = NULL;
1299    /* Compute the precision value */
1300    if (attr->precision < 0) {
1301        attr->precision = SECUREC_FLOAT_DEFAULT_PRECISION;
1302    }
1303    /*
1304     * Calc buffer size to store double value
1305     * The maximum length of SECUREC_MAX_WIDTH_LEN is enough
1306     */
1307    if ((attr->flags & SECUREC_FLAG_LONG_DOUBLE) != 0) {
1308        if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE_LB)) {
1309            return -1;
1310        }
1311        /* Long double needs to meet the basic print length */
1312        floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE_LB + attr->precision + SECUREC_FLOAT_BUF_EXT;
1313    } else {
1314        if (attr->precision > (SECUREC_MAX_WIDTH_LEN - SECUREC_FLOAT_BUFSIZE)) {
1315            return -1;
1316        }
1317        /* Double needs to meet the basic print length */
1318        floatAdapt->bufferSize = SECUREC_FLOAT_BUFSIZE + attr->precision + SECUREC_FLOAT_BUF_EXT;
1319    }
1320    if (attr->fldWidth > floatAdapt->bufferSize) {
1321        floatAdapt->bufferSize = attr->fldWidth + SECUREC_FLOAT_BUF_EXT;
1322    }
1323
1324    if (floatAdapt->bufferSize > SECUREC_BUFFER_SIZE) {
1325        /* The current value of SECUREC_BUFFER_SIZE could not store the formatted float string */
1326        floatAdapt->floatBuffer = (char *)SECUREC_MALLOC(((size_t)(unsigned int)floatAdapt->bufferSize));
1327        if (floatAdapt->floatBuffer == NULL) {
1328            return -1;
1329        }
1330        attr->text.str = floatAdapt->floatBuffer;
1331    } else {
1332        attr->text.str = attr->buffer.str; /* Output buffer for float string with default size */
1333    }
1334
1335    if (SecInitFloatFmt(floatAdapt, format) != 0) {
1336        if (floatAdapt->floatBuffer != NULL) {
1337            SECUREC_FREE(floatAdapt->floatBuffer);
1338            floatAdapt->floatBuffer = NULL;
1339        }
1340        return -1;
1341    }
1342    return 0;
1343}
1344#endif
1345
1346SECUREC_INLINE SecInt64 SecUpdateNegativeChar(SecFormatAttr *attr, char ch)
1347{
1348    SecInt64 num64 = ch; /* Sign extend */
1349    if (num64 >= 128) { /* 128 on some platform, char is always unsigned */
1350        unsigned char tmp = (unsigned char)(~((unsigned char)ch));
1351        num64 = tmp + 1;
1352        attr->flags |= SECUREC_FLAG_NEGATIVE;
1353    }
1354    return num64;
1355}
1356
1357/*
1358 * If the precision is not satisfied, zero is added before the string
1359 */
1360SECUREC_INLINE void SecNumberSatisfyPrecision(SecFormatAttr *attr)
1361{
1362    int precision;
1363    if (attr->precision < 0) {
1364        precision = 1; /* Default precision 1 */
1365    } else {
1366#if defined(SECUREC_COMPATIBLE_WIN_FORMAT)
1367        attr->flags &= ~SECUREC_FLAG_LEADZERO;
1368#else
1369        if ((attr->flags & SECUREC_FLAG_POINTER) == 0) {
1370            attr->flags &= ~SECUREC_FLAG_LEADZERO;
1371        }
1372#endif
1373        if (attr->precision > SECUREC_MAX_PRECISION) {
1374            attr->precision = SECUREC_MAX_PRECISION;
1375        }
1376        precision = attr->precision;
1377    }
1378    while (attr->textLen < precision) {
1379        --attr->text.str;
1380        *(attr->text.str) = '0';
1381        ++attr->textLen;
1382    }
1383}
1384
1385/*
1386 * Add leading zero for %#o
1387 */
1388SECUREC_INLINE void SecNumberForceOctal(SecFormatAttr *attr)
1389{
1390    /* Force a leading zero if FORCEOCTAL flag set */
1391    if ((attr->flags & SECUREC_FLAG_FORCE_OCTAL) != 0 &&
1392        (attr->textLen == 0 || attr->text.str[0] != '0')) {
1393        --attr->text.str;
1394        *(attr->text.str) = '0';
1395        ++attr->textLen;
1396    }
1397}
1398
1399SECUREC_INLINE void SecUpdateSignedNumberPrefix(SecFormatAttr *attr)
1400{
1401    if ((attr->flags & SECUREC_FLAG_SIGNED) == 0) {
1402        return;
1403    }
1404    if ((attr->flags & SECUREC_FLAG_NEGATIVE) != 0) {
1405        /* Prefix is '-' */
1406        attr->prefix[0] = SECUREC_CHAR('-');
1407        attr->prefixLen = 1;
1408        return;
1409    }
1410    if ((attr->flags & SECUREC_FLAG_SIGN) != 0) {
1411        /* Prefix is '+' */
1412        attr->prefix[0] = SECUREC_CHAR('+');
1413        attr->prefixLen = 1;
1414        return;
1415    }
1416    if ((attr->flags & SECUREC_FLAG_SIGN_SPACE) != 0) {
1417        /* Prefix is ' ' */
1418        attr->prefix[0] = SECUREC_CHAR(' ');
1419        attr->prefixLen = 1;
1420        return;
1421    }
1422    return;
1423}
1424
1425SECUREC_INLINE void SecNumberCompatZero(SecFormatAttr *attr)
1426{
1427#if SECUREC_IN_KERNEL
1428    if ((attr->flags & SECUREC_FLAG_POINTER) != 0) {
1429        static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(null)";
1430        attr->text.str = strNullPointer;
1431        attr->textLen = 6; /* Length of (null) is 6 */
1432        attr->flags &= ~SECUREC_FLAG_LEADZERO;
1433        attr->prefixLen = 0;
1434        if (attr->precision >= 0 && attr->precision < attr->textLen) {
1435            attr->textLen = attr->precision;
1436        }
1437    }
1438    if ((attr->flags & SECUREC_FLAG_POINTER) == 0 && attr->radix == SECUREC_RADIX_HEX &&
1439        (attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
1440        /* Add 0x prefix for %x or %X, the prefix string has been set before */
1441        attr->prefixLen = SECUREC_PREFIX_LEN;
1442    }
1443#elif defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && (!defined(SECUREC_ON_UNIX))
1444    if ((attr->flags & SECUREC_FLAG_POINTER) != 0) {
1445        static char strNullPointer[SECUREC_NULL_STRING_SIZE] = "(nil)";
1446        attr->text.str = strNullPointer;
1447        attr->textLen = 5; /* Length of (nil) is 5 */
1448        attr->flags &= ~SECUREC_FLAG_LEADZERO;
1449    }
1450#elif defined(SECUREC_VXWORKS_PLATFORM) || defined(__hpux)
1451    if ((attr->flags & SECUREC_FLAG_POINTER) != 0 && (attr->flags & SECUREC_FLAG_ALTERNATE) != 0) {
1452        /* Add 0x prefix for %p, the prefix string has been set before */
1453        attr->prefixLen = SECUREC_PREFIX_LEN;
1454    }
1455#endif
1456    (void)attr; /* To clear e438 last value assigned not used , the compiler will optimize this code */
1457}
1458
1459/*
1460 * Formatting output core function
1461 */
1462SECUREC_INLINE int SecOutput(SecPrintfStream *stream, const SecChar *cFormat, va_list argList)
1463{
1464    const SecChar *format = cFormat;
1465    int charsOut;               /* Characters written */
1466    int noOutput = 0; /* Must be initialized or compiler alerts */
1467    SecFmtState state;
1468    SecFormatAttr formatAttr;
1469
1470    formatAttr.flags = 0;
1471    formatAttr.textIsWide = 0;    /* Flag for buffer contains wide chars */
1472    formatAttr.fldWidth = 0;
1473    formatAttr.precision = 0;
1474    formatAttr.dynWidth = 0;
1475    formatAttr.dynPrecision = 0;
1476    formatAttr.digits = g_itoaUpperDigits;
1477    formatAttr.radix = SECUREC_RADIX_DECIMAL;
1478    formatAttr.padding = 0;
1479    formatAttr.textLen = 0;
1480    formatAttr.text.str = NULL;
1481    formatAttr.prefixLen = 0;
1482    formatAttr.prefix[0] = SECUREC_CHAR('\0');
1483    formatAttr.prefix[1] = SECUREC_CHAR('\0');
1484    charsOut = 0;
1485    state = STAT_NORMAL;        /* Starting state */
1486
1487    /* Loop each format character */
1488    while (*format != SECUREC_CHAR('\0') && charsOut >= 0) {
1489        SecFmtState lastState = state;
1490        SecChar ch = *format; /* Currently read character */
1491        ++format;
1492        state = SecDecodeState(ch, lastState);
1493        switch (state) {
1494            case STAT_NORMAL:
1495                SecWriteChar(stream, ch, &charsOut);
1496                continue;
1497            case STAT_PERCENT:
1498                /* Set default values */
1499                noOutput = 0;
1500                formatAttr.prefixLen = 0;
1501                formatAttr.textLen = 0;
1502                formatAttr.flags = 0;
1503                formatAttr.fldWidth = 0;
1504                formatAttr.precision = -1;
1505                formatAttr.textIsWide = 0;
1506                formatAttr.dynWidth = 0;
1507                formatAttr.dynPrecision = 0;
1508                break;
1509            case STAT_FLAG:
1510                /* Set flag based on which flag character */
1511                SecDecodeFlags(ch, &formatAttr);
1512                break;
1513            case STAT_WIDTH:
1514                /* Update width value */
1515                if (ch == SECUREC_CHAR('*')) {
1516                    /* get width from arg list */
1517                    formatAttr.fldWidth = (int)va_arg(argList, int);
1518                    formatAttr.dynWidth = 1;
1519                }
1520                if (SecDecodeWidth(ch, &formatAttr, lastState) != 0) {
1521                    return -1;
1522                }
1523                break;
1524            case STAT_DOT:
1525                formatAttr.precision = 0;
1526                break;
1527            case STAT_PRECIS:
1528                /* Update precision value */
1529                if (ch == SECUREC_CHAR('*')) {
1530                    /* Get precision from arg list */
1531                    formatAttr.precision = (int)va_arg(argList, int);
1532                    formatAttr.dynPrecision = 1;
1533                }
1534                if (SecDecodePrecision(ch, &formatAttr) != 0) {
1535                    return -1;
1536                }
1537                break;
1538            case STAT_SIZE:
1539                /* Read a size specifier, set the formatAttr.flags based on it, and skip format to next character */
1540                if (SecDecodeSize(ch, &formatAttr, &format) != 0) {
1541                    /* Compatibility  code for "%I" just print I */
1542                    SecWriteChar(stream, ch, &charsOut);
1543                    state = STAT_NORMAL;
1544                    continue;
1545                }
1546                break;
1547            case STAT_TYPE:
1548                switch (ch) {
1549                    case SECUREC_CHAR('C'): /* Wide char */
1550                        SecUpdateWcharFlags(&formatAttr);
1551                        /* fall-through */ /* FALLTHRU */
1552                    case SECUREC_CHAR('c'): {
1553                        unsigned int cValue = (unsigned int)va_arg(argList, int);
1554                        SecDecodeTypeC(&formatAttr, cValue);
1555                        break;
1556                    }
1557                    case SECUREC_CHAR('S'):    /* Wide char string */
1558                        SecUpdateWstringFlags(&formatAttr);
1559                        /* fall-through */ /* FALLTHRU */
1560                    case SECUREC_CHAR('s'): {
1561                        char *argPtr = (char *)va_arg(argList, char *);
1562                        SecDecodeTypeS(&formatAttr, argPtr);
1563                        break;
1564                    }
1565                    case SECUREC_CHAR('G'): /* fall-through */ /* FALLTHRU */
1566                    case SECUREC_CHAR('g'): /* fall-through */ /* FALLTHRU */
1567                    case SECUREC_CHAR('E'): /* fall-through */ /* FALLTHRU */
1568                    case SECUREC_CHAR('F'): /* fall-through */ /* FALLTHRU */
1569                    case SECUREC_CHAR('e'): /* fall-through */ /* FALLTHRU */
1570                    case SECUREC_CHAR('f'): {
1571#if SECUREC_ENABLE_SPRINTF_FLOAT
1572                        /* Add following code to call system sprintf API for float number */
1573                        SecFloatAdapt floatAdapt;
1574                        noOutput = 1; /* It's no more data needs to be written */
1575
1576                        /* Now format is pointer to the next character of 'f' */
1577                        if (SecInitFloatBuffer(&floatAdapt, format, &formatAttr) != 0) {
1578                            break;
1579                        }
1580
1581                        if ((formatAttr.flags & SECUREC_FLAG_LONG_DOUBLE) != 0) {
1582#if defined(SECUREC_COMPATIBLE_LINUX_FORMAT) && SECUREC_ENABLE_SPRINTF_LONG_DOUBLE
1583                            long double tmp = (long double)va_arg(argList, long double);
1584                            SecFormatLongDouble(&formatAttr, &floatAdapt, tmp);
1585#else
1586                            double tmp = (double)va_arg(argList, double);
1587                            SecFormatDouble(&formatAttr, &floatAdapt, tmp);
1588#endif
1589                        } else {
1590                            double tmp = (double)va_arg(argList, double);
1591                            SecFormatDouble(&formatAttr, &floatAdapt, tmp);
1592                        }
1593
1594                        /* Only need write formatted float string */
1595                        SecWriteFloatText(stream, &formatAttr, &charsOut);
1596                        SecFreeFloatBuffer(&floatAdapt);
1597                        break;
1598#else
1599                        return -1;
1600#endif
1601                    }
1602                    case SECUREC_CHAR('X'): /* fall-through */ /* FALLTHRU */
1603                    case SECUREC_CHAR('p'): /* fall-through */ /* FALLTHRU */
1604                    case SECUREC_CHAR('x'): /* fall-through */ /* FALLTHRU */
1605                        SecUpdateXpxFlags(&formatAttr, ch);
1606                        /* fall-through */ /* FALLTHRU */
1607                    case SECUREC_CHAR('i'): /* fall-through */ /* FALLTHRU */
1608                    case SECUREC_CHAR('d'): /* fall-through */ /* FALLTHRU */
1609                    case SECUREC_CHAR('u'): /* fall-through */ /* FALLTHRU */
1610                    case SECUREC_CHAR('o'): {
1611                        SecInt64 num64;
1612                        SecUpdateOudiFlags(&formatAttr, ch);
1613                        /* Read argument into variable num64. Be careful, depend on the order of judgment */
1614                        if ((formatAttr.flags & SECUREC_FLAG_I64) != 0 ||
1615                            (formatAttr.flags & SECUREC_FLAG_LONGLONG) != 0) {
1616                            num64 = (SecInt64)va_arg(argList, SecInt64); /* Maximum Bit Width sign bit unchanged */
1617                        } else if ((formatAttr.flags & SECUREC_FLAG_LONG) != 0) {
1618                            num64 = SECUREC_GET_LONG_FROM_ARG(formatAttr);
1619                        } else if ((formatAttr.flags & SECUREC_FLAG_CHAR) != 0) {
1620                            num64 = SECUREC_GET_CHAR_FROM_ARG(formatAttr);
1621                        } else if ((formatAttr.flags & SECUREC_FLAG_SHORT) != 0) {
1622                            num64 = SECUREC_GET_SHORT_FROM_ARG(formatAttr);
1623#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT
1624                        } else if ((formatAttr.flags & SECUREC_FLAG_PTRDIFF) != 0) {
1625                            num64 = (ptrdiff_t)va_arg(argList, ptrdiff_t);  /* Sign extend */
1626                        } else if ((formatAttr.flags & SECUREC_FLAG_SIZE) != 0) {
1627                            num64 = SECUREC_GET_SIZE_FROM_ARG(formatAttr);
1628                        } else if ((formatAttr.flags & SECUREC_FLAG_INTMAX) != 0) {
1629                            num64 = (SecInt64)va_arg(argList, SecInt64);
1630#endif
1631                        } else {
1632                            num64 = SECUREC_GET_INT_FROM_ARG(formatAttr);
1633                        }
1634
1635                        /* The order of the following calls must be correct */
1636                        SecNumberToBuffer(&formatAttr, num64);
1637                        SecNumberSatisfyPrecision(&formatAttr);
1638                        SecNumberForceOctal(&formatAttr);
1639                        SecUpdateSignedNumberPrefix(&formatAttr);
1640                        if (num64 == 0) {
1641                            SecNumberCompatZero(&formatAttr);
1642                        }
1643                        break;
1644                    }
1645                    default:
1646                        /* Do nothing */
1647                        break;
1648                }
1649
1650                if (noOutput == 0) {
1651                    /* Calculate amount of padding */
1652                    formatAttr.padding = (formatAttr.fldWidth - formatAttr.textLen) - formatAttr.prefixLen;
1653
1654                    /* Put out the padding, prefix, and text, in the correct order */
1655                    SecWriteLeftPadding(stream, &formatAttr, &charsOut);
1656                    SecWritePrefix(stream, &formatAttr, &charsOut);
1657                    SecWriteLeadingZero(stream, &formatAttr, &charsOut);
1658                    SecWriteText(stream, &formatAttr, &charsOut);
1659                    SecWriteRightPadding(stream, &formatAttr, &charsOut);
1660                }
1661                break;
1662            case STAT_INVALID: /* fall-through */ /* FALLTHRU */
1663            default:
1664                return -1;  /* Input format is wrong(STAT_INVALID), directly return */
1665        }
1666    }
1667
1668    if (state != STAT_NORMAL && state != STAT_TYPE) {
1669        return -1;
1670    }
1671
1672    return charsOut;            /* The number of characters written */
1673}
1674
1675/*
1676 * Output one zero character zero into the SecPrintfStream structure
1677 * If there is not enough space, make sure f->count is less than 0
1678 */
1679SECUREC_INLINE int SecPutZeroChar(SecPrintfStream *stream)
1680{
1681    --stream->count;
1682    if (stream->count >= 0) {
1683        *(stream->cur) = SECUREC_CHAR('\0');
1684        ++stream->cur;
1685        return 0;
1686    }
1687    return -1;
1688}
1689
1690/*
1691 * Multi character formatted output implementation
1692 */
1693#ifdef SECUREC_FOR_WCHAR
1694int SecVswprintfImpl(wchar_t *string, size_t count, const wchar_t *format, va_list argList)
1695#else
1696int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList)
1697#endif
1698{
1699    SecPrintfStream stream;
1700    int retVal;
1701
1702    stream.count = (int)count; /* The count include \0 character, must be greater than zero */
1703    stream.cur = string;
1704
1705    retVal = SecOutput(&stream, format, argList);
1706    if (retVal >= 0) {
1707        if (SecPutZeroChar(&stream) == 0) {
1708            return retVal;
1709        }
1710    }
1711    if (stream.count < 0) {
1712        /* The buffer was too small, then truncate */
1713        string[count - 1] = SECUREC_CHAR('\0');
1714        return SECUREC_PRINTF_TRUNCATE;
1715    }
1716    string[0] = SECUREC_CHAR('\0'); /* Empty the dest string */
1717    return -1;
1718}
1719#endif /* OUTPUT_INL_2B263E9C_43D8_44BB_B17A_6D2033DECEE5 */
1720
1721