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